Exemplo n.º 1
0
        private void AddMethodCore <TRequest, TResponse>(
            Method <TRequest, TResponse> method,
            HttpRule httpRule,
            string pattern,
            string httpVerb,
            string body,
            string responseBody,
            MethodDescriptor methodDescriptor)
            where TRequest : class
            where TResponse : class
        {
            try
            {
                if (!pattern.StartsWith('/'))
                {
                    // This validation is consistent with grpc-gateway code generation.
                    // We should match their validation to be a good member of the eco-system.
                    throw new InvalidOperationException($"Path template must start with /: {pattern}");
                }

                var(invoker, metadata) = CreateModelCore <UnaryServerMethod <TService, TRequest, TResponse> >(
                    method.Name,
                    new[] { typeof(TRequest), typeof(ServerCallContext) },
                    httpVerb,
                    httpRule,
                    methodDescriptor);

                var methodContext = global::Grpc.Shared.Server.MethodOptions.Create(new[] { _globalOptions, _serviceOptions });

                var routePattern = RoutePatternFactory.Parse(pattern);
                var routeParameterDescriptors = ServiceDescriptorHelpers.ResolveRouteParameterDescriptors(routePattern, methodDescriptor.InputType);

                ServiceDescriptorHelpers.ResolveBodyDescriptor(body, methodDescriptor, out var bodyDescriptor, out var bodyFieldDescriptors, out var bodyDescriptorRepeated);

                FieldDescriptor?responseBodyDescriptor = null;
                if (!string.IsNullOrEmpty(responseBody))
                {
                    responseBodyDescriptor = methodDescriptor.OutputType.FindFieldByName(responseBody);
                    if (responseBodyDescriptor == null)
                    {
                        throw new InvalidOperationException($"Couldn't find matching field for response body '{responseBody}' on {methodDescriptor.OutputType.Name}.");
                    }
                }

                var unaryInvoker           = new UnaryServerMethodInvoker <TService, TRequest, TResponse>(invoker, method, methodContext, _serviceActivator);
                var unaryServerCallHandler = new UnaryServerCallHandler <TService, TRequest, TResponse>(
                    unaryInvoker,
                    responseBodyDescriptor,
                    bodyDescriptor,
                    bodyDescriptorRepeated,
                    bodyFieldDescriptors,
                    routeParameterDescriptors);

                _context.AddMethod <TRequest, TResponse>(method, routePattern, metadata, unaryServerCallHandler.HandleCallAsync);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Error binding {method.Name} on {typeof(TService).Name} to HTTP API.", ex);
            }
        }
Exemplo n.º 2
0
 public UnaryServerCallHandler(
     UnaryServerMethodInvoker <TService, TRequest, TResponse> invoker,
     ILoggerFactory loggerFactory)
     : base(invoker, loggerFactory)
 {
     _invoker = invoker;
 }
Exemplo n.º 3
0
 public UnaryServerCallHandler(
     UnaryServerMethodInvoker <TService, TRequest, TResponse> unaryMethodInvoker,
     FieldDescriptor?responseBodyDescriptor,
     MessageDescriptor?bodyDescriptor,
     bool bodyDescriptorRepeated,
     List <FieldDescriptor>?bodyFieldDescriptors,
     Dictionary <string, List <FieldDescriptor> > routeParameterDescriptors,
     GrpcHttpApiOptions httpApiOptions)
 {
     _unaryMethodInvoker     = unaryMethodInvoker;
     _responseBodyDescriptor = responseBodyDescriptor;
     _bodyDescriptor         = bodyDescriptor;
     _bodyDescriptorRepeated = bodyDescriptorRepeated;
     _bodyFieldDescriptors   = bodyFieldDescriptors;
     if (_bodyFieldDescriptors != null)
     {
         _bodyFieldDescriptorsPath = string.Join('.', _bodyFieldDescriptors.Select(d => d.Name));
     }
     if (_bodyDescriptorRepeated && _bodyFieldDescriptors != null)
     {
         _resolvedBodyFieldDescriptors = _bodyFieldDescriptors.Take(_bodyFieldDescriptors.Count - 1).ToList();
     }
     _routeParameterDescriptors = routeParameterDescriptors;
     _jsonFormatter             = httpApiOptions.JsonFormatter;
     _jsonParser           = httpApiOptions.JsonParser;
     _pathDescriptorsCache = new ConcurrentDictionary <string, List <FieldDescriptor>?>(StringComparer.Ordinal);
 }
