.NET Core 3.0中用 Code-First 方式創建 gRPC 服務與客戶端
.NET Core love gRPC
千呼萬喚的 .NET Core 3.0 終於在 9 月份正式發布,在它的眾多新特性中,除了性能得到了大大提高,比較受關注的應該是 ASP.NET Core 3.0 對 gRPC 的集成了。
它的源碼託管在 grpc-dotnet 這個 Github 庫中,由微軟 .NET 團隊與谷歌 gRPC 團隊共同維護.
.NET Core 對 gRPC 的支持在 grpc 官方倉庫早已有實現(grpc/csharp),但服務端沒有很好地與 ASP.NET Core 集成,使用起來還需要自己進行一些集成擴展。
而 ASP.NET Core 3.0 新增了 gRPC 服務的託管功能,能讓 gRPC 與 ASP.NET Core 框架本身的特性很好地結合,如日誌、依賴注入、身份認證和授權,並由 Kestrel 服務器提供 HTTP/2 鏈接,性能上得到充分保障。
推薦把項目中已有的 RPC 框架或者內部服務間 REST 調用都遷移到 gRPC 上,因為它已經是雲原生應用的標準 RPC 框架,在整個 CNCF 主導下的雲原生應用開發生態里 gRpc 有着舉足輕重的地位。
對於 gRPC 的使用方式,前段時間已經有其他大神寫的幾篇文章了,這裏就不再贅述了。
本文主要介紹的是區別於標準使用規範的,但對.NET 應用更加友好的使用方式,最後會提供源碼來展示。
作為對比,還是要列一下標準的使用步驟:
- 定義 proto 文件,包含服務、方法、消息對象的定義
- 引入
Grpc.Tools
Nuget 包並添加指定 proto 路徑和生成模式 - 生成項目,得到服務端的抽象類或客戶端的調用客戶端組件
- 實現服務端抽象類,並在 ASP.NET Core 註冊這個服務的路由端點
- DI 註冊 gRPC 服務。
- 客戶端用
Grpc.Net.ClientFactory
Nuget 包進行統一配置和依賴注入
.NET Core 對 gRPC 的大力支持使開發者開發效率大大提高,入門難度也減少了許多,完全可以成為跟 WebApi 等一樣的 .NET Core 技術棧的標配。
proto 在單一語言系統架構中的局限性
使用 proto 文件的好處是多語言支持,同一份 proto 可以生成各種語言的服務和客戶端,可以讓用不同語言開發的微服務直接互相遠程調用。但 proto 文件作為不同服務間的契約,不可以經常修改,否則就會對使用了它的服務造成不同程度的影響,因此對 proto 文件的版本控制需要得到重視。
另外,我們的應用程序還不應該與 gRPC 耦合,否則就會導致系統架構被這些實現細節所綁架。直接依賴 proto 文件和由它生成的代碼,就是對 gRPC 的強耦合。
例如,當應用程序在演進的過程中,複雜度還未達到完全部署隔離的必要時,為了避免因“完全邊界”引入的部署運維複雜性,又能預留隔離的可能性,需要有一層接口層作為“不完全邊界”。
又比如,目前在 windows 系統的 iis 上還不支持 grpc-dotnet,當有 windows 上的應用程序需要使用 RPC,就需要換成 REST 的實現了。
因此,為了不讓應用程序對 gRPC 過於依賴,還應該使用一層抽象(接口)層與其解耦,用接口來隔離對 RPC 實現的依賴,這樣在需要使用不同的實現時,可以通過註冊不同的實現來方便地切換。
在這些場景下,本文要介紹的 Code-First gRPC 使用方法就發揮作用了。
Code-First gRPC
說了這麼久,我好像還沒正式介紹 Code-First gRPC,到底他有多適合在單一語言系統架構中實現 gRPC 呢?下面要介紹的就是基於大名鼎鼎的 protobuf-net 實現的 gRPC 框架,protobuf-net.Grpc。
protobuf-net 是在過去十幾年前到現在一直在 .NET 中有名的 Protobuf 庫,想用 Protobuf 序列化時就會用到這個庫。他的特性就是可以把 C# 代碼編寫的類能以 Protobuf 的協議進行序列化和反序列化,而不是 proto 文件再生成這些類。而 protobuf-net.Grpc 則是一脈相承,可以把 C# 寫的接口,在服務端方便地把接口的實現類註冊成 ASP.NET Core 的 gRPC 服務,在客戶端把接口動態代理實現為調用客戶端,調用前面的這個服務端。
用法很簡單,只要聲明一個接口為您的服務契約:
[ServiceContract]
public interface IMyAmazingService {
ValueTask<SearchResponse> SearchAsync(SearchRequest request);
// ...
}
然後實現該接口的服務端:
public class MyServer : IMyAmazingService {
// ...
}
或者向系統獲取客戶端:
var client = http.CreateGrpcService<IMyAmazingService>();
var results = await client.SearchAsync(request);
這相當於以下 .proto 中的服務:
service MyAmazingService {
rpc Search (SearchRequest) returns (SearchResponse) {}
// ...
}
protobuf-net.Grpc
同樣通過普通類型定義支持 gRPC 的四種模式,把 C# 8.0 中最新的 IAsyncEnumerable
類型識別成 proto 中的 stream
,單向流、雙向流都可以實現!而且用 IAsyncEnumerable
實現可比 proto 生成的類方便很多。
例如 proto 雙向流定義:
rpc chat(stream ChatRequest) returns ( stream ChatResponse);
生成出來的方法是:
Task BathTheCat(IAsyncStreamReader<ChatRequest> requestStream, IServerStreamWriter<ChatResponse> responseStream)
而 protobuf-net.Grpc
只要定義一個方法:
IAsyncEnumerable<ChatResponse> SubscribeAsync(IAsyncEnumerable<ChatRequest> requestStream);
由此可見,protobuf-net.Grpc
無需在契約層引入第三方庫,充分運用了 C# 類型系統,把方法、類型映射到兼容了 gRPC 的服務定義上。
上文所說的 proto 局限也迎刃而解了,函數調用、gRPC、REST 都能方便切換。(REST 實現可以參考我的開源框架 shriek-fx 中的 Shriek.ServiceProxy.Http )組件。
下一篇,我將主要介紹利用 protobuf-net.Grpc
的 gRPC 雙向流模式與 Blazor
實現一個簡單的在線即時聊天室。
相關鏈接:
- protobuf-net.Grpc:
- shriek-fx:
- GrpcChat:
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】
※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線
※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益
※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象