-
Notifications
You must be signed in to change notification settings - Fork 16
/
GrpcMethodHelper.cs
158 lines (151 loc) · 7.62 KB
/
GrpcMethodHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
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.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(ServerServiceDefinition.Builder).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;
}
}
}
/// <summary>
/// 自动注册服务方法
/// </summary>
/// <param name="srv"></param>
/// <param name="builder"></param>
/// <param name="package"></param>
/// <param name="serviceName"></param>
public static void AutoRegisterMethod(IGrpcService srv, ServerServiceDefinition.Builder builder, string package = null, string serviceName = null)
{
var methods = srv.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
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), method.IsStatic ? null : srv);
addMethod.MakeGenericMethod(reallyInputType, reallyOutputType).Invoke(builder, new[] { buildMethodResult, serverMethodDelegate });
}
}
/// <summary>
/// 生成Grpc方法(CodeFirst方式)
/// </summary>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
/// <param name="srv"></param>
/// <param name="methodName"></param>
/// <param name="package"></param>
/// <param name="srvName"></param>
/// <param name="mType"></param>
/// <returns></returns>
public static Method<TRequest, TResponse> BuildMethod<TRequest, TResponse>(this IGrpcService srv,
string methodName, string package = null, string srvName = null, MethodType mType = MethodType.Unary)
{
var serviceName = srvName ??
GrpcExtensionsOptions.Instance.GlobalService ??
srv.GetType().Name;
var pkg = package ?? GrpcExtensionsOptions.Instance.GlobalPackage;
if (!string.IsNullOrWhiteSpace(pkg))
{
serviceName = $"{pkg}.{serviceName}";
}
#region 为生成proto收集信息
if (!(srv is IGrpcBaseService) || GrpcExtensionsOptions.Instance.GenBaseServiceProtoEnable)
{
ProtoInfo.Methods.Add(new ProtoMethodInfo
{
ServiceName = serviceName,
MethodName = methodName,
RequestName = typeof(TRequest).Name,
ResponseName = typeof(TResponse).Name,
MethodType = mType
});
ProtoGenerator.AddProto<TRequest>(typeof(TRequest).Name);
ProtoGenerator.AddProto<TResponse>(typeof(TResponse).Name);
}
#endregion
var request = Marshallers.Create<TRequest>((arg) => ProtobufExtensions.Serialize<TRequest>(arg), data => ProtobufExtensions.Deserialize<TRequest>(data));
var response = Marshallers.Create<TResponse>((arg) => ProtobufExtensions.Serialize<TResponse>(arg), data => ProtobufExtensions.Deserialize<TResponse>(data));
return new Method<TRequest, TResponse>(mType, serviceName, methodName, request, response);
}
}
}