private static MethodInfo?GetImplementationMethod(RpcServiceInfo serviceInfo, MethodInfo?method)
        {
            MethodInfo?implMethod = null;

            Type?implementationType = serviceInfo.ImplementationType;

            if (implementationType != null)
            {
                var iMap             = implementationType.GetInterfaceMap(serviceInfo.Type);
                var interfaceMethods = iMap.InterfaceMethods;
                var targetMethods    = iMap.TargetMethods;
                Debug.Assert(interfaceMethods.Length == targetMethods.Length);

                for (int i = 0; i < interfaceMethods.Length; i++)
                {
                    if (Equals(interfaceMethods[i], method))
                    {
                        implMethod = targetMethods[i];
                        break;
                    }
                }
            }

            return(implMethod);
        }
        private static ImmutableArray <object> GetPropertyMetadata(RpcServiceInfo serviceInfo, PropertyInfo property)
        {
            var metadataBuilder = ImmutableArray.CreateBuilder <object>();

            metadataBuilder.AddRange(serviceInfo.Metadata);

            metadataBuilder.AddRange(property.GetCustomAttributes());

            Type?implementationType = serviceInfo.ImplementationType;

            if (implementationType != null)
            {
                var implMethod =
                    GetImplementationMethod(serviceInfo, property.GetMethod)
                    ?? GetImplementationMethod(serviceInfo, property.SetMethod);

                if (implMethod != null)
                {
                    var implProperty = implementationType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                       .FirstOrDefault(p => Equals(p.GetMethod, implMethod) || Equals(p.SetMethod, implMethod));

                    if (implProperty != null)
                    {
                        metadataBuilder.AddRange(implProperty.GetCustomAttributes());
                    }
                }
            }

            var metadata = metadataBuilder.ToImmutableArray();

            return(metadata);
        }
        private static ImmutableArray <object> GetEventMetadata(RpcServiceInfo serviceInfo, EventInfo eventInfo)
        {
            var metadataBuilder = ImmutableArray.CreateBuilder <object>();

            metadataBuilder.AddRange(serviceInfo.Metadata);

            metadataBuilder.AddRange(eventInfo.GetCustomAttributes());

            var implMethod = GetImplementationMethod(serviceInfo, eventInfo.AddMethod);

            if (implMethod != null)
            {
                var implProperty = serviceInfo.ImplementationType !.GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                   .FirstOrDefault(p => Equals(p.AddMethod, implMethod));

                if (implProperty != null)
                {
                    metadataBuilder.AddRange(implProperty.GetCustomAttributes());
                }
            }

            var metadata = metadataBuilder.ToImmutableArray();

            return(metadata);
        }
 internal RpcPropertyInfo(
     RpcServiceInfo service,
     PropertyInfo propertyInfo,
     ServiceOperationReturnKind propertyTypeKind,
     Type responseReturnType,
     ImmutableArray <object> metadata)
     : base(propertyInfo?.Name !, service, propertyInfo !, metadata)
        public static RpcEventInfo GetEventInfoFromEvent(RpcServiceInfo serviceInfo, EventInfo eventInfo)
        {
            var  eventHandlerType = eventInfo.EventHandlerType ?? throw new NotSupportedException($"{eventInfo.Name} has no EventHandlerType");;
            Type eventArgsType;

            if (eventHandlerType.IsGenericType)
            {
                var eventHandlerGenericType = eventHandlerType.GetGenericTypeDefinition();
                if (eventHandlerGenericType != typeof(EventHandler <>))
                {
                    throw new RpcDefinitionException("Event handler must be EventHandler, or EventHandler<>.");
                }

                eventArgsType = eventHandlerType.GetGenericArguments()[0];
            }
            else
            {
                if (eventHandlerType != typeof(EventHandler))
                {
                    throw new RpcDefinitionException("Event handler must be EventHandler, or EventHandler<>.");
                }
                eventArgsType = typeof(EventArgs);
            }

            return(new RpcEventInfo
                   (
                       service: serviceInfo,
                       eventInfo: eventInfo,
                       eventArgsType: eventArgsType,
                       metadata: GetEventMetadata(serviceInfo, eventInfo)
                   ));
        }
 internal RpcOperationInfo(string name,
                           RpcServiceInfo service,
                           MemberInfo declaringMember,
                           MethodInfo method,
                           RpcMethodType methodType,
                           bool isAsync,
                           ImmutableArray <RpcRequestParameter> requestParameters,
                           int?callbackParameterIndex,
                           int?cancellationTokenIndex,
                           Type returnType,
                           Type responseReturnType,
                           Type requestType,
                           Type responseType,
                           ServiceOperationReturnKind returnKind,
                           bool allowInlineExecution,
                           ImmutableArray <object> metadata) :
     base(name, service, declaringMember, metadata)
 {
     this.Method                 = method ?? throw new ArgumentNullException(nameof(method));
     this.MethodType             = methodType;
     this.IsAsync                = isAsync;
     this.RequestParameters      = !requestParameters.IsDefault ? requestParameters : throw new ArgumentNullException(nameof(requestParameters));
     this.CallbackParameterIndex = callbackParameterIndex;
     this.CancellationTokenIndex = cancellationTokenIndex;
     this.ReturnType             = returnType ?? throw new ArgumentNullException(nameof(returnType));
     this.ResponseReturnType     = responseReturnType ?? throw new ArgumentNullException(nameof(responseReturnType));
     this.RequestType            = requestType ?? throw new ArgumentNullException(nameof(requestType));
     this.ResponseType           = responseType ?? throw new ArgumentNullException(nameof(responseType));
     this.ReturnKind             = returnKind;
     this.AllowInlineExecution   = allowInlineExecution;
 }
 public RpcMemberInfo(string name, RpcServiceInfo service, MemberInfo declaringMember, ImmutableArray <object> metadata)
 {
     this.Name            = name ?? throw new ArgumentNullException(nameof(name));
     this.Service         = service ?? throw new ArgumentNullException(nameof(service));
     this.DeclaringMember = declaringMember ?? throw new ArgumentNullException(nameof(declaringMember));
     this.Metadata        = metadata.IsDefault ? ImmutableArray <object> .Empty : metadata;
 }
        public static RpcPropertyInfo GetPropertyInfoFromProperty(RpcServiceInfo serviceInfo, PropertyInfo propertyInfo)
        {
            var propertyType = propertyInfo.PropertyType;

            var(returnKind, responseReturnType) = GetOperationReturnKind(propertyType);

            return(new RpcPropertyInfo
                   (
                       service: serviceInfo,
                       propertyInfo: propertyInfo,
                       propertyTypeKind: returnKind,
                       responseReturnType: responseReturnType,
                       metadata: GetPropertyMetadata(serviceInfo, propertyInfo)
                   ));
        }
