gRPC 作爲一套獨立的 RPC 框架,像攔截器這種功能當然也是不可或缺的,框架自帶的攔截器更多是基於框架本身出發,對於 gRPC 來說最突出的就是需要支持各種不同 RPC 調用方式的攔截,如:簡單 RPC 調用、流式 RPC 調用,流式調用又分 客戶端流式調用、服務端流式調用、雙向流式調用,關於流式調用更多介紹可參考:ASP.NET Core gRPC 流式調用。
攔截器分類
不論是基於 .NET Core 2.x 或 3.x,都需要依賴 Grpc.Core
這個 NuGet Package,Grpc.Core
中已提供攔截器(Interceptor
類)功能(不過如果使用的版本過低,可能不支持攔截器,我們之前經歷過這個階段)。攔截器中的方法分兩類,分別作用於客戶端(客戶端向服務端發請求時攔截) 和 服務端(服務端接收到客戶端請求時攔截)。
服務端相關攔截方法:
// 簡單調用攔截
public virtual Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
// 客戶端流式調用攔截
public virtual Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, ServerCallContext context, ClientStreamingServerMethod<TRequest, TResponse> continuation)
// 服務端流式調用攔截
public virtual Task ServerStreamingServerHandler<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, ServerStreamingServerMethod<TRequest, TResponse> continuation)
// 雙向流調用攔截
public virtual Task DuplexStreamingServerHandler<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream, ServerCallContext context, DuplexStreamingServerMethod<TRequest, TResponse> continuation)
客戶端相關攔截方法:
// 同步簡單調用攔截
public virtual TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
// 異步簡單調用攔截
public virtual AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
// 異步服務端流式調用攔截
public virtual AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
// 異步客戶端流式調用攔截
public virtual AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
// 異步雙向流調用攔截
public virtual AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
服務端攔截器實現
創建 ServerInterceptor
繼承於抽象類 Interceptor
,這裏通過實現簡單調用的服務端攔截方法 UnaryServerHandler
進行說明,最終需按實際開發情況實現更多攔截方法。
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
Console.WriteLine("服務端執行開始");
var response = await continuation(request, context);
Console.WriteLine("服務端執行結束");
return response;
}
客戶端攔截器實現
創建 ClientInterceptor
繼承於抽象類 Interceptor
,這裏通過實現 同步/異步 客戶端簡單調用的攔截方法 BlockingUnaryCall
、AsyncUnaryCall
進行說明,最終需按實際開發情況實現更多攔截方法。
public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客戶端調用執行開始");
var response = continuation(request, context);
Console.WriteLine("客戶端調用執行結束");
return response;
}
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("客戶端調用執行開始");
var responseCon = continuation(request, context);
var response = new AsyncUnaryCall<TResponse>(responseCon.ResponseAsync, responseCon.ResponseHeadersAsync, responseCon.GetStatus, responseCon.GetTrailers, responseCon.Dispose);
Console.WriteLine("客戶端調用執行結束");
return response;
}
攔截器配置
.NET Core 3.0 後配置方式如下:
服務端配置攔截器可通過在 ConfigureServices
中通過 services.AddGrpc
中的 GrpcServiceOptions
來指定 Interceptors
,如下:
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerInterceptor>();
});
客戶端配置攔截通過 channel
的 Intercept
方法,如下:
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientInterceptor());
var client = new Greeter.GreeterClient(invoker);
服務端和服務端攔截器的配置都可支持多個,如果同時指定多個攔截器會按照添加順序依次執行