GrpcMethodHelper.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. using System;
  2. using System.Linq;
  3. using System.Reflection;
  4. using Grpc.Core;
  5. using Grpc.Extension.Abstract;
  6. using Grpc.Extension.BaseService;
  7. using Grpc.Extension.BaseService.Model;
  8. using Grpc.Extension.Common;
  9. using Grpc.Extension.Common.Internal;
  10. namespace Grpc.Extension.AspNetCore.Internal
  11. {
  12. // ReSharper disable once IdentifierTypo
  13. internal static class GrpcMethodHelper
  14. {
  15. // ReSharper disable once InconsistentNaming
  16. private static readonly MethodInfo buildMethod;
  17. // ReSharper disable once InconsistentNaming
  18. private static readonly MethodInfo unaryAddMethod;
  19. private static readonly MethodInfo clientStreamingAddMethod;
  20. private static readonly MethodInfo serverStreamingAddMethod;
  21. private static readonly MethodInfo duplexStreamingAddMethod;
  22. // ReSharper disable once IdentifierTypo
  23. static GrpcMethodHelper()
  24. {
  25. buildMethod = typeof(GrpcMethodHelper).GetMethod("BuildMethod");
  26. var methods = typeof(ServiceBinderBase).GetMethods().Where(p => p.Name == "AddMethod");
  27. foreach (var method in methods)
  28. {
  29. var parameters = method.GetParameters();
  30. if (parameters.Length != 2) continue;
  31. if (parameters[1].ParameterType.Name.Contains("UnaryServerMethod"))
  32. {
  33. unaryAddMethod = method;
  34. }
  35. else if (parameters[1].ParameterType.Name.Contains("ClientStreamingServerMethod"))
  36. {
  37. clientStreamingAddMethod = method;
  38. }
  39. else if (parameters[1].ParameterType.Name.Contains("ServerStreamingServerMethod"))
  40. {
  41. serverStreamingAddMethod = method;
  42. }
  43. else if (parameters[1].ParameterType.Name.Contains("DuplexStreamingServerMethod"))
  44. {
  45. duplexStreamingAddMethod = method;
  46. }
  47. }
  48. }
  49. /// <summary>
  50. /// 自动注册服务方法
  51. /// </summary>
  52. /// <param name="srv"></param>
  53. /// <param name="serviceBinder"></param>
  54. /// <param name="package"></param>
  55. /// <param name="serviceName"></param>
  56. public static void AutoRegisterMethod(Type srv, ServiceBinderBase serviceBinder, string package = null, string serviceName = null)
  57. {
  58. var methods = srv.GetMethods(BindingFlags.Public | BindingFlags.Instance);
  59. foreach (var method in methods)
  60. {
  61. if (!method.ReturnType.Name.StartsWith("Task")) continue;
  62. var parameters = method.GetParameters();
  63. if (parameters[parameters.Length-1].ParameterType != typeof(ServerCallContext) ||
  64. method.CustomAttributes.Any(x => x.AttributeType == typeof(NotGrpcMethodAttribute))) continue;
  65. Type inputType = parameters[0].ParameterType;
  66. Type inputType2 = parameters[1].ParameterType;
  67. Type outputType = method.ReturnType.IsGenericType ? method.ReturnType.GenericTypeArguments[0] : method.ReturnType;
  68. var addMethod = unaryAddMethod;
  69. var serverMethodType = typeof(UnaryServerMethod<,>);
  70. var methodType = MethodType.Unary;
  71. var reallyInputType = inputType;
  72. var reallyOutputType = outputType;
  73. //非一元方法
  74. if ((inputType.IsGenericType || inputType2.IsGenericType))
  75. {
  76. if (inputType.Name == "IAsyncStreamReader`1")
  77. {
  78. reallyInputType = inputType.GenericTypeArguments[0];
  79. if (inputType2.Name == "IServerStreamWriter`1")//双向流
  80. {
  81. addMethod = duplexStreamingAddMethod;
  82. methodType = MethodType.DuplexStreaming;
  83. serverMethodType = typeof(DuplexStreamingServerMethod<,>);
  84. reallyOutputType = inputType2.GenericTypeArguments[0];
  85. }
  86. else//客户端流
  87. {
  88. addMethod = clientStreamingAddMethod;
  89. methodType = MethodType.ClientStreaming;
  90. serverMethodType = typeof(ClientStreamingServerMethod<,>);
  91. }
  92. }
  93. else if (inputType2.Name == "IServerStreamWriter`1")//服务端流
  94. {
  95. addMethod = serverStreamingAddMethod;
  96. methodType = MethodType.ServerStreaming;
  97. serverMethodType = typeof(ServerStreamingServerMethod<,>);
  98. reallyOutputType = inputType2.GenericTypeArguments[0];
  99. }
  100. }
  101. var buildMethodResult = buildMethod.MakeGenericMethod(reallyInputType, reallyOutputType)
  102. .Invoke(null, new object[] { srv, method.Name, package, serviceName, methodType });
  103. Delegate serverMethodDelegate = method.CreateDelegate(serverMethodType
  104. .MakeGenericType(reallyInputType, reallyOutputType), null);
  105. addMethod.MakeGenericMethod(reallyInputType, reallyOutputType).Invoke(serviceBinder, new[] { buildMethodResult, serverMethodDelegate });
  106. }
  107. }
  108. /// <summary>
  109. /// 生成Grpc方法(CodeFirst方式)
  110. /// </summary>
  111. /// <typeparam name="TRequest"></typeparam>
  112. /// <typeparam name="TResponse"></typeparam>
  113. /// <param name="srv"></param>
  114. /// <param name="methodName"></param>
  115. /// <param name="package"></param>
  116. /// <param name="srvName"></param>
  117. /// <param name="mType"></param>
  118. /// <returns></returns>
  119. public static Method<TRequest, TResponse> BuildMethod<TRequest, TResponse>(this Type srv,
  120. string methodName, string package = null, string srvName = null, MethodType mType = MethodType.Unary)
  121. {
  122. var serviceName = srvName ??
  123. GrpcExtensionsOptions.Instance.GlobalService ??
  124. srv.Name;
  125. var pkg = package ?? GrpcExtensionsOptions.Instance.GlobalPackage;
  126. if (!string.IsNullOrWhiteSpace(pkg))
  127. {
  128. serviceName = $"{pkg}.{serviceName}";
  129. }
  130. #region 为生成proto收集信息
  131. if (!(typeof(IGrpcBaseService).IsAssignableFrom(srv)) || GrpcExtensionsOptions.Instance.GenBaseServiceProtoEnable)
  132. {
  133. ProtoInfo.Methods.Add(new ProtoMethodInfo
  134. {
  135. ServiceName = serviceName,
  136. MethodName = methodName,
  137. RequestName = typeof(TRequest).Name,
  138. ResponseName = typeof(TResponse).Name,
  139. MethodType = mType
  140. });
  141. ProtoGenerator.AddProto<TRequest>(typeof(TRequest).Name);
  142. ProtoGenerator.AddProto<TResponse>(typeof(TResponse).Name);
  143. }
  144. #endregion
  145. var request = Marshallers.Create<TRequest>((arg) => ProtobufExtensions.Serialize<TRequest>(arg), data => ProtobufExtensions.Deserialize<TRequest>(data));
  146. var response = Marshallers.Create<TResponse>((arg) => ProtobufExtensions.Serialize<TResponse>(arg), data => ProtobufExtensions.Deserialize<TResponse>(data));
  147. return new Method<TRequest, TResponse>(mType, serviceName, methodName, request, response);
  148. }
  149. /// <summary>
  150. /// 绑定GrpcService的方法
  151. /// </summary>
  152. /// <param name="serviceBinder"></param>
  153. /// <param name="service"></param>
  154. public static void BindService(ServiceBinderBase serviceBinder, Type service)
  155. {
  156. if (typeof(IGrpcBaseService).IsAssignableFrom(service))
  157. {
  158. AutoRegisterMethod(service, serviceBinder, ServerConsts.BaseServicePackage, ServerConsts.BaseServiceName);
  159. }
  160. else
  161. {
  162. AutoRegisterMethod(service, serviceBinder);
  163. }
  164. }
  165. }
  166. }