Esempio n. 9
0
        protected RpcServiceStubBuilder(RpcServiceInfo serviceInfo, RpcServiceOptions <TService>?options)
        {
            this.ServiceInfo = serviceInfo ?? throw new ArgumentNullException(nameof(serviceInfo));

            this.Options = options;

            var converterAttributes = serviceInfo.Type.GetCustomAttributes <RpcFaultConverterAttribute>();
            var exceptionConverters = RetrieveServerExceptionConverters(converterAttributes);

            var faultAttributes = serviceInfo.Type.GetCustomAttributes <RpcFaultAttribute>();
            var mappings        = GetFaultToDetailsMapping(faultAttributes);

            if (exceptionConverters.Count > 0 || mappings.Count > 0)
            {
                this.FaultHandler = new RpcServerFaultHandler(null, exceptionConverters, mappings);
            }
            else
            {
                this.FaultHandler = RpcServerFaultHandler.Default;
            }
        }
        private static ImmutableArray <object> GetPropertyMethodMetadata(RpcServiceInfo serviceInfo, PropertyInfo property, MethodInfo method)
        {
            var metadataBuilder = ImmutableArray.CreateBuilder <object>();

            metadataBuilder.AddRange(serviceInfo.Metadata);

            metadataBuilder.AddRange(property.GetCustomAttributes());

            Type?implementationType = serviceInfo.ImplementationType;

            if (implementationType != null)
            {
                var implMethod = implementationType.GetInterfaceMap(serviceInfo.Type).InterfaceMethods
                                 .FirstOrDefault(m => Equals(m, method));

                if (implMethod != null)
                {
                    var implProperty = implementationType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                       .FirstOrDefault(p => Equals(p.GetMethod, implMethod) || Equals(p.SetMethod, implMethod));

                    if (implProperty != null)
                    {
                        metadataBuilder.AddRange(implProperty.GetCustomAttributes());
                    }

                    metadataBuilder.AddRange(implMethod.GetCustomAttributes(inherit: true));
                }
            }
            else
            {
                // Assuming that inherit will find attributes on interface method.
                // TODO: Must check!
                metadataBuilder.AddRange(method.GetCustomAttributes(inherit: true));
            }

            var metadata = metadataBuilder.ToImmutableArray();

            return(metadata);
        }
        private static ImmutableArray <object> GetMethodMetadata(RpcServiceInfo serviceInfo, MethodInfo method)
        {
            var metadataBuilder = ImmutableArray.CreateBuilder <object>();

            metadataBuilder.AddRange(serviceInfo.Metadata);

            Type?      implementationType = serviceInfo.ImplementationType;
            MethodInfo?implMethod         = GetImplementationMethod(serviceInfo, method);

            if (implMethod != null)
            {
                metadataBuilder.AddRange(implMethod.GetCustomAttributes(inherit: true));
            }
            else
            {
                metadataBuilder.AddRange(method.GetCustomAttributes(inherit: true));
            }

            var metadata = metadataBuilder.ToImmutableArray();

            return(metadata);
        }
