コード例 #1
0
        protected override void AddGenericBlockingMethodCore <TRequest, TReturn, TResponseReturn>(
            Func <TService, TRequest, CancellationToken, TReturn> serviceCaller,
            Func <TReturn, TResponseReturn>?responseConverter,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub,
            RpcOperationInfo operationInfo,
            INetGrpcBinder <TService> binder)
        {
            var serializer = serviceStub.Serializer;

            Task <RpcResponse <TResponseReturn> > Handler(NetGrpcServiceActivator <TService> activator, TRequest request, ServerCallContext context)
            => serviceStub.CallBlockingMethod(
                request,
                new GrpcCallContext(context),
                serviceCaller,
                responseConverter,
                faultHandler,
                serializer,
                activator.ServiceProvider).AsTask();

            var methodStub = GrpcMethodDefinition.Create <TRequest, RpcResponse <TResponseReturn> >(
                MethodType.Unary,
                operationInfo.FullServiceName, operationInfo.Name,
                serializer);

            binder.AddUnaryMethod(methodStub, operationInfo.Metadata, Handler);
        }
コード例 #2
0
        private Type CreateResponseType(ModuleBuilder dynamicModuleBuilder, RpcOperationInfo opInfo)
        {
            try
            {
                var typeBuilder   = dynamicModuleBuilder.DefineType($"{opInfo.Service.Name}_{opInfo.Name}Reply");
                var contractCtor  = typeof(ProtoContractAttribute).GetConstructor(Type.EmptyTypes);
                var attribBuilder = new CustomAttributeBuilder(contractCtor, Array.Empty <object>());
                typeBuilder.SetCustomAttribute(attribBuilder);

                var errorField = typeBuilder.DefineField("Error", typeof(RpcError), FieldAttributes.Public);
                AddMemberAttribute(errorField, 1);
                if (!Equals(opInfo.ResponseReturnType, typeof(void)))
                {
                    var resultField = typeBuilder.DefineField("Result", opInfo.ResponseReturnType, FieldAttributes.Public);
                    AddMemberAttribute(resultField, 2);
                }
                _ = opInfo.Method.GetParameters();
                return(typeBuilder.CreateType());
            }
            catch (Exception e)
            {
                LogWarning(2, $"Failed to create reply type for operation '{opInfo.FullName}'", e);
            }

            return(null);
        }
コード例 #3
0
        protected override void AddCallbackMethodCore <TRequest, TReturn, TResponseReturn>(
            Func <TService, TRequest, Action <TReturn>, CancellationToken, Task> serviceCaller,
            Func <TReturn, TResponseReturn>?responseConverter, RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub, RpcOperationInfo operationInfo, INetGrpcBinder <TService> binder)
        {
            var serializer = serviceStub.Serializer;
            ServerStreamingServerMethod <NetGrpcServiceActivator <TService>, TRequest, TResponseReturn> handler = (activator, request, responseStream, context) =>
            {
                return(serviceStub.CallCallbackMethod(
                           request,
                           activator.ServiceProvider,
                           new GrpcCallContext(context),
                           new GrpcAsyncStreamWriter <TResponseReturn>(responseStream),
                           serviceCaller,
                           responseConverter,
                           faultHandler,
                           serializer).AsTask());
            };

            var methodStub = GrpcMethodDefinition.Create <TRequest, TResponseReturn>(
                MethodType.ServerStreaming,
                operationInfo.FullServiceName, operationInfo.Name,
                serializer);

            binder.AddServerStreamingMethod(methodStub, operationInfo.Metadata, handler);
        }
コード例 #4
0
        protected override void AddCallbackMethodCore <TRequest, TReturn, TResponseReturn>(
            Func <TService, TRequest, Action <TReturn>, CancellationToken, Task> serviceCaller,
            Func <TReturn, TResponseReturn>?responseConverter, RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub, RpcOperationInfo operationInfo, IGrpcMethodBinder binder)
            where TResponseReturn : class
        {
            var serializer = serviceStub.Serializer;

            GrpcCore.ServerStreamingServerMethod <TRequest, TResponseReturn> handler = (request, responseStream, context) =>
            {
                using (var serviceScope = CreateServiceScope(serviceStub))
                {
                    return(serviceStub.CallCallbackMethod(
                               request,
                               serviceScope?.ServiceProvider,
                               new GrpcCallContext(context),
                               new GrpcAsyncStreamWriter <TResponseReturn>(responseStream),
                               serviceCaller,
                               responseConverter,
                               faultHandler,
                               serializer).AsTask());
                }
            };

            binder.AddMethod(
                GrpcMethodDefinition.Create <TRequest, TResponseReturn>(
                    GrpcCore.MethodType.ServerStreaming,
                    operationInfo.FullServiceName,
                    operationInfo.Name,
                    serviceStub.Serializer),
                handler);
        }
