|
|
|
@ -27,27 +27,27 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// Provides a base class for generic interceptor implementations that raises |
|
|
|
|
/// events and hooks to control the RPC lifecycle. |
|
|
|
|
/// </summary> |
|
|
|
|
public abstract class GenericInterceptor : Interceptor |
|
|
|
|
internal abstract class GenericInterceptor : Interceptor |
|
|
|
|
{ |
|
|
|
|
/// <summary> |
|
|
|
|
/// Provides hooks through which an invocation should be intercepted. |
|
|
|
|
/// </summary> |
|
|
|
|
public sealed class ClientCallArbitrator<TRequest, TResponse> |
|
|
|
|
public sealed class ClientCallHooks<TRequest, TResponse> |
|
|
|
|
where TRequest : class
|
|
|
|
|
where TResponse : class
|
|
|
|
|
{ |
|
|
|
|
internal ClientCallArbitrator<TRequest, TResponse> Freeze() |
|
|
|
|
internal ClientCallHooks<TRequest, TResponse> Freeze() |
|
|
|
|
{ |
|
|
|
|
return (ClientCallArbitrator<TRequest, TResponse>)MemberwiseClone(); |
|
|
|
|
return (ClientCallHooks<TRequest, TResponse>)MemberwiseClone(); |
|
|
|
|
} |
|
|
|
|
/// <summary> |
|
|
|
|
/// Override the context for the outgoing invocation. |
|
|
|
|
/// </summary> |
|
|
|
|
public ClientInterceptorContext<TRequest, TResponse> Context { get; set; } |
|
|
|
|
public ClientInterceptorContext<TRequest, TResponse>? ContextOverride { get; set; } |
|
|
|
|
/// <summary> |
|
|
|
|
/// Override the request for the outgoing invocation for non-client-streaming invocations. |
|
|
|
|
/// </summary> |
|
|
|
|
public TRequest UnaryRequest { get; set; } |
|
|
|
|
public TRequest UnaryRequestOverride { get; set; } |
|
|
|
|
/// <summary> |
|
|
|
|
/// Delegate that intercepts a response from a non-server-streaming invocation and optionally overrides it. |
|
|
|
|
/// </summary> |
|
|
|
@ -73,7 +73,7 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <summary> |
|
|
|
|
/// Intercepts an outgoing call from the client side. |
|
|
|
|
/// Derived classes that intend to intercept outgoing invocations from the client side should |
|
|
|
|
/// override this and return the appropriate hooks in the form of a ClientCallArbitrator instance. |
|
|
|
|
/// override this and return the appropriate hooks in the form of a ClientCallHooks instance. |
|
|
|
|
/// </summary> |
|
|
|
|
/// <param name="context">The context of the outgoing invocation.</param> |
|
|
|
|
/// <param name="clientStreaming">True if the invocation is client-streaming.</param> |
|
|
|
@ -82,10 +82,10 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TRequest">Request message type for the current invocation.</typeparam> |
|
|
|
|
/// <typeparam name="TResponse">Response message type for the current invocation.</typeparam> |
|
|
|
|
/// <returns> |
|
|
|
|
/// The derived class should return an instance of ClientCallArbitrator to control the trajectory |
|
|
|
|
/// The derived class should return an instance of ClientCallHooks to control the trajectory |
|
|
|
|
/// as they see fit, or null if it does not intend to pursue the invocation any further. |
|
|
|
|
/// </returns> |
|
|
|
|
protected virtual ClientCallArbitrator<TRequest, TResponse> InterceptCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, bool clientStreaming, bool serverStreaming, TRequest request) |
|
|
|
|
protected virtual ClientCallHooks<TRequest, TResponse> InterceptCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, bool clientStreaming, bool serverStreaming, TRequest request) |
|
|
|
|
where TRequest : class
|
|
|
|
|
where TResponse : class
|
|
|
|
|
{ |
|
|
|
@ -95,18 +95,18 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <summary> |
|
|
|
|
/// Provides hooks through which a server-side handler should be intercepted. |
|
|
|
|
/// </summary> |
|
|
|
|
public sealed class ServerCallArbitrator<TRequest, TResponse> |
|
|
|
|
public sealed class ServerCallHooks<TRequest, TResponse> |
|
|
|
|
where TRequest : class
|
|
|
|
|
where TResponse : class
|
|
|
|
|
{ |
|
|
|
|
internal ServerCallArbitrator<TRequest, TResponse> Freeze() |
|
|
|
|
internal ServerCallHooks<TRequest, TResponse> Freeze() |
|
|
|
|
{ |
|
|
|
|
return (ServerCallArbitrator<TRequest, TResponse>)MemberwiseClone(); |
|
|
|
|
return (ServerCallHooks<TRequest, TResponse>)MemberwiseClone(); |
|
|
|
|
} |
|
|
|
|
/// <summary> |
|
|
|
|
/// Override the request for the outgoing invocation for non-client-streaming invocations. |
|
|
|
|
/// </summary> |
|
|
|
|
public TRequest UnaryRequest { get; set; } |
|
|
|
|
public TRequest UnaryRequestOverride { get; set; } |
|
|
|
|
/// <summary> |
|
|
|
|
/// Delegate that intercepts a response from a non-server-streaming invocation and optionally overrides it. |
|
|
|
|
/// </summary> |
|
|
|
@ -132,7 +132,7 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <summary> |
|
|
|
|
/// Intercepts an incoming service handler invocation on the server side. |
|
|
|
|
/// Derived classes that intend to intercept incoming handlers on the server side should |
|
|
|
|
/// override this and return the appropriate hooks in the form of a ServerCallArbitrator instance. |
|
|
|
|
/// override this and return the appropriate hooks in the form of a ServerCallHooks instance. |
|
|
|
|
/// </summary> |
|
|
|
|
/// <param name="context">The context of the incoming invocation.</param> |
|
|
|
|
/// <param name="clientStreaming">True if the invocation is client-streaming.</param> |
|
|
|
@ -141,14 +141,14 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TRequest">Request message type for the current invocation.</typeparam> |
|
|
|
|
/// <typeparam name="TResponse">Response message type for the current invocation.</typeparam> |
|
|
|
|
/// <returns> |
|
|
|
|
/// The derived class should return an instance of ServerCallArbitrator to control the trajectory |
|
|
|
|
/// The derived class should return an instance of ServerCallHooks to control the trajectory |
|
|
|
|
/// as they see fit, or null if it does not intend to pursue the invocation any further. |
|
|
|
|
/// </returns> |
|
|
|
|
protected virtual Task<ServerCallArbitrator<TRequest, TResponse>> InterceptHandler<TRequest, TResponse>(ServerCallContext context, bool clientStreaming, bool serverStreaming, TRequest request) |
|
|
|
|
protected virtual Task<ServerCallHooks<TRequest, TResponse>> InterceptHandler<TRequest, TResponse>(ServerCallContext context, bool clientStreaming, bool serverStreaming, TRequest request) |
|
|
|
|
where TRequest : class
|
|
|
|
|
where TResponse : class
|
|
|
|
|
{ |
|
|
|
|
return Task.FromResult<ServerCallArbitrator<TRequest, TResponse>>(null); |
|
|
|
|
return Task.FromResult<ServerCallHooks<TRequest, TResponse>>(null); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -156,13 +156,13 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// </summary> |
|
|
|
|
public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = InterceptCall(context, false, false, request)?.Freeze(); |
|
|
|
|
context = arbitrator?.Context ?? context; |
|
|
|
|
request = arbitrator?.UnaryRequest ?? request; |
|
|
|
|
var hooks = InterceptCall(context, false, false, request)?.Freeze(); |
|
|
|
|
context = hooks?.ContextOverride ?? context; |
|
|
|
|
request = hooks?.UnaryRequestOverride ?? request; |
|
|
|
|
var response = continuation(request, context); |
|
|
|
|
if (arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
response = arbitrator.OnUnaryResponse(response); |
|
|
|
|
response = hooks.OnUnaryResponse(response); |
|
|
|
|
} |
|
|
|
|
return response; |
|
|
|
|
} |
|
|
|
@ -172,13 +172,13 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// </summary> |
|
|
|
|
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = InterceptCall(context, false, false, request)?.Freeze(); |
|
|
|
|
context = arbitrator?.Context ?? context; |
|
|
|
|
request = arbitrator?.UnaryRequest ?? request; |
|
|
|
|
var hooks = InterceptCall(context, false, false, request)?.Freeze(); |
|
|
|
|
context = hooks?.ContextOverride ?? context; |
|
|
|
|
request = hooks?.UnaryRequestOverride ?? request; |
|
|
|
|
var response = continuation(request, context); |
|
|
|
|
if (arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
response = new AsyncUnaryCall<TResponse>(response.ResponseAsync.ContinueWith(unaryResponse => arbitrator.OnUnaryResponse(unaryResponse.Result)), |
|
|
|
|
response = new AsyncUnaryCall<TResponse>(response.ResponseAsync.ContinueWith(unaryResponse => hooks.OnUnaryResponse(unaryResponse.Result)), |
|
|
|
|
response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose); |
|
|
|
|
} |
|
|
|
|
return response; |
|
|
|
@ -189,14 +189,14 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// </summary> |
|
|
|
|
public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = InterceptCall(context, false, true, request)?.Freeze(); |
|
|
|
|
context = arbitrator?.Context ?? context; |
|
|
|
|
request = arbitrator?.UnaryRequest ?? request; |
|
|
|
|
var hooks = InterceptCall(context, false, true, request)?.Freeze(); |
|
|
|
|
context = hooks?.ContextOverride ?? context; |
|
|
|
|
request = hooks?.UnaryRequestOverride ?? request; |
|
|
|
|
var response = continuation(request, context); |
|
|
|
|
if (arbitrator?.OnResponseMessage != null || arbitrator?.OnResponseStreamEnd != null) |
|
|
|
|
if (hooks?.OnResponseMessage != null || hooks?.OnResponseStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
response = new AsyncServerStreamingCall<TResponse>( |
|
|
|
|
new WrappedAsyncStreamReader<TResponse>(response.ResponseStream, arbitrator.OnResponseMessage, arbitrator.OnResponseStreamEnd), |
|
|
|
|
new WrappedAsyncStreamReader<TResponse>(response.ResponseStream, hooks.OnResponseMessage, hooks.OnResponseStreamEnd), |
|
|
|
|
response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose); |
|
|
|
|
} |
|
|
|
|
return response; |
|
|
|
@ -207,20 +207,20 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// </summary> |
|
|
|
|
public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = InterceptCall(context, true, false, null)?.Freeze(); |
|
|
|
|
context = arbitrator?.Context ?? context; |
|
|
|
|
var hooks = InterceptCall(context, true, false, null)?.Freeze(); |
|
|
|
|
context = hooks?.ContextOverride ?? context; |
|
|
|
|
var response = continuation(context); |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnResponseStreamEnd != null || arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnResponseStreamEnd != null || hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
var requestStream = response.RequestStream; |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnRequestStreamEnd != null) |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnRequestStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
requestStream = new WrappedClientStreamWriter<TRequest>(response.RequestStream, arbitrator.OnRequestMessage, arbitrator.OnRequestStreamEnd); |
|
|
|
|
requestStream = new WrappedClientStreamWriter<TRequest>(response.RequestStream, hooks.OnRequestMessage, hooks.OnRequestStreamEnd); |
|
|
|
|
} |
|
|
|
|
var responseAsync = response.ResponseAsync; |
|
|
|
|
if (arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
responseAsync = response.ResponseAsync.ContinueWith(unaryResponse => arbitrator.OnUnaryResponse(unaryResponse.Result)); |
|
|
|
|
responseAsync = response.ResponseAsync.ContinueWith(unaryResponse => hooks.OnUnaryResponse(unaryResponse.Result)); |
|
|
|
|
} |
|
|
|
|
response = new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, responseAsync, response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose); |
|
|
|
|
} |
|
|
|
@ -232,20 +232,20 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// </summary> |
|
|
|
|
public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = InterceptCall(context, true, true, null)?.Freeze(); |
|
|
|
|
context = arbitrator?.Context ?? context; |
|
|
|
|
var hooks = InterceptCall(context, true, true, null)?.Freeze(); |
|
|
|
|
context = hooks?.ContextOverride ?? context; |
|
|
|
|
var response = continuation(context); |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnRequestStreamEnd != null || arbitrator?.OnResponseMessage != null || arbitrator?.OnResponseStreamEnd != null) |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnRequestStreamEnd != null || hooks?.OnResponseMessage != null || hooks?.OnResponseStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
var requestStream = response.RequestStream; |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnRequestStreamEnd != null) |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnRequestStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
requestStream = new WrappedClientStreamWriter<TRequest>(response.RequestStream, arbitrator.OnRequestMessage, arbitrator.OnRequestStreamEnd); |
|
|
|
|
requestStream = new WrappedClientStreamWriter<TRequest>(response.RequestStream, hooks.OnRequestMessage, hooks.OnRequestStreamEnd); |
|
|
|
|
} |
|
|
|
|
var responseStream = response.ResponseStream; |
|
|
|
|
if (arbitrator?.OnResponseMessage != null || arbitrator?.OnResponseStreamEnd != null) |
|
|
|
|
if (hooks?.OnResponseMessage != null || hooks?.OnResponseStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
responseStream = new WrappedAsyncStreamReader<TResponse>(response.ResponseStream, arbitrator.OnResponseMessage, arbitrator.OnResponseStreamEnd); |
|
|
|
|
responseStream = new WrappedAsyncStreamReader<TResponse>(response.ResponseStream, hooks.OnResponseMessage, hooks.OnResponseStreamEnd); |
|
|
|
|
} |
|
|
|
|
response = new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, response.ResponseHeadersAsync, response.GetStatus, response.GetTrailers, response.Dispose); |
|
|
|
|
} |
|
|
|
@ -259,14 +259,14 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TResponse">Response message type for this method.</typeparam> |
|
|
|
|
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = (await InterceptHandler<TRequest, TResponse>(context, false, false, request))?.Freeze(); |
|
|
|
|
request = arbitrator?.UnaryRequest ?? request; |
|
|
|
|
var hooks = (await InterceptHandler<TRequest, TResponse>(context, false, false, request))?.Freeze(); |
|
|
|
|
request = hooks?.UnaryRequestOverride ?? request; |
|
|
|
|
var response = await continuation(request, context); |
|
|
|
|
if (arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
response = arbitrator.OnUnaryResponse(response); |
|
|
|
|
response = hooks.OnUnaryResponse(response); |
|
|
|
|
} |
|
|
|
|
arbitrator?.OnHandlerEnd(); |
|
|
|
|
hooks?.OnHandlerEnd(); |
|
|
|
|
return response; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -277,17 +277,17 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TResponse">Response message type for this method.</typeparam> |
|
|
|
|
public override async Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = (await InterceptHandler<TRequest, TResponse>(context, true, false, null))?.Freeze(); |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnRequestStreamEnd != null) |
|
|
|
|
var hooks = (await InterceptHandler<TRequest, TResponse>(context, true, false, null))?.Freeze(); |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnRequestStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
requestStream = new WrappedAsyncStreamReader<TRequest>(requestStream, arbitrator.OnRequestMessage, arbitrator.OnRequestStreamEnd); |
|
|
|
|
requestStream = new WrappedAsyncStreamReader<TRequest>(requestStream, hooks.OnRequestMessage, hooks.OnRequestStreamEnd); |
|
|
|
|
} |
|
|
|
|
var response = await continuation(requestStream, context); |
|
|
|
|
if (arbitrator?.OnUnaryResponse != null) |
|
|
|
|
if (hooks?.OnUnaryResponse != null) |
|
|
|
|
{ |
|
|
|
|
response = arbitrator.OnUnaryResponse(response); |
|
|
|
|
response = hooks.OnUnaryResponse(response); |
|
|
|
|
} |
|
|
|
|
arbitrator?.OnHandlerEnd(); |
|
|
|
|
hooks?.OnHandlerEnd(); |
|
|
|
|
return response; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -298,14 +298,14 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TResponse">Response message type for this method.</typeparam> |
|
|
|
|
public override async Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = (await InterceptHandler<TRequest, TResponse>(context, false, true, request))?.Freeze(); |
|
|
|
|
request = arbitrator?.UnaryRequest ?? request; |
|
|
|
|
if (arbitrator?.OnResponseMessage != null) |
|
|
|
|
var hooks = (await InterceptHandler<TRequest, TResponse>(context, false, true, request))?.Freeze(); |
|
|
|
|
request = hooks?.UnaryRequestOverride ?? request; |
|
|
|
|
if (hooks?.OnResponseMessage != null) |
|
|
|
|
{ |
|
|
|
|
responseStream = new WrappedAsyncStreamWriter<TResponse>(responseStream, arbitrator.OnResponseMessage); |
|
|
|
|
responseStream = new WrappedAsyncStreamWriter<TResponse>(responseStream, hooks.OnResponseMessage); |
|
|
|
|
} |
|
|
|
|
await continuation(request, responseStream, context); |
|
|
|
|
arbitrator?.OnHandlerEnd(); |
|
|
|
|
hooks?.OnHandlerEnd(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
@ -315,17 +315,17 @@ namespace Grpc.Core.Interceptors |
|
|
|
|
/// <typeparam name="TResponse">Response message type for this method.</typeparam> |
|
|
|
|
public override async Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation) |
|
|
|
|
{ |
|
|
|
|
var arbitrator = (await InterceptHandler<TRequest, TResponse>(context, true, true, null))?.Freeze(); |
|
|
|
|
if (arbitrator?.OnRequestMessage != null || arbitrator?.OnRequestStreamEnd != null) |
|
|
|
|
var hooks = (await InterceptHandler<TRequest, TResponse>(context, true, true, null))?.Freeze(); |
|
|
|
|
if (hooks?.OnRequestMessage != null || hooks?.OnRequestStreamEnd != null) |
|
|
|
|
{ |
|
|
|
|
requestStream = new WrappedAsyncStreamReader<TRequest>(requestStream, arbitrator.OnRequestMessage, arbitrator.OnRequestStreamEnd); |
|
|
|
|
requestStream = new WrappedAsyncStreamReader<TRequest>(requestStream, hooks.OnRequestMessage, hooks.OnRequestStreamEnd); |
|
|
|
|
} |
|
|
|
|
if (arbitrator?.OnResponseMessage != null) |
|
|
|
|
if (hooks?.OnResponseMessage != null) |
|
|
|
|
{ |
|
|
|
|
responseStream = new WrappedAsyncStreamWriter<TResponse>(responseStream, arbitrator.OnResponseMessage); |
|
|
|
|
responseStream = new WrappedAsyncStreamWriter<TResponse>(responseStream, hooks.OnResponseMessage); |
|
|
|
|
} |
|
|
|
|
await continuation(requestStream, responseStream, context); |
|
|
|
|
arbitrator?.OnHandlerEnd(); |
|
|
|
|
hooks?.OnHandlerEnd(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private class WrappedAsyncStreamReader<T> : IAsyncStreamReader<T> |
|
|
|
|