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) )); }
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); }
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)