コード例 #5
0
        protected override void AddGenericBlockingMethodCore <TRequest, TReturn, TResponseReturn>(
            Func <TService, TRequest, CancellationToken, TReturn> serviceCaller,
            Func <TReturn, TResponseReturn>?responseConverter,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub,
            RpcOperationInfo operationInfo,
            IGrpcMethodBinder binder)
        {
            var serializer = serviceStub.Serializer;

            Task <RpcResponse <TResponseReturn> > handler(TRequest request, GrpcCore.ServerCallContext context)
            {
                using (var serviceScope = CreateServiceScope(serviceStub))
                {
                    return(serviceStub.CallBlockingMethod(
                               request, new GrpcCallContext(context), serviceCaller, responseConverter,
                               faultHandler, serializer, serviceScope?.ServiceProvider).AsTask());
                }
            }

            binder.AddMethod(
                GrpcMethodDefinition.Create <TRequest, RpcResponse <TResponseReturn> >(GrpcCore.MethodType.Unary,
                                                                                       operationInfo.FullServiceName, operationInfo.Name, serializer),
                handler);
        }
コード例 #6
0
 protected abstract void AddGenericVoidBlockingMethodCore <TRequest>(
     Action <TService, TRequest, CancellationToken> serviceCaller,
     RpcServerFaultHandler faultHandler,
     RpcStub <TService> serviceStub,
     RpcOperationInfo operationInfo,
     TMethodBinder binder)
     where TRequest : class, IObjectRequest;
コード例 #7
0
 protected abstract void AddGenericBlockingMethodCore <TRequest, TReturn, TResponseReturn>(
     Func <TService, TRequest, CancellationToken, TReturn> serviceCaller,
     Func <TReturn, TResponseReturn>?responseConverter,
     RpcServerFaultHandler faultHandler,
     RpcStub <TService> serviceStub,
     RpcOperationInfo operationInfo,
     TMethodBinder binder)
     where TRequest : class, IObjectRequest;
コード例 #8
0
            where TResponseReturn : class;  // Needs to be class due to gRPC restriction

        protected abstract void AddCallbackMethodCore <TRequest, TReturn, TResponseReturn>(
            Func <TService, TRequest, Action <TReturn>, CancellationToken, Task> serviceCaller,
            Func <TReturn, TResponseReturn>?responseConverter,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub,
            RpcOperationInfo operationInfo,
            TMethodBinder binder)
            where TRequest : class, IObjectRequest
            where TResponseReturn : class;  // Needs to be class due to gRPC constraint
コード例 #9
0
 protected abstract void AddServerStreamingMethodCore <TRequest, TReturn, TResponseReturn>(
     Func <TService, TRequest, CancellationToken, IAsyncEnumerable <TReturn> > serviceCaller,
     Func <TReturn, TResponseReturn>?responseConverter,
     RpcServerFaultHandler faultHandler,
     RpcStub <TService> serviceStub,
     RpcOperationInfo operationInfo,
     TMethodBinder binder)
     where TRequest : class, IObjectRequest
     where TResponseReturn : class;  // Needs to be class due to gRPC restriction
コード例 #10
0
        protected override void AddCallbackMethodCore <TRequest, TReturn, TResponse>(
            Func <TService, TRequest, Action <TReturn>, CancellationToken, Task> serviceCaller,
            Func <TReturn, TResponse>?responseConverter,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub, RpcOperationInfo operationInfo, ILightweightMethodBinder binder)
        {
            var serializer = serviceStub.Serializer;

            ValueTask HandleRequest(TRequest request, IServiceProvider?serviceProvider, IRpcAsyncStreamWriter <TResponse> responseWriter, LightweightCallContext context)
            => serviceStub.CallCallbackMethod(request, serviceProvider, context, responseWriter, serviceCaller, responseConverter, faultHandler, serializer);

            var methodStub = new LightweightStreamingMethodStub <TRequest, TResponse>(operationInfo.FullName, HandleRequest, serializer, faultHandler);

            binder.AddMethod(methodStub);
        }
