/// <summary> /// DuplexStreaming メソッドを生成します。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="builderContext">コンテキスト</param> /// <returns>メソッド</returns> private DuplexStreamingServerMethod <TRequest, TResponse> CreateDuplexStreamingServerMethod <TRequest, TResponse>(MethodBuildContext builderContext) where TRequest : class where TResponse : class { DuplexStreamingServerMethod <TRequest, TResponse> method = builderContext.MethodImpl.CreateDelegate(typeof(DuplexStreamingServerMethod <TRequest, TResponse>), builderContext.ServiceInstance) as DuplexStreamingServerMethod <TRequest, TResponse>; GrpcServerPerformanceListener performanceListener = builderContext.NeedNotifyPerformanceLog ? builderContext.Settings.PerformanceListener : null; return(async delegate(IAsyncStreamReader <TRequest> requestStream, IServerStreamWriter <TResponse> responseStream, ServerCallContext context) { try { await OnExecutingServiceMethodAsync(context, builderContext.InvokingInterceptors, performanceListener).ConfigureAwait(false); if (performanceListener != null) { performanceListener.NotifyMethodCalling(context); } Stopwatch watch = Stopwatch.StartNew(); double elapsd; try { await method( new RequestStreamReader <TRequest>(requestStream, context, performanceListener) , new ResponseStreamWriter <TResponse>(responseStream, context, performanceListener) , context ).ConfigureAwait(false); } catch (Exception ex) { throw new GrpcServerMethodException(string.Format(Properties.MessageResources.ServerMethodFailed, context.Method) + ex.Message, ex, context); } finally { elapsd = GrpcPerformanceListener.GetMilliseconds(watch); if (performanceListener != null) { performanceListener.NotifyMethodCalled(context, elapsd); } } await OnExecutedServiceMethodAsync(context, builderContext.InvokedInterceptors, performanceListener).ConfigureAwait(false); } catch (Exception ex) { Exception wrapped; if (HandleException(context, builderContext.ExceptionHandlers, performanceListener, ex, out wrapped)) { GrpcExceptionListener.NotifyCatchServerException(context, wrapped); throw wrapped; } else { GrpcExceptionListener.NotifyCatchServerException(context, ex); throw; } } }); }
/// <summary> /// Unary メソッドを非同期で呼び出します。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="method">メソッド</param> /// <param name="host">ホスト</param> /// <param name="options">オプション</param> /// <param name="request">リクエスト</param> /// <returns>呼び出しオブジェクト</returns> public override AsyncUnaryCall <TResponse> AsyncUnaryCall <TRequest, TResponse>(Method <TRequest, TResponse> method, string host, CallOptions options, TRequest request) { double elapsed = 0; try { method = GetCustomMethod <TRequest, TResponse>(method); OnInvokingMethod(method, host, options, request); Stopwatch watch = null; AsyncUnaryCall <TResponse> call; try { watch = Stopwatch.StartNew(); call = m_Invoker.AsyncUnaryCall(method, host, options, request); } finally { elapsed = GrpcPerformanceListener.GetMilliseconds(watch); } OnInvokedMethod(method, host, options, request, elapsed); // 待機されると dispose が呼ばれず、解放されずに残ってしまう // ストリーム操作もないため、監視しない // return GrcpCallInvokerContext.Regist<TRequest, TResponse>(call, method, host, options); return(call); } catch (Exception ex) { GrpcExceptionListener.NotifyCatchClientException(method, host, options, ex); Exception alternate; if (HandleException(method, host, options, ex, out alternate)) { throw alternate; } else { throw; } } }
/// <summary> /// /// </summary> /// <returns></returns> async Task IClientStreamWriter <TRequest> .CompleteAsync() { Stopwatch watch = Stopwatch.StartNew(); try { await m_Target.CompleteAsync().ConfigureAwait(false); } finally { GrpcPerformanceListener.GetMilliseconds(watch); } if (m_OnCompleted != null) { m_OnCompleted(); } }
/// <summary> /// Unary メソッドを呼び出します。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="method">メソッド</param> /// <param name="host">ホスト</param> /// <param name="options">オプション</param> /// <param name="request">リクエスト</param> /// <returns>レスポンス</returns> public override TResponse BlockingUnaryCall <TRequest, TResponse>(Method <TRequest, TResponse> method, string host, CallOptions options, TRequest request) { double elapsed = 0; try { method = GetCustomMethod <TRequest, TResponse>(method); OnInvokingMethod(method, host, options, request); Stopwatch watch = null; TResponse result; try { watch = Stopwatch.StartNew(); result = m_Invoker.BlockingUnaryCall(method, host, options, request); } finally { elapsed = GrpcPerformanceListener.GetMilliseconds(watch); } OnInvokedMethod(method, host, options, request, elapsed); return(result); } catch (Exception ex) { GrpcExceptionListener.NotifyCatchClientException(method, host, options, ex); Exception alternate; if (HandleException(method, host, options, ex, out alternate)) { throw alternate; } else { throw; } } }
/// <summary> /// ServerStreaming メソッドを非同期で呼び出します。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="method">メソッド</param> /// <param name="host">ホスト</param> /// <param name="options">オプション</param> /// <param name="request">リクエスト</param> /// <returns>呼び出しオブジェクト</returns> public override AsyncServerStreamingCall <TResponse> AsyncServerStreamingCall <TRequest, TResponse>(Method <TRequest, TResponse> method, string host, CallOptions options, TRequest request) { double elapsed = 0; try { method = GetCustomMethod <TRequest, TResponse>(method); OnInvokingMethod(method, host, options, request); Stopwatch watch = null; AsyncServerStreamingCall <TResponse> call; try { watch = Stopwatch.StartNew(); call = m_Invoker.AsyncServerStreamingCall(method, host, options, request); } finally { elapsed = GrpcPerformanceListener.GetMilliseconds(watch); } OnInvokedMethod(method, host, options, request, elapsed); return(GrpcCallInvokerContext.Regist <TRequest, TResponse>(call, method, host, options, m_Settings.PerformanceListener)); } catch (Exception ex) { GrpcExceptionListener.NotifyCatchClientException(method, host, options, ex); Exception alternate; if (HandleException(method, host, options, ex, out alternate)) { throw alternate; } else { throw; } } }
/// <summary> /// /// </summary> /// <param name="message"></param> /// <returns></returns> Task IAsyncStreamWriter <TResponse> .WriteAsync(TResponse message) { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyResponseWriting(m_Context); } Stopwatch watch = Stopwatch.StartNew(); try { return(m_Target.WriteAsync(message)); } finally { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyResponseWrote(m_Context, GrpcPerformanceListener.GetMilliseconds(watch)); } } }
/// <summary> /// /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> Task <bool> IAsyncEnumerator <TRequest> .MoveNext(CancellationToken cancellationToken) { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyRequestReading(m_Context); } Stopwatch watch = Stopwatch.StartNew(); try { return(m_Target.MoveNext(cancellationToken)); } finally { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyRequestReaded(m_Context, GrpcPerformanceListener.GetMilliseconds(watch)); } } }
/// <summary> /// /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> async Task <bool> IAsyncEnumerator <TResponse> .MoveNext(CancellationToken cancellationToken) { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyResponseReading(m_Method, m_Host, m_Options); } Stopwatch watch = Stopwatch.StartNew(); bool result; try { result = await m_Target.MoveNext(cancellationToken).ConfigureAwait(false); } finally { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyResponseReaded(m_Method, m_Host, m_Options, GrpcPerformanceListener.GetMilliseconds(watch)); } } if (!result && m_OnEndResponse != null) { m_OnEndResponse(); } return(result); }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="serviceName"></param> /// <param name="methodName"></param> /// <param name="outputPerformanceLog"></param> /// <returns></returns> private Marshaller <T> GetMarshaller <T>(string serviceName, string methodName, bool outputPerformanceLog) { Marshaller <T> marshaller = m_Settings.GetMarshallerFactoryOrDefault().GetMarshaller <T>(); if (!outputPerformanceLog) { return(marshaller); } string typeName = typeof(T).Name; return(new Marshaller <T>( delegate(T arg) { try { Stopwatch watch = Stopwatch.StartNew(); byte[] data = marshaller.Serializer(arg); if (m_Settings.PerformanceListener != null) { m_Settings.PerformanceListener.NotifySerialized(serviceName, methodName, typeName, GrpcPerformanceListener.GetMilliseconds(watch), data == null ? 0 : data.Length); } return data; } catch (Exception ex) { GrpcExceptionListener.NotifyCatchSerializerException(serviceName, methodName, typeof(T), ex); throw new GrpcSerializerException(ex.Message, ex, serviceName, methodName, typeName); } } , delegate(byte[] data) { try { Stopwatch watch = Stopwatch.StartNew(); T arg = marshaller.Deserializer(data); if (m_Settings.PerformanceListener != null) { m_Settings.PerformanceListener.NotifyDeserialized(serviceName, methodName, typeName, GrpcPerformanceListener.GetMilliseconds(watch), data == null ? 0 : data.Length); } return arg; } catch (Exception ex) { GrpcExceptionListener.NotifyCatchSerializerException(serviceName, methodName, typeof(T), ex); throw new GrpcSerializerException(ex.Message, ex, serviceName, methodName, typeName); } } )); }
/// <summary> /// 例外をキャッチしたときの処理を行います。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="method">メソッド</param> /// <param name="host">ホスト</param> /// <param name="options">オプション</param> /// <param name="original">キャッチした例外</param> /// <param name="alternate">代わりにスローさせる例外</param> /// <returns>処理された場合、true を返します。</returns> private bool HandleException <TRequest, TResponse>(Method <TRequest, TResponse> method, string host, CallOptions options, Exception original, out Exception alternate) { Exception alt = null; foreach (IGrpcClientMethodExceptionHandler interceptor in m_Settings.InvokingInterceptors) { if (interceptor == null) { continue; } Stopwatch watch = Stopwatch.StartNew(); try { bool wrapped = interceptor.ReplaceException(method, host, options, original, out alt); if (m_Settings.PerformanceListener != null) { m_Settings.PerformanceListener.NotifyMethodIntercepted(method, host, options, interceptor, GrpcPerformanceListener.GetMilliseconds(watch)); } if (wrapped) { break; } } catch (Exception ex) { GrpcExceptionListener.NotifyCatchClientException(method, host, options, ex); throw new GrpcClientMethodException(string.Format(Properties.MessageResources.ClientMethodInterceptorFailed + ex.Message, method.FullName, interceptor.Name), ex, method, host, options, interceptor); } } if (alt != null && !object.Equals(alt, original)) { alternate = alt; return(true); } else { alternate = null; return(false); } }
/// <summary> /// メソッドが実行されたときの処理を行います。 /// </summary> /// <typeparam name="TRequest">リクエストの型</typeparam> /// <typeparam name="TResponse">レスポンスの型</typeparam> /// <param name="method">メソッド</param> /// <param name="host">ホスト</param> /// <param name="options">オプション</param> /// <param name="request">リクエスト</param> /// <param name="elapsedMilliseconds">処理時間(ミリ秒)</param> protected virtual void OnInvokedMethod <TRequest, TResponse>(Method <TRequest, TResponse> method, string host, CallOptions options, TRequest request, double elapsedMilliseconds) { if (m_Settings.PerformanceListener != null) { m_Settings.PerformanceListener.NotifyMethodCalled(method, host, options, elapsedMilliseconds); } foreach (IGrpcClientMethodInvokedInterceptor interceptor in m_Settings.InvokingInterceptors) { if (interceptor == null) { continue; } Stopwatch watch = Stopwatch.StartNew(); try { interceptor.OnInvoked(method, host, options); if (m_Settings.PerformanceListener != null) { m_Settings.PerformanceListener.NotifyMethodIntercepted(method, host, options, interceptor, GrpcPerformanceListener.GetMilliseconds(watch)); } } catch (Exception ex) { throw new GrpcClientMethodException(string.Format(Properties.MessageResources.ClientMethodInterceptorFailed + ex.Message, method.FullName, interceptor.Name), ex, method, host, options, interceptor); } } }
/// <summary> /// 例外を処理します。 /// </summary> /// <param name="context">コンテキスト</param> /// <param name="exceptionHandlers">例外ハンドラ</param> /// <param name="performanceListener">パフォーマンスリスナー</param> /// <param name="original">発生した例外</param> /// <param name="alternate">代わりにスローする例外</param> /// <returns>例外がラップされた場合、true を返します。</returns> private bool HandleException(ServerCallContext context, IEnumerable <IGrpcServerMethodExceptionHandler> exceptionHandlers, GrpcServerPerformanceListener performanceListener, Exception original, out Exception alternate) { Exception alt = null; if (exceptionHandlers != null) { foreach (IGrpcServerMethodExceptionHandler handler in exceptionHandlers) { if (handler == null) { continue; } Stopwatch watch = Stopwatch.StartNew(); try { if (handler.RelpaceException(context, original, out alt)) { break; } } catch (Exception ex) { throw new GrpcServerMethodException(string.Format(Properties.MessageResources.ServerMethodInterceptorFailed + ex.Message, context.Method, handler.Name), ex, context, handler); } finally { if (performanceListener != null) { performanceListener.NotifyMethodIntercepted(context, handler, GrpcPerformanceListener.GetMilliseconds(watch)); } } } } if (alt == null) { alt = original; } RpcException rpc = alt as RpcException; if (rpc == null) { alternate = CreateRpcException(context, alt); } else { alternate = rpc; } return(!object.Equals(original, alternate)); }
/// <summary> /// サービスメソッドが呼び出されたときの処理を行います。 /// </summary> /// <param name="context">コンテキスト</param> /// <param name="interceptors">割込処理</param> /// <param name="performanceListener">パフォーマンスリスナー</param> /// <returns></returns> private async Task OnExecutedServiceMethodAsync(ServerCallContext context, IEnumerable <IGrpcServerMethodInvokedInterceptor> interceptors, GrpcServerPerformanceListener performanceListener) { if (interceptors != null) { foreach (IGrpcServerMethodInvokedInterceptor interceptor in interceptors) { if (interceptor == null) { continue; } Stopwatch watch = Stopwatch.StartNew(); try { await interceptor.OnInvokedAsync(context).ConfigureAwait(false); } catch (Exception ex) { throw new GrpcServerMethodException(string.Format(Properties.MessageResources.ServerMethodInterceptorFailed + ex.Message, context.Method, interceptor.Name), ex, context, interceptor); } finally { if (performanceListener != null) { performanceListener.NotifyMethodIntercepted(context, interceptor, GrpcPerformanceListener.GetMilliseconds(watch)); } } } } }
/// <summary> /// /// </summary> /// <param name="message"></param> /// <returns></returns> async Task IAsyncStreamWriter <TRequest> .WriteAsync(TRequest message) { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyRequestWriting(m_Method, m_Host, m_Options); } Stopwatch watch = Stopwatch.StartNew(); try { await m_Target.WriteAsync(message).ConfigureAwait(false); } finally { if (m_PerformanceListener != null) { m_PerformanceListener.NotifyRequestWrote(m_Method, m_Host, m_Options, GrpcPerformanceListener.GetMilliseconds(watch)); } } }