Forked from JunTaoLuo/gist:6127169c8a643a36122981f232ad849d
Created
February 20, 2019 21:48
-
-
Save shirhatti/5774a0efce3ee6b113217666d4176b9f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Buffers.Binary; | |
using System.Collections.Generic; | |
using System.Net.Http; | |
using System.Reflection; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Text; | |
using Grpc.Core; | |
namespace Sample.Clients | |
{ | |
public class HttpClientCallInvoker : CallInvoker | |
{ | |
private string _requestUriRoot; | |
private HttpClient _client; | |
public HttpClientCallInvoker(string requestUriRoot, X509Certificate2 certificate) | |
{ | |
var handler = new HttpClientHandler(); | |
EnsureHttp2Feature(handler); | |
handler.ClientCertificates.Add(certificate); | |
handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true; | |
_client = new HttpClient(handler); | |
_requestUriRoot = requestUriRoot; | |
} | |
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options) | |
{ | |
throw new NotImplementedException(); | |
} | |
public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options) | |
{ | |
throw new NotImplementedException(); | |
} | |
public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request) | |
{ | |
throw new NotImplementedException(); | |
} | |
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request) | |
{ | |
var callUri = "https://" + _requestUriRoot + method.FullName; | |
var requestBytes = method.RequestMarshaller.Serializer(request); | |
var payload = new Memory<byte>(new byte[requestBytes.Length + 1 + 4]); | |
payload.Span[0] = 0; | |
BinaryPrimitives.WriteUInt32BigEndian(payload.Span.Slice(1), (uint)requestBytes.Length); | |
requestBytes.CopyTo(payload.Slice(1 + 4)); | |
var content = new ReadOnlyMemoryContent(payload); | |
var message = new HttpRequestMessage(HttpMethod.Post, callUri); | |
message.Content = content; | |
message.Version = new Version(2, 0); | |
var response = _client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult(); | |
var responseStream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult(); | |
int byteRead; | |
while ((byteRead = responseStream.ReadByte()) != -1) | |
{ | |
Console.WriteLine(byteRead); | |
} | |
return null; | |
} | |
public override TResponse BlockingUnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, string host, CallOptions options, TRequest request) | |
{ | |
return AsyncUnaryCall(method, host, options, request)?.GetAwaiter().GetResult(); | |
} | |
public static void EnsureHttp2Feature(HttpClientHandler handler) | |
{ | |
// All .NET Core implementations of HttpClientHandler have HTTP/2 enabled by default except when using | |
// SocketsHttpHandler. Right now, the HTTP/2 feature is disabled on SocketsHttpHandler unless certain | |
// AppContext switches or environment variables are set. To help with testing, we can enable the HTTP/2 | |
// feature for a specific handler instance by using reflection. | |
FieldInfo field_socketsHttpHandler = typeof(HttpClientHandler).GetField( | |
"_socketsHttpHandler", | |
BindingFlags.NonPublic | BindingFlags.Instance); | |
if (field_socketsHttpHandler == null) | |
{ | |
// Not using .NET Core implementation, i.e. could be .NET Framework or UAP. | |
return; | |
} | |
object _socketsHttpHandler = field_socketsHttpHandler.GetValue(handler); | |
if (_socketsHttpHandler == null) | |
{ | |
// Not using SocketsHttpHandler, i.e. using WinHttpHandler or CurlHandler. | |
return; | |
} | |
// Get HttpConnectionSettings object from SocketsHttpHandler. | |
Type type_SocketsHttpHandler = typeof(HttpClientHandler).Assembly.GetType("System.Net.Http.SocketsHttpHandler"); | |
FieldInfo field_settings = type_SocketsHttpHandler.GetField( | |
"_settings", | |
BindingFlags.NonPublic | BindingFlags.Instance); | |
object _settings = field_settings.GetValue(_socketsHttpHandler); | |
// Set _maxHttpVersion field to HTTP/2.0. | |
Type type_HttpConnectionSettings = typeof(HttpClientHandler).Assembly.GetType("System.Net.Http.HttpConnectionSettings"); | |
FieldInfo field_maxHttpVersion = type_HttpConnectionSettings.GetField( | |
"_maxHttpVersion", | |
BindingFlags.NonPublic | BindingFlags.Instance); | |
field_maxHttpVersion.SetValue(_settings, new Version(2, 0)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment