/// <summary> /// Process grpc request /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> private async Task ProcessInternal(HttpContext context, Func <Task> next) { var downstreamRoute = context.Items.DownstreamRoute(); var methodPath = downstreamRoute.DownstreamPathTemplate.Value; try { var grpcAssemblyResolver = context.RequestServices.GetService <GrpcAssemblyResolver>(); var methodDescriptor = grpcAssemblyResolver.FindMethodDescriptor(methodPath.Split('/').Last().ToUpperInvariant()); if (methodDescriptor == null) { await next.Invoke(); return; } var downstreamRequest = context.Items.DownstreamRequest(); var upstreamHeaders = new Dictionary <string, string> { { "x-grpc-route-data", JsonConvert.SerializeObject( context.Items.TemplatePlaceholderNameAndValues().Select(x => new { x.Name, x.Value })) }, { "x-grpc-body-data", await downstreamRequest.Content.ReadAsStringAsync() } }; var requestData = context.ParseJsonRequest(upstreamHeaders); var client = await CreateGrpcClient(context); var timeout = _options.GetRouteTimeout(methodPath); var deadline = (timeout != TimeSpan.MaxValue) ? DateTime.UtcNow.Add(timeout) : DateTime.MaxValue; var requestObject = JsonConvert.DeserializeObject(requestData, methodDescriptor.InputType.ClrType, _jsonSerializerSettings); var headers = context.BuildRequestHeaders(downstreamRoute, downstreamRequest); var result = await client.InvokeAsync(methodDescriptor, headers, requestObject, deadline); var content = new GrpcHttpContent(JsonConvert.SerializeObject(result, _jsonSerializerSettings)); var response = new OkResponse <GrpcHttpContent>(content); response.Data.Headers.ContentType = new MediaTypeHeaderValue(MediaTypeNames.Application.Json); context.Response.ContentType = MediaTypeNames.Application.Json; context.Items.UpsertDownstreamResponse(new DownstreamResponse(response.Data, HttpStatusCode.OK, response.Data.Headers, HttpStatusCode.OK.ToString())); } catch (RpcException e) { ProcessRpcError(context, e); } catch (Exception e) { ProcessError(context, e); } }
private static DownstreamResponse CreateHttpResponseMessage(CachedResponse cached) { if (cached == null) { return(null); } var streamContent = new GrpcHttpContent(cached.Body); foreach (var(key, value) in cached.ContentHeaders) { streamContent.Headers.TryAddWithoutValidation(key, value); } return(new DownstreamResponse(streamContent, cached.StatusCode, cached.Headers.ToList(), cached.ReasonPhrase)); }
private static void ProcessError(HttpContext context, Exception e) { var content = new GrpcHttpContent(new ApiResponse { ResponseCode = _defaultErrorStatus, Errors = new[] { new ApiError(e.Message, e.InnerException?.Message) } }); context.Response.ContentType = MediaTypeNames.Application.Json; var response = new DownstreamResponse(content, _defaultErrorCode, new List <Header> { new Header(HeaderNames.ContentType, new [] { MediaTypeNames.Application.Json }) }, _defaultErrorCode.ToString()); context.Items.UpsertDownstreamResponse(response); }
public async Task Invoke(HttpContext context, Func <Task> next) { var downstreamRoute = context.Items.DownstreamRoute(); var methodPath = downstreamRoute.DownstreamPathTemplate.Value; // ignore if the request is not a gRPC content type if (!_options.IsGrpcRoute(methodPath)) { await next.Invoke(); if (context.Items.DownstreamResponse() != null) // if has response - everything is ok, just return { return; } // add human friendly error message for grpc-call var errors = context.Items.Errors() ?? new List <Error>(); var response = new GrpcHttpContent(new { ResponseCode = _defaultErrorStatus, Errors = errors.Any() ? errors .Select(x => $"{x.Code}: {x.Message}") .ToArray() : new[] { "Request process error. Either request is invalid or application wasn't configured properly" } }); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)_defaultErrorCode; await response.WriteStream(context.Response.Body); return; } await _cacheHelper.Process(context, async ctx => await ProcessInternal(ctx, next)); }