2
2
using ProtoBuf . Grpc . Internal ;
3
3
using System ;
4
4
using System . Collections . Generic ;
5
+ using System . Linq ;
5
6
using System . Linq . Expressions ;
6
7
using System . Reflection ;
8
+ using System . Threading . Tasks ;
7
9
8
10
namespace ProtoBuf . Grpc . Configuration
9
11
{
@@ -40,16 +42,20 @@ public int Bind(object state, Type serviceType, BinderConfiguration? binderConfi
40
42
? new HashSet < Type > { serviceType }
41
43
: ContractOperation . ExpandInterfaces ( serviceType ) ;
42
44
45
+ bool serviceImplSimplifiedExceptions = serviceType . IsDefined ( typeof ( SimpleRpcExceptionsAttribute ) ) ;
43
46
foreach ( var serviceContract in serviceContracts )
44
47
{
45
48
if ( ! binderConfiguration . Binder . IsServiceContract ( serviceContract , out serviceName ) ) continue ;
46
49
50
+ var serviceContractSimplifiedExceptions = serviceImplSimplifiedExceptions || serviceContract . IsDefined ( typeof ( SimpleRpcExceptionsAttribute ) ) ;
47
51
int svcOpCount = 0 ;
48
52
var bindCtx = new ServiceBindContext ( serviceContract , serviceType , state ) ;
49
53
foreach ( var op in ContractOperation . FindOperations ( binderConfiguration , serviceContract , this ) )
50
54
{
51
55
if ( ServerInvokerLookup . TryGetValue ( op . MethodType , op . Context , op . Result , op . Void , out var invoker )
52
- && AddMethod ( op . From , op . To , op . Name , op . Method , op . MethodType , invoker , bindCtx ) )
56
+ && AddMethod ( op . From , op . To , op . Name , op . Method , op . MethodType , invoker , bindCtx ,
57
+ serviceContractSimplifiedExceptions || op . Method . IsDefined ( typeof ( SimpleRpcExceptionsAttribute ) )
58
+ ) )
53
59
{
54
60
// yay!
55
61
totalCount ++ ;
@@ -61,7 +67,7 @@ public int Bind(object state, Type serviceType, BinderConfiguration? binderConfi
61
67
return totalCount ;
62
68
63
69
bool AddMethod ( Type @in , Type @out , string on , MethodInfo m , MethodType t ,
64
- Func < MethodInfo , ParameterExpression [ ] , Expression > ? invoker , ServiceBindContext bindContext )
70
+ Func < MethodInfo , ParameterExpression [ ] , Expression > ? invoker , ServiceBindContext bindContext , bool simplifiedExceptionHandling )
65
71
{
66
72
try
67
73
{
@@ -72,16 +78,20 @@ bool AddMethod(Type @in, Type @out, string on, MethodInfo m, MethodType t,
72
78
typesBuffer [ 1 ] = @in ;
73
79
typesBuffer [ 2 ] = @out ;
74
80
75
- if ( argsBuffer == null )
81
+ if ( argsBuffer is null )
76
82
{
77
- argsBuffer = new object ? [ ] { null , null , null , null , null , null , binderConfiguration ! . MarshallerCache , service == null ? null : Expression . Constant ( service , serviceType ) } ;
83
+ argsBuffer = new object ? [ 9 ] ;
84
+ argsBuffer [ 6 ] = binderConfiguration ! . MarshallerCache ;
85
+ argsBuffer [ 7 ] = service is null ? null : Expression . Constant ( service , serviceType ) ;
78
86
}
79
87
argsBuffer [ 0 ] = serviceName ;
80
88
argsBuffer [ 1 ] = on ;
81
89
argsBuffer [ 2 ] = m ;
82
90
argsBuffer [ 3 ] = t ;
83
91
argsBuffer [ 4 ] = bindContext ;
84
92
argsBuffer [ 5 ] = invoker ;
93
+ // 6, 7 set during array initialization
94
+ argsBuffer [ 8 ] = simplifiedExceptionHandling ;
85
95
86
96
return ( bool ) s_addMethod . MakeGenericMethod ( typesBuffer ) . Invoke ( this , argsBuffer ) ! ;
87
97
}
@@ -116,14 +126,16 @@ protected readonly struct MethodStub<TService>
116
126
{
117
127
private readonly ConstantExpression ? _service ;
118
128
private readonly Func < MethodInfo , Expression [ ] , Expression > ? _invoker ;
129
+ private readonly bool _simpleExceptionHandling ;
119
130
120
131
/// <summary>
121
132
/// The runtime method being considered
122
133
/// </summary>
123
134
public MethodInfo Method { get ; }
124
135
125
- internal MethodStub ( Func < MethodInfo , Expression [ ] , Expression > ? invoker , MethodInfo method , ConstantExpression ? service )
136
+ internal MethodStub ( Func < MethodInfo , Expression [ ] , Expression > ? invoker , MethodInfo method , ConstantExpression ? service , bool simpleExceptionHandling )
126
137
{
138
+ _simpleExceptionHandling = simpleExceptionHandling ;
127
139
_invoker = invoker ;
128
140
_service = service ;
129
141
Method = method ;
@@ -137,43 +149,86 @@ public TDelegate CreateDelegate<TDelegate>()
137
149
{
138
150
if ( _invoker == null )
139
151
{
140
- // basic - direct call
141
- return ( TDelegate ) Delegate . CreateDelegate ( typeof ( TDelegate ) , _service , Method ) ;
142
- }
143
- var lambdaArgs = ParameterCache < TDelegate > . Parameters ;
152
+ if ( _simpleExceptionHandling )
153
+ {
154
+ var lambdaArgs = ParameterCache < TDelegate > . Parameters ;
155
+
156
+ var call = _service is null
157
+ ? Expression . Call ( Method , lambdaArgs )
158
+ : Expression . Call ( _service , Method , lambdaArgs ) ;
144
159
145
- Expression [ ] mapArgs ;
146
- if ( _service == null )
147
- { // if no service object, then the service is part of the signature, i.e. (svc, req) => svc.Blah();
148
- mapArgs = lambdaArgs ;
160
+ return Expression . Lambda < TDelegate > (
161
+ ApplySimpleExceptionHandling ( call ) , lambdaArgs ) . Compile ( ) ;
162
+ }
163
+ else
164
+ {
165
+ // basic - direct call
166
+ return ( TDelegate ) Delegate . CreateDelegate ( typeof ( TDelegate ) , _service , Method ) ;
167
+ }
149
168
}
150
169
else
151
170
{
152
- // if there *is* a service object, then that is *not* part of the signature, i.e. (req) => svc.Blah(req)
153
- // where the svc instance comes in separately
154
- mapArgs = new Expression [ lambdaArgs . Length + 1 ] ;
155
- mapArgs [ 0 ] = _service ;
156
- lambdaArgs . CopyTo ( mapArgs , 1 ) ;
157
- }
171
+ var lambdaArgs = ParameterCache < TDelegate > . Parameters ;
172
+
173
+ Expression [ ] mapArgs ;
174
+ if ( _service is null )
175
+ { // if no service object, then the service is part of the signature, i.e. (svc, req) => svc.Blah();
176
+ mapArgs = lambdaArgs ;
177
+ }
178
+ else
179
+ {
180
+ // if there *is* a service object, then that is *not* part of the signature, i.e. (req) => svc.Blah(req)
181
+ // where the svc instance comes in separately
182
+ mapArgs = new Expression [ lambdaArgs . Length + 1 ] ;
183
+ mapArgs [ 0 ] = _service ;
184
+ lambdaArgs . CopyTo ( mapArgs , 1 ) ;
185
+ }
158
186
159
- var body = _invoker . Invoke ( Method , mapArgs ) ;
160
- var lambda = Expression . Lambda < TDelegate > ( body , lambdaArgs ) ;
187
+ var body = _invoker . Invoke ( Method , mapArgs ) ;
188
+ if ( _simpleExceptionHandling )
189
+ {
190
+ body = ApplySimpleExceptionHandling ( body ) ;
191
+ }
192
+ var lambda = Expression . Lambda < TDelegate > ( body , lambdaArgs ) ;
161
193
162
- return lambda . Compile ( ) ;
194
+ return lambda . Compile ( ) ;
195
+ }
196
+ }
197
+
198
+ static Expression ApplySimpleExceptionHandling ( Expression body )
199
+ {
200
+ var type = body . Type ;
201
+ if ( type == typeof ( Task ) )
202
+ {
203
+ body = Expression . Call ( s_ReshapeWithSimpleExceptionHandling [ 0 ] , body ) ;
204
+ }
205
+ else if ( type . IsGenericType && type . GetGenericTypeDefinition ( ) == typeof ( Task < > ) )
206
+ {
207
+ body = Expression . Call ( s_ReshapeWithSimpleExceptionHandling [ 1 ] . MakeGenericMethod ( type . GetGenericArguments ( ) ) , body ) ;
208
+ }
209
+ return body ;
163
210
}
164
211
}
165
212
213
+ #pragma warning disable CS0618
214
+ private static readonly Dictionary < int , MethodInfo > s_ReshapeWithSimpleExceptionHandling =
215
+ ( from method in typeof ( Reshape ) . GetMethods ( BindingFlags . Public | BindingFlags . Static )
216
+ where method . Name is nameof ( Reshape . WithSimpleExceptionHandling )
217
+ select method )
218
+ . ToDictionary ( method => method . IsGenericMethodDefinition ? method . GetGenericArguments ( ) . Length : 0 ) ;
219
+ #pragma warning restore CS0618
220
+
166
221
private bool AddMethod < TService , TRequest , TResponse > (
167
222
string serviceName , string operationName , MethodInfo method , MethodType methodType ,
168
223
ServiceBindContext bindContext ,
169
224
Func < MethodInfo , Expression [ ] , Expression > ? invoker , MarshallerCache marshallerCache ,
170
- ConstantExpression ? service )
225
+ ConstantExpression ? service , bool simplfiedExceptionHandling )
171
226
where TService : class
172
227
where TRequest : class
173
228
where TResponse : class
174
229
{
175
230
var grpcMethod = new Method < TRequest , TResponse > ( methodType , serviceName , operationName , marshallerCache . GetMarshaller < TRequest > ( ) , marshallerCache . GetMarshaller < TResponse > ( ) ) ;
176
- var stub = new MethodStub < TService > ( invoker , method , service ) ;
231
+ var stub = new MethodStub < TService > ( invoker , method , service , simplfiedExceptionHandling ) ;
177
232
try
178
233
{
179
234
return TryBind < TService , TRequest , TResponse > ( bindContext , grpcMethod , stub ) ;
0 commit comments