Exemplo n.º 4
0
        public async Task Invoke_AwaitedSuccess_ReleaseCalled()
        {
            // Arrange
            var methodTcs        = new TaskCompletionSource <TestMessage>(TaskCreationOptions.RunContinuationsAsynchronously);
            var methodResult     = new TestMessage();
            var serviceActivator = new TestGrpcServiceActivator <TestService>();
            var invoker          = new UnaryServerMethodInvoker <TestService, TestMessage, TestMessage>(
                (service, reader, context) => methodTcs.Task,
                new Method <TestMessage, TestMessage>(MethodType.Unary, "test", "test", _marshaller, _marshaller),
                HttpContextServerCallContextHelper.CreateMethodOptions(),
                serviceActivator);
            var httpContext = HttpContextHelpers.CreateContext();

            // Act
            var task = invoker.Invoke(httpContext, HttpContextServerCallContextHelper.CreateServerCallContext(), new TestMessage());

            Assert.False(task.IsCompleted);

            methodTcs.SetResult(methodResult);
            var awaitedResult = await task;

            // Assert
            Assert.AreEqual(methodResult, awaitedResult);
            Assert.True(serviceActivator.Released);
        }
Exemplo n.º 5
0
 public UnaryServerCallHandler(
     UnaryServerMethodInvoker <TService, TRequest, TResponse> unaryMethodInvoker,
     ILoggerFactory loggerFactory,
     CallHandlerDescriptorInfo descriptorInfo,
     JsonSerializerOptions options) : base(unaryMethodInvoker, loggerFactory, descriptorInfo, options)
 {
     _invoker = unaryMethodInvoker;
 }
        public UnaryServerCallHandler <TService, TRequest, TResponse> CreateUnary <TRequest, TResponse>(Method <TRequest, TResponse> method, UnaryServerMethod <TService, TRequest, TResponse> invoker)
            where TRequest : class
            where TResponse : class
        {
            var options       = CreateMethodOptions();
            var methodInvoker = new UnaryServerMethodInvoker <TService, TRequest, TResponse>(invoker, method, options, _serviceActivator);

            return(new UnaryServerCallHandler <TService, TRequest, TResponse>(methodInvoker, _loggerFactory));
        }
Exemplo n.º 7
0
 public UnaryServerCallHandler(
     UnaryServerMethodInvoker <TService, TRequest, TResponse> unaryMethodInvoker,
     FieldDescriptor?responseBodyDescriptor,
     MessageDescriptor?bodyDescriptor,
     FieldDescriptor?bodyFieldDescriptor,
     Dictionary <string, List <FieldDescriptor> > routeParameterDescriptors)
 {
     _unaryMethodInvoker        = unaryMethodInvoker;
     _responseBodyDescriptor    = responseBodyDescriptor;
     _bodyDescriptor            = bodyDescriptor;
     _bodyFieldDescriptor       = bodyFieldDescriptor;
     _routeParameterDescriptors = routeParameterDescriptors;
     _queryParameterDescriptors = new ConcurrentDictionary <string, List <FieldDescriptor> >(StringComparer.Ordinal);
 }
        private static UnaryServerCallHandler <HttpApiGreeterService, HelloRequest, HelloReply> CreateCallHandler(
            UnaryServerMethod <HttpApiGreeterService, HelloRequest, HelloReply> invoker,
            FieldDescriptor?responseBodyDescriptor = null,
            Dictionary <string, List <FieldDescriptor> >?routeParameterDescriptors = null,
            MessageDescriptor?bodyDescriptor    = null,
            FieldDescriptor?bodyFieldDescriptor = null)
        {
            var unaryServerCallInvoker = new UnaryServerMethodInvoker <HttpApiGreeterService, HelloRequest, HelloReply>(
                invoker,
                CreateServiceMethod <HelloRequest, HelloReply>("TestMethodName", HelloRequest.Parser, HelloReply.Parser),
                Shared.Server.MethodOptions.Create(new[] { new GrpcServiceOptions() }),
                new TestGrpcServiceActivator <HttpApiGreeterService>());

            return(new UnaryServerCallHandler <HttpApiGreeterService, HelloRequest, HelloReply>(
                       unaryServerCallInvoker,
                       responseBodyDescriptor,
                       bodyDescriptor,
                       bodyFieldDescriptor,
                       routeParameterDescriptors ?? new Dictionary <string, List <FieldDescriptor> >()));
        }
