ASP.NET Core gRPC 拦截器

gRPC 作为一套独立的 RPC 框架,像拦截器这种功能当然也是不可或缺的,框架自带的拦截器更多是基于框架本身出发,对于 gRPC 来说最突出的就是需要支持各种不同 RPC 调用方式的拦截,如:简单 RPC 调用流式 RPC 调用,流式调用又分 客户端流式调用服务端流式调用双向流式调用,关于流式调用更多介绍可参考:ASP.NET Core gRPC 流式调用

拦截器分类

不论是基于 .NET Core 2.x 或 3.x,都需要依赖 Grpc.Core 这个 NuGet Package,Grpc.Core 中已提供拦截器(Interceptor 类)功能(不过如果使用的版本过低,可能不支持拦截器,我们之前经历过这个阶段)。拦截器中的方法分两类,分别作用于客户端(客户端向服务端发请求时拦截) 和 服务端(服务端接收到客户端请求时拦截)。

服务端相关拦截方法:

1
2
3
4
5
6
7
8
9
10
11
// 简单调用拦截
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)

客户端相关拦截方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 同步简单调用拦截
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 进行说明,最终需按实际开发情况实现更多拦截方法。

1
2
3
4
5
6
7
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,这里通过实现 同步/异步 客户端简单调用的拦截方法 BlockingUnaryCallAsyncUnaryCall 进行说明,最终需按实际开发情况实现更多拦截方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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,如下:

1
2
3
4
services.AddGrpc(options =>
{
options.Interceptors.Add<ServerInterceptor>();
});

客户端配置拦截通过 channelIntercept 方法,如下:

1
2
3
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var invoker = channel.Intercept(new ClientInterceptor());
var client = new Greeter.GreeterClient(invoker);

服务端和服务端拦截器的配置都可支持多个,如果同时指定多个拦截器会按照添加顺序依次执行

result

参考链接

如果对你有帮助就好