在實際項目當中,咱們採用的是 Abp 框架,可是 Abp 框架官方並無針對 Grpc 進行模塊封裝。基於此我結合 Abp 與 MagicOnion 封裝了一個 Abp.Grpc 模塊,它包括服務端和調用端兩部分的包。經過這兩個包,你能夠很方便地在 Abp 框架當中集成 Grpc 實現服務內部通信。git
可是在實際使用當中會出現一個問題,當 A 服務調用 B 服務的時候,A 服務當前登陸用戶爲 admin,調用 B 服務的 IAbpSession
的值仍然爲空,這個時候當 B 服務內部實現使用了 IAbpSession
時會出現問題。github
這是由於經過 Grpc 接口調用時,並無傳遞諸如 Token 之類的東西,而在 B 服務內部的 IAbpSession
自己附加的數據是從 HttpContext
裏面獲取的,因此 B 服務當前是沒有用戶狀態的。session
所幸 IAbpSession
提供了一個 Use
方法,經過這個方法咱們能夠臨時地改變 IAbpSession
內部的值,當 。定義以下:框架
IDisposable Use(int? tenantId, long? userId);
使用方法以下:測試
public class TestAppService : ITransientDependency { private readonly IAbpSession _abpSession; public TestAppService(IAbpSession abpSession) { _abpSession = abpSession; } public void TestMethod() { using(_abpSession.Use(10,20)) { // 其餘操做 } // 出去 using 語句以後會自動釋放以前的值 } }
這裏 Abp.Grpc 庫使用的是 MagicOnion 庫實現 Grpc 接口的,底層序列化使用的是 MessagePack,速度也不比 Protocol Buffer 差。code
服務定義接口時,必須附加一個 GrpcSession
參數,這個參數用於調用方傳遞其 IAbpSession
值所使用。例如我有一個接口方法以下,用於返回服務方接收到的用戶 Id 值。blog
public interface ITestGrpcService : IService<ITestGrpcService> { // 普通的 Grpc 接口定義 UnaryResult<int> Sum(int x, int y); // 帶有 GrpcSession 的接口定義 UnaryResult<long?> TestGrpcSession(GrpcSession session); }
服務提供方在實現 ITestGrpcService
的時候,須要在代碼起始點就開始使用 using
語句包裹代碼。接口
public class TestGrpcService : ServiceBase<ITestGrpcService>, ITestGrpcService { private readonly IAbpSession _abpSession; public TestGrpcService() { _abpSession = IocManager.Instance.Resolve<IIocManager>().Resolve<IAbpSession>(); } public UnaryResult<int> Sum(int x, int y) { return UnaryResult(x + y); } public UnaryResult<long?> TestGrpcSession(GrpcSession session) { // 賦值前 Session 的值 Console.WriteLine(_abpSession.UserId); // 臨時改變 Session 值 using (_abpSession.Use(session.TenantId, session.UserId)) { Console.WriteLine(_abpSession.UserId); } // 離開 using 語句時 Session 的值 Console.WriteLine(_abpSession.UserId); return new UnaryResult<long?>(1000); } }
服務調用方則直接在調用 Grpc 接口的時候,傳遞給接口當前服務的 Session 狀態。rpc
public class TestApplicationService : ApplicationService { private readonly IGrpcConnectionUtility _utility; public TestApplicationService(IGrpcConnectionUtility utility) { _utility = utility; } public void TestAction() { // 得到指定的 Grpc 服務 var service = _utility.GetRemoteService<ITestGrpcService>("Grpc 服務名稱"); // 調用測試方法,傳遞當前調用方的 Session 值 var userId = service.TestGrpcSession(AbpSession as AbpSessionBase).GetAwaiter().GetResult(); Console.WriteLine("TestGrpcSession 方法結果:" + userId); } }
當客戶端調用 GRPC 接口時,會將自身的 Session 狀態經過 GrpcSession 傳遞到服務端,這樣服務端就可以共享客戶端的繪畫狀態。get
Abp.Grpc 庫地址:https://github.com/GameBelial/Abp.Grpc