using System; using System.Linq; using System.Reflection; using Grpc.Core; using Grpc.Extension.Abstract; using Grpc.Extension.BaseService; using Grpc.Extension.BaseService.Model; using Grpc.Extension.Common; using Grpc.Extension.Common.Internal; namespace Grpc.Extension.AspNetCore.Internal { // ReSharper disable once IdentifierTypo internal static class GrpcMethodHelper { // ReSharper disable once InconsistentNaming private static readonly MethodInfo buildMethod; // ReSharper disable once InconsistentNaming private static readonly MethodInfo unaryAddMethod; private static readonly MethodInfo clientStreamingAddMethod; private static readonly MethodInfo serverStreamingAddMethod; private static readonly MethodInfo duplexStreamingAddMethod; // ReSharper disable once IdentifierTypo static GrpcMethodHelper() { buildMethod = typeof(GrpcMethodHelper).GetMethod("BuildMethod"); var methods = typeof(ServiceBinderBase).GetMethods().Where(p => p.Name == "AddMethod"); foreach (var method in methods) { var parameters = method.GetParameters(); if (parameters.Length != 2) continue; if (parameters[1].ParameterType.Name.Contains("UnaryServerMethod")) { unaryAddMethod = method; } else if (parameters[1].ParameterType.Name.Contains("ClientStreamingServerMethod")) { clientStreamingAddMethod = method; } else if (parameters[1].ParameterType.Name.Contains("ServerStreamingServerMethod")) { serverStreamingAddMethod = method; } else if (parameters[1].ParameterType.Name.Contains("DuplexStreamingServerMethod")) { duplexStreamingAddMethod = method; } } } /// /// 自动注册服务方法 /// /// /// /// /// public static void AutoRegisterMethod(Type srv, ServiceBinderBase serviceBinder, string package = null, string serviceName = null) { var methods = srv.GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (var method in methods) { if (!method.ReturnType.Name.StartsWith("Task")) continue; var parameters = method.GetParameters(); if (parameters[parameters.Length-1].ParameterType != typeof(ServerCallContext) || method.CustomAttributes.Any(x => x.AttributeType == typeof(NotGrpcMethodAttribute))) continue; Type inputType = parameters[0].ParameterType; Type inputType2 = parameters[1].ParameterType; Type outputType = method.ReturnType.IsGenericType ? method.ReturnType.GenericTypeArguments[0] : method.ReturnType; var addMethod = unaryAddMethod; var serverMethodType = typeof(UnaryServerMethod<,>); var methodType = MethodType.Unary; var reallyInputType = inputType; var reallyOutputType = outputType; //非一元方法 if ((inputType.IsGenericType || inputType2.IsGenericType)) { if (inputType.Name == "IAsyncStreamReader`1") { reallyInputType = inputType.GenericTypeArguments[0]; if (inputType2.Name == "IServerStreamWriter`1")//双向流 { addMethod = duplexStreamingAddMethod; methodType = MethodType.DuplexStreaming; serverMethodType = typeof(DuplexStreamingServerMethod<,>); reallyOutputType = inputType2.GenericTypeArguments[0]; } else//客户端流 { addMethod = clientStreamingAddMethod; methodType = MethodType.ClientStreaming; serverMethodType = typeof(ClientStreamingServerMethod<,>); } } else if (inputType2.Name == "IServerStreamWriter`1")//服务端流 { addMethod = serverStreamingAddMethod; methodType = MethodType.ServerStreaming; serverMethodType = typeof(ServerStreamingServerMethod<,>); reallyOutputType = inputType2.GenericTypeArguments[0]; } } var buildMethodResult = buildMethod.MakeGenericMethod(reallyInputType, reallyOutputType) .Invoke(null, new object[] { srv, method.Name, package, serviceName, methodType }); Delegate serverMethodDelegate = method.CreateDelegate(serverMethodType .MakeGenericType(reallyInputType, reallyOutputType), null); addMethod.MakeGenericMethod(reallyInputType, reallyOutputType).Invoke(serviceBinder, new[] { buildMethodResult, serverMethodDelegate }); } } /// /// 生成Grpc方法(CodeFirst方式) /// /// /// /// /// /// /// /// /// public static Method BuildMethod(this Type srv, string methodName, string package = null, string srvName = null, MethodType mType = MethodType.Unary) { var serviceName = srvName ?? GrpcExtensionsOptions.Instance.GlobalService ?? srv.Name; var pkg = package ?? GrpcExtensionsOptions.Instance.GlobalPackage; if (!string.IsNullOrWhiteSpace(pkg)) { serviceName = $"{pkg}.{serviceName}"; } #region 为生成proto收集信息 if (!(typeof(IGrpcBaseService).IsAssignableFrom(srv)) || GrpcExtensionsOptions.Instance.GenBaseServiceProtoEnable) { ProtoInfo.Methods.Add(new ProtoMethodInfo { ServiceName = serviceName, MethodName = methodName, RequestName = typeof(TRequest).Name, ResponseName = typeof(TResponse).Name, MethodType = mType }); ProtoGenerator.AddProto(typeof(TRequest).Name); ProtoGenerator.AddProto(typeof(TResponse).Name); } #endregion var request = Marshallers.Create((arg) => ProtobufExtensions.Serialize(arg), data => ProtobufExtensions.Deserialize(data)); var response = Marshallers.Create((arg) => ProtobufExtensions.Serialize(arg), data => ProtobufExtensions.Deserialize(data)); return new Method(mType, serviceName, methodName, request, response); } /// /// 绑定GrpcService的方法 /// /// /// public static void BindService(ServiceBinderBase serviceBinder, Type service) { if (typeof(IGrpcBaseService).IsAssignableFrom(service)) { AutoRegisterMethod(service, serviceBinder, ServerConsts.BaseServicePackage, ServerConsts.BaseServiceName); } else { AutoRegisterMethod(service, serviceBinder); } } } }