Exemplo n.º 9
0
        public async Task Invoke_SuccessAwaitedRelease_ReleaseCalled()
        {
            // Arrange
            var releaseTcs       = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);
            var serviceActivator = new TcsGrpcServiceActivator <TestService>(releaseTcs);
            var invoker          = new UnaryServerMethodInvoker <TestService, TestMessage, TestMessage>(
                (service, reader, context) => Task.FromResult(new TestMessage()),
                new Method <TestMessage, TestMessage>(MethodType.Unary, "test", "test", _marshaller, _marshaller),
                HttpContextServerCallContextHelper.CreateMethodOptions(),
                serviceActivator);
            var httpContext = HttpContextHelpers.CreateContext();

            // Act
            var task = invoker.Invoke(httpContext, HttpContextServerCallContextHelper.CreateServerCallContext(), new TestMessage());

            Assert.False(task.IsCompleted);

            releaseTcs.SetResult(null);
            await task;

            // Assert
            Assert.True(serviceActivator.Released);
        }
Exemplo n.º 10
0
        private void AddMethodCore <TRequest, TResponse>(
            Method <TRequest, TResponse> method,
            string pattern,
            string httpVerb,
            string body,
            string responseBody,
            MethodDescriptor methodDescriptor)
            where TRequest : class
            where TResponse : class
        {
            try
            {
                var(invoker, metadata) = CreateModelCore <UnaryServerMethod <TService, TRequest, TResponse> >(
                    method.Name,
                    new[] { typeof(TRequest), typeof(ServerCallContext) },
                    httpVerb);

                var methodContext = global::Grpc.Shared.Server.MethodOptions.Create(new[] { _globalOptions, _serviceOptions });

                var routeParameterDescriptors = ResolveRouteParameterDescriptors(pattern, methodDescriptor.InputType);

                MessageDescriptor?bodyDescriptor      = null;
                FieldDescriptor?  bodyFieldDescriptor = null;
                if (!string.IsNullOrEmpty(body))
                {
                    if (!string.Equals(body, "*", StringComparison.Ordinal))
                    {
                        bodyFieldDescriptor = methodDescriptor.InputType.FindFieldByName(body);
                        if (bodyFieldDescriptor == null)
                        {
                            throw new InvalidOperationException($"Couldn't find matching field for body '{body}' on {methodDescriptor.InputType.Name}.");
                        }
                        bodyDescriptor = bodyFieldDescriptor.ContainingType;
                    }
                    else
                    {
                        bodyDescriptor = methodDescriptor.InputType;
                    }
                }

                FieldDescriptor?responseBodyDescriptor = null;
                if (!string.IsNullOrEmpty(responseBody))
                {
                    responseBodyDescriptor = methodDescriptor.OutputType.FindFieldByName(responseBody);
                    if (responseBodyDescriptor == null)
                    {
                        throw new InvalidOperationException($"Couldn't find matching field for response body '{responseBody}' on {methodDescriptor.OutputType.Name}.");
                    }
                }

                var unaryInvoker           = new UnaryServerMethodInvoker <TService, TRequest, TResponse>(invoker, method, methodContext, _serviceActivator);
                var unaryServerCallHandler = new UnaryServerCallHandler <TService, TRequest, TResponse>(
                    unaryInvoker,
                    responseBodyDescriptor,
                    bodyDescriptor,
                    bodyFieldDescriptor,
                    routeParameterDescriptors);

                _context.AddMethod <TRequest, TResponse>(method, RoutePatternFactory.Parse(pattern), metadata, unaryServerCallHandler.HandleCallAsync);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Error binding {method.Name} on {typeof(TService).Name} to HTTP API.", ex);
            }
        }