コード例 #11
0
        protected override void AddGenericVoidBlockingMethodCore <TRequest>(
            Action <TService, TRequest, CancellationToken> serviceCaller,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub,
            RpcOperationInfo operationInfo,
            ILightweightMethodBinder binder)
        {
            var serializer = operationInfo.SerializerOverride ?? serviceStub.Serializer;

            ValueTask <RpcResponse> HandleRequest(TRequest request, IServiceProvider?serviceProvider, LightweightCallContext context)
            => serviceStub.CallVoidBlockingMethod(request, serviceProvider, context, serviceCaller, faultHandler, serializer);

            var methodStub = new LightweightMethodStub <TRequest, RpcResponse>(operationInfo.FullName, HandleRequest, serializer, faultHandler,
                                                                               operationInfo.AllowInlineExecution);

            binder.AddMethod(methodStub);
        }
コード例 #12
0
        private Type CreateRequestType(ModuleBuilder dynamicModuleBuilder, RpcOperationInfo opInfo)
        {
            try
            {
                var typeBuilder   = dynamicModuleBuilder.DefineType($"{opInfo.Service.Name}_{opInfo.Name}Request");
                var contractCtor  = typeof(ProtoContractAttribute).GetConstructor(Type.EmptyTypes);
                var attribBuilder = new CustomAttributeBuilder(contractCtor, Array.Empty <object>());
                typeBuilder.SetCustomAttribute(attribBuilder);

                var parameters = opInfo.Method.GetParameters();
                int paramIndex = 0;
                foreach (var argType in opInfo.RequestParameters)
                {
                    FieldBuilder fieldBuilder;
                    if (paramIndex == 0)
                    {
                        fieldBuilder = typeBuilder.DefineField("Id", typeof(RpcObjectId), FieldAttributes.Public);
                    }
                    else
                    {
                        fieldBuilder = typeBuilder.DefineField(parameters[paramIndex - 1].Name, argType.Type, FieldAttributes.Public);
                    }

                    AddMemberAttribute(fieldBuilder, paramIndex + 1);

                    paramIndex++;
                }

                return(typeBuilder.CreateType());
            }
            catch (Exception e)
            {
                LogWarning(2, $"Failed to create request type for operation '{opInfo.FullName}'", e);
            }

            return(null);
        }
コード例 #13
0
        protected override void AddGenericVoidBlockingMethodCore <TRequest>(
            Action <TService, TRequest, CancellationToken> serviceCaller,
            RpcServerFaultHandler faultHandler,
            RpcStub <TService> serviceStub,
            RpcOperationInfo operationInfo,
            IGrpcMethodBinder binder)
        {
            var serializer = serviceStub.Serializer;

            GrpcCore.UnaryServerMethod <TRequest, RpcResponse> handler = (request, context) =>
            {
                using (var serviceScope = CreateServiceScope(serviceStub))
                {
                    return(serviceStub.CallVoidBlockingMethod(
                               request, serviceScope?.ServiceProvider, new GrpcCallContext(context), serviceCaller,
                               faultHandler, serializer).AsTask());
                }
            };

            binder.AddMethod(
                GrpcMethodDefinition.Create <TRequest, RpcResponse>(GrpcCore.MethodType.Unary,
                                                                    operationInfo.FullServiceName, operationInfo.Name, serializer),
                handler);
        }