Esempio n. 12
0
 public GrpcServiceStubBuilder(RpcServiceInfo serviceInfo, RpcServiceOptions <TService>?options) : base(serviceInfo, options)
 {
 }
        public static RpcOperationInfo GetOperationInfoFromMethod(RpcServiceInfo serviceInfo, MethodInfo method)
        {
            var parameters = method.GetParameters();

            var requestTypeInfo = GetRequestType(parameters, serviceInfo.IsSingleton);

            Type          actualReturnType = method.ReturnType;
            bool          isAsync          = false;
            RpcMethodType methodType       = RpcMethodType.Unary;

            if (method.ReturnType.IsGenericType)
            {
                var genericTypeDef = method.ReturnType.GetGenericTypeDefinition();
                if (genericTypeDef.Equals(typeof(IAsyncEnumerable <>)))// || genericTypeDef.Equals(typeof(IAsyncEnumerator<>)))
                {
                    if (requestTypeInfo.CallbackParameterIndex != null)
                    {
                        throw new RpcDefinitionException($"A streaming server method '{method.Name}' cannot have a callback parameter.");
                    }
                    actualReturnType = method.ReturnType.GenericTypeArguments[0];
                    methodType       = RpcMethodType.ServerStreaming;
                    isAsync          = true;
                }
                else if (genericTypeDef.Equals(typeof(Task <>)) || genericTypeDef.Equals(typeof(ValueTask <>)))
                {
                    actualReturnType = method.ReturnType.GenericTypeArguments[0];
                    isAsync          = true;
                }
            }
            else if (method.ReturnType == typeof(Task))
            {
                actualReturnType = typeof(void);
                isAsync          = true;
            }
            else
            {
                actualReturnType = method.ReturnType;
            }

            if (requestTypeInfo.CallbackParameterIndex != null)
            {
                if (!typeof(void).Equals(actualReturnType))
                {
                    throw new RpcDefinitionException($"Method '{method.Name}' has a callback parameter and must return void.");
                }

                actualReturnType = requestTypeInfo.CallbackRequestType ?? throw new InvalidOperationException("CallbackRequestType must be initialized when CallbackParameterIndex is not null");
                methodType       = RpcMethodType.ServerStreaming;
            }

            string?operationName = null;

            var rpcAttribute = method.GetCustomAttribute <RpcOperationAttribute>();

            if (rpcAttribute != null)
            {
                operationName = rpcAttribute.Name;
            }

            if (string.IsNullOrEmpty(operationName))
            {
                operationName = method.Name;
                if (isAsync && operationName.EndsWith("Async", StringComparison.Ordinal))
                {
                    operationName = operationName.Substring(0, operationName.Length - "Async".Length);
                }
            }

            var(returnKind, responseReturnType) = GetOperationReturnKind(actualReturnType);
            Type responseType = GetResponseType(methodType, responseReturnType);

            ImmutableArray <object> metadata = GetMethodMetadata(serviceInfo, method);

            return(new RpcOperationInfo
                   (
                       service: serviceInfo,
                       method: method,
                       declaringMember: method,
                       methodType: methodType,
                       isAsync: isAsync,
                       name: operationName !,
                       requestParameters: requestTypeInfo.Parameters,
                       callbackParameterIndex: requestTypeInfo.CallbackParameterIndex,
                       cancellationTokenIndex: requestTypeInfo.CancellationTokenIndex,
                       requestType: requestTypeInfo.Type,
                       returnType: actualReturnType,
                       responseType: responseType,
                       responseReturnType: responseReturnType,
                       returnKind: returnKind,
                       allowInlineExecution: rpcAttribute?.AllowInlineExecution ?? false,
                       metadata: metadata
                   ));
        }
        /// <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;
                    }
                }
            }
        }
 public RpcEventInfo(RpcServiceInfo service, EventInfo eventInfo, Type eventArgsType, ImmutableArray <object> metadata)
     : base(eventInfo?.Name !, service, eventInfo !, metadata)