[料理佳餚] gRPC 服務也有支援 AOP(Aspect-Oriented Programming)的實作

這幾天在把玩著 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 給大家,希望能帶給大家一點點幫助。

參考資料

C# 指南 ASP.NET 教學 ASP.NET MVC 指引
Azure SQL Database 教學 SQL Server 教學 Xamarin.Forms 教學