コード例 #14
0
        protected static Func <TService, TRequest, Action <TReturn>, CancellationToken, Task> GenerateBlockingCallbackMethodHandler <TRequest, TReturn>(RpcOperationInfo operationInfo)
            where TRequest : class
        {
            if (operationInfo is null)
            {
                throw new ArgumentNullException(nameof(operationInfo));
            }

            var requestParameter           = Expression.Parameter(typeof(TRequest));
            var callbackParameter          = Expression.Parameter(typeof(Action <TReturn>));
            var cancellationTokenParameter = Expression.Parameter(typeof(CancellationToken));

            List <Expression> parameterExpressions = GetParameterExpressions <TRequest>(operationInfo, requestParameter, callbackParameter, cancellationTokenParameter);

            var serviceParameter = Expression.Parameter(typeof(TService));

            var invocation = Expression.Call(serviceParameter, operationInfo.Method, parameterExpressions);

            var expression = Expression.Lambda <Action <TService, TRequest, Action <TReturn>, CancellationToken> >(
                invocation, false, serviceParameter, requestParameter, callbackParameter, cancellationTokenParameter);

            var func = expression.Compile();

            Task callFunc(TService service, TRequest request, Action <TReturn> callback, CancellationToken cancellation)
            {
                func(service, request, callback, cancellation);
                return(Task.CompletedTask);
            }

            return(callFunc);
        }
コード例 #15
0
        protected static Func <TService, TRequest, CancellationToken, Task <TResponse> > GenerateUnaryMethodHandler <TRequest, TResponse>(RpcOperationInfo operationInfo)
            where TRequest : class
        {
            if (operationInfo is null)
            {
                throw new ArgumentNullException(nameof(operationInfo));
            }

            var requestParameter           = Expression.Parameter(typeof(TRequest));
            var cancellationTokenParameter = Expression.Parameter(typeof(CancellationToken));

            List <Expression> parameterExpressions = GetParameterExpressions <TRequest>(operationInfo, requestParameter, cancellationTokenParameter);

            var serviceParameter = Expression.Parameter(typeof(TService));

            var invocation = Expression.Call(serviceParameter, operationInfo.Method, parameterExpressions);
            var expression = Expression.Lambda <Func <TService, TRequest, CancellationToken, Task <TResponse> > >(
                invocation, false, serviceParameter, requestParameter, cancellationTokenParameter);

            var func = expression.Compile();

            return(func);
        }