Exemplo n.º 11
0
        private void AddMethodCore <TRequest, TResponse>(
            Method <TRequest, TResponse> method,
            string pattern,
            string httpVerb,
            string body,
            string responseBody,
            MethodDescriptor methodDescriptor)
            where TRequest : class
            where TResponse : class
        {
            try
            {
                if (!pattern.StartsWith('/'))
                {
                    // This validation is consistent with grpc-gateway code generation.
                    // We should match their validation to be a good member of the eco-system.
                    throw new InvalidOperationException($"Path template must start with /: {pattern}");
                }

                var(invoker, metadata) = CreateModelCore <UnaryServerMethod <TService, TRequest, TResponse> >(
                    method.Name,
                    new[] { typeof(TRequest), typeof(ServerCallContext) },
                    httpVerb);

                var methodContext = global::Grpc.Shared.Server.MethodOptions.Create(new[] { _globalOptions, _serviceOptions });

                var routeParameterDescriptors = ResolveRouteParameterDescriptors(pattern, methodDescriptor.InputType);

                MessageDescriptor?     bodyDescriptor       = null;
                List <FieldDescriptor>?bodyFieldDescriptors = null;
                var bodyDescriptorRepeated = false;
                if (!string.IsNullOrEmpty(body))
                {
                    if (!string.Equals(body, "*", StringComparison.Ordinal))
                    {
                        if (!ServiceDescriptorHelpers.TryResolveDescriptors(methodDescriptor.InputType, body, out bodyFieldDescriptors))
                        {
                            throw new InvalidOperationException($"Couldn't find matching field for body '{body}' on {methodDescriptor.InputType.Name}.");
                        }
                        var leafDescriptor = bodyFieldDescriptors.Last();
                        if (leafDescriptor.IsRepeated)
                        {
                            // A repeating field isn't a message type. The JSON parser will parse using the containing
                            // type to get the repeating collection.
                            bodyDescriptor         = leafDescriptor.ContainingType;
                            bodyDescriptorRepeated = true;
                        }
                        else
                        {
                            bodyDescriptor = leafDescriptor.MessageType;
                        }
                    }
                    else
                    {
                        bodyDescriptor = methodDescriptor.InputType;
                    }
                }

                FieldDescriptor?responseBodyDescriptor = null;
                if (!string.IsNullOrEmpty(responseBody))
                {
                    responseBodyDescriptor = methodDescriptor.OutputType.FindFieldByName(responseBody);
                    if (responseBodyDescriptor == null)
                    {
                        throw new InvalidOperationException($"Couldn't find matching field for response body '{responseBody}' on {methodDescriptor.OutputType.Name}.");
                    }
                }

                var unaryInvoker           = new UnaryServerMethodInvoker <TService, TRequest, TResponse>(invoker, method, methodContext, _serviceActivator);
                var unaryServerCallHandler = new UnaryServerCallHandler <TService, TRequest, TResponse>(
                    unaryInvoker,
                    responseBodyDescriptor,
                    bodyDescriptor,
                    bodyDescriptorRepeated,
                    bodyFieldDescriptors,
                    routeParameterDescriptors);

                _context.AddMethod <TRequest, TResponse>(method, RoutePatternFactory.Parse(pattern), metadata, unaryServerCallHandler.HandleCallAsync);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"Error binding {method.Name} on {typeof(TService).Name} to HTTP API.", ex);
            }
        }