這幾天在把玩著 ASP.NET Core 的 gRPC 服務,正當思索著要怎麼實作 AOP(Aspect-Oriented Programming)時,我就看到了 GrpcServiceOptions
有一個 Interceptors
屬性,看到 Interceptor 這個關鍵字就知道 gRPC 服務天生就支援 AOP 的實作。
實作 Interceptor
gRPC 服務的 AOP 在伺服器端及客戶端都可以做,首先我們要實作 Grpc.Core.Interceptors.Interceptor
這個抽象類別,假定我的需求是希望能統一做一些通用的 Log,所以我就建立一個 LogInterceptor
。
public class LogInterceptor : Interceptor
{
}
接下來要選擇我們要 override 的方法,這邊可以 override 的方法有 9 個,這 9 個方法是根據不同的訊息傳送方式來觸發的,分成伺服器端用的 4 個,及客戶端用的 5 個。
伺服器端
- ClientStreamingServerHandler:當客戶端傳送 Stream Message 到伺服器端時觸發
- ServerStreamingServerHandler:當伺服器端傳送 Stream Message 到客戶端時觸發
- UnaryServerHandler:伺服器端傳送單一訊息到客戶端
- DuplexStreamingServerHandler:當伺服器端與客戶端進行雙向傳送 Stream Message 時觸發
延續我之前文章的範例,我要在客戶端呼叫 GetEmployee() 方法的時候做 Log,那麼我就要 override UnaryServerHandler() 方法。
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Microsoft.Extensions.Logging;
namespace GrpcServer.Interceptors
{
public class LogInterceptor : Interceptor
{
private readonly ILogger<LogInterceptor> logger;
public LogInterceptor(ILogger<LogInterceptor> logger)
{
this.logger = logger;
}
public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
this.logger.LogWarning("Warn logs.");
return continuation(request, context);
}
}
}
實作好方法之後,就到 Startup.cs
中註冊。
測試看看
客戶端
- AsyncClientStreamingCall:當客戶端傳送 Stream Message 到伺服器端時觸發
- AsyncServerStreamingCall:當伺服器端傳送 Stream Message 到客戶端時觸發
- AsyncDuplexStreamingCall:當伺服器端與客戶端進行雙向傳送 Stream Message 時觸發
- AsyncUnaryCall:當客戶端非同步傳送 Message 到伺服器端時觸發
- BlockingUnaryCall:當客戶端同步傳送 Message 到伺服器端時觸發
客戶端如果一樣要在呼叫 GetEmployee() 方法時做 Log,override 的是 AsyncUnaryCall() 方法。
using System;
using Grpc.Core;
using Grpc.Core.Interceptors;
namespace GrpcClient.Interceptors
{
public class LogInterceptor : Interceptor
{
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
Console.WriteLine("Logs");
return continuation(request, context);
}
}
}
然後,使用 Intercept()
方法來注入攔截器。
測試看看
以上,介紹實作 gRPC 服務的 AOP 給大家,希望能帶給大家一點點幫助。