Example #1
0
        public static async Task HandleGrpcRequestAsync(this DownstreamContext context, Func <Task> next, SslCredentials secureCredentials = null)
        {
            // ignore if the request is not a gRPC content type
            if (!context.HttpContext.Request.Headers.Any(h => h.Key.ToLowerInvariant() == "content-type" && h.Value == "application/grpc"))
            {
                await next.Invoke();
            }
            else
            {
                var methodPath           = context.DownstreamReRoute.DownstreamPathTemplate.Value;
                var grpcAssemblyResolver = context.HttpContext.RequestServices.GetService <GrpcAssemblyResolver>();
                var methodDescriptor     = grpcAssemblyResolver.FindMethodDescriptor(methodPath.Split('/').Last().ToUpperInvariant());

                if (methodDescriptor == null)
                {
                    await next.Invoke();
                }
                else
                {
                    string requestData;
                    var    upstreamHeaders = new Dictionary <string, string>
                    {
                        { "x-grpc-route-data", JsonConvert.SerializeObject(context.TemplatePlaceholderNameAndValues.Select(x => new { x.Name, x.Value })) },
                        { "x-grpc-body-data", await context.DownstreamRequest.Content.ReadAsStringAsync() }
                    };
                    if (context.HttpContext.Request.Method.ToLowerInvariant() == "get")
                    {
                        requestData = context.HttpContext.ParseGetJsonRequest(upstreamHeaders);
                    }
                    else
                    {
                        requestData = context.HttpContext.ParseOtherJsonRequest(upstreamHeaders);
                    }

                    var loadBalancerFactory  = context.HttpContext.RequestServices.GetService <ILoadBalancerFactory>();
                    var loadBalancerResponse = await loadBalancerFactory.Get(context.DownstreamReRoute, context.Configuration.ServiceProviderConfiguration);

                    var serviceHostPort = await loadBalancerResponse.Data.Lease(context);

                    var downstreamAddress = context.DownstreamReRoute.DownstreamAddresses.FirstOrDefault();
                    var downstreamHost    = $"{serviceHostPort.Data.DownstreamHost}:{serviceHostPort.Data.DownstreamPort}";

                    var channel = new Channel(downstreamHost, secureCredentials ?? ChannelCredentials.Insecure);
                    var client  = new MethodDescriptorCaller(channel);

                    var requestObject = JsonConvert.DeserializeObject(requestData, methodDescriptor.InputType.ClrType);
                    var result        = await client.InvokeAsync(methodDescriptor, context.HttpContext.GetRequestHeaders(), requestObject);

                    var response            = new OkResponse <GrpcHttpContent>(new GrpcHttpContent(JsonConvert.SerializeObject(result)));
                    var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = response.Data
                    };

                    context.HttpContext.Response.ContentType = "application/json";
                    context.DownstreamResponse = new DownstreamResponse(httpResponseMessage);
                }
            }
        }
Example #2
0
        public static async Task HandleGrpcRequestAsync(this DownstreamContext context, Func <Task> next)
        {
            // ignore if the request is not a gRPC content type
            if (!context.HttpContext.Request.Headers.Any(h => h.Key.ToLowerInvariant() == "content-type" && h.Value == "application/grpc"))
            {
                await next.Invoke();
            }
            else
            {
                var methodPath           = context.DownstreamReRoute.DownstreamPathTemplate.Value;
                var grpcAssemblyResolver = context.HttpContext.RequestServices.GetService <GrpcAssemblyResolver>();
                var methodDescriptor     = grpcAssemblyResolver.FindMethodDescriptor(methodPath.Split('/').Last().ToUpperInvariant());

                if (methodDescriptor == null)
                {
                    await next.Invoke();
                }
                else
                {
                    string requestData;
                    var    upstreamHeaders = new Dictionary <string, string>
                    {
                        { "x-grpc-route-data", JsonConvert.SerializeObject(context.TemplatePlaceholderNameAndValues.Select(x => new { x.Name, x.Value })) },
                        { "x-grpc-body-data", await context.DownstreamRequest.Content.ReadAsStringAsync() }
                    };
                    if (context.HttpContext.Request.Method.ToLowerInvariant() == "get")
                    {
                        requestData = context.HttpContext.ParseGetJsonRequest(upstreamHeaders);
                    }
                    else
                    {
                        requestData = context.HttpContext.ParseOtherJsonRequest(upstreamHeaders);
                    }

                    // todo: only get the first one, currently we use service mesh to LB the downstream gRPC services
                    // but we open to support it with manually LB such as Consult
                    var downstreamAddress = context.DownstreamReRoute.DownstreamAddresses.FirstOrDefault();
                    var downstreamHost    = $"{downstreamAddress.Host}:{downstreamAddress.Port}";

                    var channel = new Channel(downstreamHost, ChannelCredentials.Insecure); //todo: handle TLS with certs later
                    var client  = new MethodDescriptorCaller(channel);

                    var requestObject = JsonConvert.DeserializeObject(requestData, methodDescriptor.InputType.ClrType);
                    var result        = await client.InvokeAsync(methodDescriptor, context.HttpContext.GetRequestHeaders(), requestObject);

                    var response            = new OkResponse <GrpcHttpContent>(new GrpcHttpContent(JsonConvert.SerializeObject(result)));
                    var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = response.Data
                    };

                    context.HttpContext.Response.ContentType = "application/json";
                    context.DownstreamResponse = new DownstreamResponse(httpResponseMessage);
                }
            }
        }
        public async Task Invoke(HttpContext context, GrpcAssemblyResolver grpcAssemblyResolver, IOptions <GrpcMapperOptions> options)
        {
            if (!context.Request.Headers.Any(h => h.Key.ToLowerInvariant() == "content-type" && h.Value == "application/grpc"))
            {
                await _next(context);
            }
            else
            {
                var path = context.Request.Path.Value;

                var methodDescriptor = grpcAssemblyResolver.FindMethodDescriptor(path.Split('/').Last().ToUpperInvariant());

                if (methodDescriptor == null)
                {
                    await _next(context);
                }
                else
                {
                    string requestData;

                    if (context.Request.Method.ToLowerInvariant() == "get")
                    {
                        requestData = context.ParseGetJsonRequestOnAggregateService();
                    }
                    else
                    {
                        requestData = await context.ParseOtherJsonRequestOnAggregateService();
                    }

                    var grpcLookupTable = options.Value.GrpcMappers;
                    var grpcClient      = grpcLookupTable.FirstOrDefault(x => x.GrpcMethod == path).GrpcHost; //todo: should catch object to throw exception

                    var channel = new Channel(grpcClient, ChannelCredentials.Insecure);
                    var client  = new MethodDescriptorCaller(channel);

                    var requestObject = JsonConvert.DeserializeObject(requestData, methodDescriptor.InputType.ClrType);
                    var result        = await client.InvokeAsync(methodDescriptor, context.GetRequestHeaders(), requestObject);

                    await context.Response.WriteAsync(JsonConvert.SerializeObject(result));
                }
            }
        }