コード例 #16
0
        /// <summary>
        /// Enumerates all declared RPC members in the service interface specified by <paramref name="serviceInfo"/>.
        /// </summary>
        /// <param name="serviceInfo"></param>
        /// <param name="splitProperties">Indicates that separate <see cref="RpcOperationInfo"/>s should be returned for property get/set
        /// methods, instead of a single <see cref="RpcPropertyInfo"/>.</param>
        /// <returns></returns>
        // TODO: This method should maybe be moved to RpcServiceInfo, or at least be an RpcServiceInfo extension method.
        public static IEnumerable <RpcMemberInfo> EnumOperationHandlers(RpcServiceInfo serviceInfo, bool splitProperties)
        {
            var handledMembers = new HashSet <MemberInfo>();

            var events = serviceInfo.Type.GetEvents(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

            foreach (var eventInfo in events)
            {
                if (eventInfo.EventHandlerType == null)
                {
                    // How could this happen?
                    throw new NotSupportedException($"{eventInfo.Name} has no EventHandlerType");
                }

                if (eventInfo.AddMethod == null || eventInfo.RemoveMethod == null)
                {
                    // How could this happen?
                    throw new NotSupportedException($"{eventInfo.Name} is missing an Add or Remove method.");
                }

                var rpcEventInfo = GetEventInfoFromEvent(serviceInfo, eventInfo);

                handledMembers.Add(eventInfo.AddMethod);
                handledMembers.Add(eventInfo.RemoveMethod);

                yield return(rpcEventInfo);
            }

            var properties = serviceInfo.Type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

            foreach (var propertyInfo in properties)
            {
                var rpcPropertyInfo      = RpcBuilderUtil.GetPropertyInfoFromProperty(serviceInfo, propertyInfo);
                var propertyRpcAttribute = propertyInfo.GetCustomAttribute <RpcOperationAttribute>();

                if (propertyInfo.GetMethod != null)
                {
                    if (splitProperties)
                    {
                        var getRpcAttribute = propertyInfo.GetMethod.GetCustomAttribute <RpcOperationAttribute>();

                        var getOp = new RpcOperationInfo(
                            service: rpcPropertyInfo.Service,
                            name: $"Get{propertyInfo.Name}",
                            declaringMember: propertyInfo,
                            method: propertyInfo.GetMethod,
                            requestType: typeof(RpcObjectRequest),
                            requestParameters: ImmutableArray <RpcRequestParameter> .Empty,
                            callbackParameterIndex: null,
                            cancellationTokenIndex: null,
                            methodType: RpcMethodType.Unary,
                            isAsync: false,
                            responseType: GetResponseType(RpcMethodType.Unary, rpcPropertyInfo.ResponseReturnType),
                            responseReturnType: rpcPropertyInfo.ResponseReturnType,
                            returnType: propertyInfo.PropertyType,
                            returnKind: rpcPropertyInfo.PropertyTypeKind,
                            allowInlineExecution: getRpcAttribute?.AllowInlineExecution ?? propertyRpcAttribute?.AllowInlineExecution ?? false,
                            metadata: GetPropertyMethodMetadata(serviceInfo, propertyInfo, propertyInfo.GetMethod)
                            );

                        yield return(getOp);
                    }

                    handledMembers.Add(propertyInfo.GetMethod);
                }

                if (propertyInfo.SetMethod != null)
                {
                    if (splitProperties)
                    {
                        var setRpcAttribute = propertyInfo.SetMethod.GetCustomAttribute <RpcOperationAttribute>();

                        var setOp = new RpcOperationInfo(
                            service: rpcPropertyInfo.Service,
                            name: $"Set{propertyInfo.Name}",
                            declaringMember: propertyInfo,
                            method: propertyInfo.SetMethod,
                            requestType: typeof(RpcObjectRequest <>).MakeGenericType(propertyInfo.PropertyType),
                            requestParameters: ImmutableArray.Create(
                                new RpcRequestParameter(propertyInfo.PropertyType, 0)),
                            callbackParameterIndex: null,
                            cancellationTokenIndex: null,
                            methodType: RpcMethodType.Unary,
                            isAsync: false,
                            responseType: typeof(RpcResponse),
                            returnType: typeof(void),
                            responseReturnType: typeof(void),
                            returnKind: ServiceOperationReturnKind.Standard,
                            allowInlineExecution: setRpcAttribute?.AllowInlineExecution ?? propertyRpcAttribute?.AllowInlineExecution ?? false,
                            metadata: GetPropertyMethodMetadata(serviceInfo, propertyInfo, propertyInfo.SetMethod)
                            );

                        yield return(setOp);
                    }

                    handledMembers.Add(propertyInfo.SetMethod);
                }

                if (!splitProperties)
                {
                    yield return(rpcPropertyInfo);
                }
            }

            foreach (var method in serviceInfo.Type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
            {
                if (handledMembers.Add(method))
                {
                    var opInfo = RpcBuilderUtil.GetOperationInfoFromMethod(serviceInfo, method);
                    //this.CheckMethod(opInfo);
                    switch (opInfo.MethodType)
                    {
                    case RpcMethodType.Unary:
                    case RpcMethodType.ServerStreaming:
                        yield return(opInfo);

                        break;
                    }
                }
            }
        }
コード例 #17
0
        protected void AddGenericCallbackMethod <TRequest, TReturn, TResponseReturn>(RpcStub <TService> serviceStub, RpcOperationInfo opInfo, TMethodBinder binder)
            where TRequest : class, IObjectRequest
            where TResponseReturn : class  // Needs to be class due to gRPC constraint
        {
            if (opInfo is null)
            {
                throw new ArgumentNullException(nameof(opInfo));
            }

            Func <TReturn, TResponseReturn>?responseCreator = GetResponseCreator <TReturn, TResponseReturn>(opInfo);
            RpcServerFaultHandler           faultHandler    = this.CreateFaultHandler(opInfo);

            if (opInfo.IsAsync)
            {
                var serviceCaller = GenerateCallbackMethodHandler <TRequest, TReturn>(opInfo);
                this.AddCallbackMethodCore(serviceCaller, responseCreator, faultHandler, serviceStub, opInfo, binder);
            }
            else
            {
                var serviceCaller = GenerateBlockingCallbackMethodHandler <TRequest, TReturn>(opInfo);
                this.AddCallbackMethodCore(serviceCaller, responseCreator, faultHandler, serviceStub, opInfo, binder);
            }
        }