如何在.NET Core中為gRPC服務(wù)設(shè)計(jì)消息文件(Proto)
如何在.NET Core中為gRPC服務(wù)設(shè)計(jì)消息
使用協(xié)議緩沖區(qū)規(guī)范定義gRPC服務(wù)非常容易,但從需求轉(zhuǎn)換為.NET Core,然后管理服務(wù)的演變時(shí),需要注意幾件事。
創(chuàng)建gRPC服務(wù)的核心是.proto文件,該文件以與語言無關(guān)的格式描述了該服務(wù)。使用.proto文件,Visual Studio可以為您的服務(wù)生成基類(您只需編寫特定于業(yè)務(wù)的代碼),或者可以生成用于可靠訪問服務(wù)的客戶端類。
.proto文件必須符合Google的協(xié)議緩沖區(qū)規(guī)范(通常稱為ProtoBuf)。原始文件的內(nèi)容使您可以指定服務(wù)的接口。服務(wù)接口由兩部分組成:
- 您的gRPC服務(wù)提供的方法
- 這些方法的參數(shù)和返回值的數(shù)據(jù)結(jié)構(gòu)
您可以使用Protocol Buffers規(guī)范中[1]定義的標(biāo)量類型來構(gòu)建這些數(shù)據(jù)結(jié)構(gòu)(在ProtoBuf中稱為“消息”)??捎玫念愋桶ú紶栔?,字符串,字節(jié)數(shù)組和各種數(shù)字類型(浮點(diǎn)型,整數(shù)型和長型)。沒有日期或固定的十進(jìn)制類型。在接下來的專欄中,我將向您展示如何添加時(shí)間戳類型。對(duì)于小數(shù),您可以使用float ...并伴隨著float帶來的精度損失。
如果您要開始一個(gè)新項(xiàng)目,則要使用自2016年以來的proto3語法。但是,您必須在.proto文件的第一行“非空”行上明確指定proto3標(biāo)準(zhǔn)。引用規(guī)范[2]),否則將使用proto2規(guī)范解析您的.proto文件。指定您的文件使用proto3看起來像這樣:
syntax = "proto3";
消息和C#類
使用proto3規(guī)范,用于客戶信息的消息格式可能如下所示:
message CustomerResponse { int32 custid = 1; string firstName = 2; string lastName = 3; int32 age = 4; fixed32 creditLimit = 5; }
等號(hào)后的數(shù)字指定消息中字段的位置,從位置1開始(在我的示例中,firstName將是消息中的第二個(gè)字段)。這些數(shù)字在消息中必須是唯一的(即,您不能在同一位置使用兩個(gè)字段)。您不必按數(shù)字順序列出字段,但是如果您這樣做的話,則可以更輕松地發(fā)現(xiàn)重復(fù)的字段編號(hào)(盡管Visual Studio將發(fā)現(xiàn)任何重復(fù)的編號(hào),并在構(gòu)建應(yīng)用程序時(shí)將其報(bào)告在“錯(cuò)誤列表”中)。如果需要,您也可以跳過職位。此定義僅使用奇數(shù),例如:
message CustomerResponse { int32 custid = 1; string firstName = 3; string lastName = 5; }
在.NET Core中,消息格式被轉(zhuǎn)換為類,每個(gè)字段都成為與消息同名的類的屬性。命名這些屬性時(shí),.NET Core還將字段名稱的第一個(gè)字符轉(zhuǎn)換為大寫。因此,例如,我上一個(gè)示例中的custId字段將成為我代碼中CustomerResponse類上的CustId屬性。
在此過程中,還得刪除字段名稱中的所有下劃線,并且將以下字母大寫(即,Last_name字段名稱變?yōu)長astName屬性)。
該過程還涉及將.NET類型映射到ProtoBuf類型(例如,ProtoBuf int32變?yōu)?NET int,ProtoBuf的int64變?yōu)閘ong,fixed32變?yōu)閡int),這需要向.NET Core添加一些新類。例如,ProtoBuf支持字節(jié)數(shù)組,其類型為字節(jié)。名為ByteString的新.NET數(shù)據(jù)類型支持該字段類型。要加載ByteString,請使用ByteString類的靜態(tài)CopyFrom方法,并傳遞一個(gè)字節(jié)數(shù)組,如下所示:
byte[] bytes = new byte[1000]; cr.Valid = ByteString.CopyFrom(bytes);
要從ByteString檢索字節(jié)數(shù)組,請使用對(duì)象的CopyTo方法,并傳遞要將字節(jié)復(fù)制到的數(shù)組和起始位置:
cr.Valid.CopyTo(bytes,0);
數(shù)組和字典
您也可以使用【repeated】的關(guān)鍵字將集合包括在定義中(在ProtoBuf中,不是集合的字段稱為“單數(shù)”)。如果我的客戶消息需要一組重復(fù)的交易金額,則可以指定如下字段:
message Customer { int32 id = 1; repeated fixed32 transactionAmounts = 4;
重復(fù)的字段在轉(zhuǎn)換為類的屬性時(shí),也使用新的類型:Google.Protobuf.RepeatedField。例如,我的示例將生成Google.Protobuf.RepeatedField(無符號(hào)整數(shù))的屬性。您可以使用{}語法來初始化數(shù)組,如下所示:
CustomerResponse cr = new CustomerResponse { CreditLimit = {10, 15, 100} };
您可能更可能使用其各種Add方法將項(xiàng)目放入集合中:
cr.CreditLimit.Add(200);
您可以使用LINQ方法(例如First())或按位置訪問RepeatedField中的項(xiàng)目??梢哉9ぷ鳎纾?/p>
uint tranAmount = cr.CreditLimit [1];
ProtoBuf還支持稱為map的Dictionary-type集合,該集合允許您為字典的鍵和值指定類型。我的客戶消息可能會(huì)使用“友好名稱”來跟蹤客戶的各種信用卡,以定義一個(gè)字典,該字典包含密鑰(“彼得卡”,“我的旅行卡”)和值(信用卡號(hào))的字符串):
message CustomerResponse { int32 custId = 1; map<string, string> cards = 2;
有趣的是,在Visual Studio 2019預(yù)覽版中,編輯器不會(huì)像其他類型一樣突出顯示map對(duì)象(盡管編譯得很好)。
相應(yīng)的屬性將為Google.Protobuf.Collections.MapField類型,您可以通過將其Add方法傳遞給鍵和一個(gè)值來加載它,就像其他任何Dictionary一樣。
管理變更
上線后(客戶端開始使用它)更改.proto文件相對(duì)容易。例如,您可以將具有新位置編號(hào)的字段添加到服務(wù)器端軟件使用的.proto文件中,而不會(huì)打擾仍在使用該文件的早期版本的客戶端:客戶端只是忽略未在其.proto文件中列出的字段。
同樣,在相反的情況下(當(dāng)服務(wù)器.proto文件沒有客戶端的.proto字段具有的字段時(shí)),客戶端只會(huì)發(fā)現(xiàn)服務(wù)器未發(fā)送的屬性被設(shè)置為其默認(rèn)值。順便說一句,在服務(wù)器的.proto文件中定義的,未在客戶端的.proto文件中定義的字段仍會(huì)發(fā)送到客戶端,但是.NET不能提供一種方便的方式來訪問它(至少現(xiàn)在還沒有)。
確實(shí),隨著服務(wù)的發(fā)展和修改其.proto文件,您僅應(yīng)遵守兩個(gè)規(guī)則:
- 不要更改現(xiàn)有字段的位置編號(hào)
- 不要回收職位編號(hào)(即不要用新的字段3替換過時(shí)的字段3)
但是,從.proto文件生成的屬性不可為空,因此,如果未將屬性設(shè)置為值,則它將被設(shè)置為其默認(rèn)值。這意味著數(shù)字被設(shè)置為0;數(shù)字被設(shè)置為0。將string設(shè)置為string.Empty(長度為零的字符串);布爾變成虛假的;ByteString屬性默認(rèn)為ByteString對(duì)象,其IsEmpty屬性設(shè)置為true;并且RepeatedField和MapField屬性均默認(rèn)為其對(duì)應(yīng)的對(duì)象,每個(gè)對(duì)象均不包含任何項(xiàng)目,并且其Count屬性設(shè)置為0。
由于這種行為,存在從服務(wù)的.proto文件中刪除字段并且不更新所有客戶端(或者只是在服務(wù)器上生成響應(yīng)時(shí)未在對(duì)象上設(shè)置屬性)的危險(xiǎn)。危險(xiǎn)是客戶端無法區(qū)分未使用的字段和已設(shè)置為其默認(rèn)值的屬性之間的區(qū)別。如果將我的客戶的有效屬性設(shè)置為false,則客戶端將無法確定客戶是否無效或服務(wù)器是否不再生成該字段。
您可能需要考慮將屬性初始化為某個(gè)“不合理的”值(例如,數(shù)字為-1),以便客戶端可以區(qū)分設(shè)置為默認(rèn)值的屬性和已刪除的字段之間的區(qū)別。因?yàn)檫@對(duì)于布爾值是不可能的(布爾值沒有不合理的值),所以您要特別警惕刪除(甚至不再使用)布爾類型的字段。
效率和局限性
正如我在較早的概述中[3]所討論的那樣[4],gRPC服務(wù)的功能之一是它們的消息比基于HTTP的(RESTful)服務(wù)小得多。如果您真的想利用這種效率,請注意位置1到15僅需要一個(gè)字節(jié)的額外開銷(即超出存儲(chǔ)值的數(shù)據(jù)),而位置16到2047則需要兩個(gè)字節(jié)。將消息格式保持在16位以下似乎是個(gè)好主意。
有關(guān)將數(shù)據(jù)打包到盡可能小的空間的選擇類型方面的其他效率提示,請參閱規(guī)范中的標(biāo)量類型說明[5]。
順便說一句,您不能使用以下任何一種作為字段位置編號(hào):負(fù)數(shù),0、19,000到19,999(保留給ProtoBuf使用)或大于536,870,911的數(shù)字。我是否也可以建議,如果您想使用這些數(shù)字,那么您將遇到在本專欄中我無法解決的問題。
真的。別那樣做。
以上就是如何在.NET Core中為gRPC服務(wù)設(shè)計(jì)消息文件(Proto)的詳細(xì)內(nèi)容,更多關(guān)于.NET Core中為gRPC服務(wù)設(shè)計(jì)消息文件的資料請關(guān)注腳本之家其它相關(guān)文章!
- 使用grpcui測試ASP.NET core的gRPC服務(wù)
- .NET?Core(.NET6)中g(shù)RPC使用實(shí)踐
- .Net?Core微服務(wù)rpc框架GRPC通信實(shí)際運(yùn)用
- .Net?Core微服務(wù)rpc框架GRPC通信基礎(chǔ)
- 在?ASP.NET?Core?中為?gRPC?服務(wù)添加全局異常處理
- .Net Core中使用Grpc的方法
- ASP.NET Core 3.0 gRPC攔截器的使用
- ASP.NET Core 3.0使用gRPC的具體方法
- 圖析ASP.NET Core引入gRPC服務(wù)模板
- ASP.NET Core中Grpc通信的簡單用法
相關(guān)文章
.NetCore手動(dòng)封裝日志組件的實(shí)現(xiàn)代碼
這篇文章主要介紹了.NetCore手動(dòng)封裝日志組件的實(shí)現(xiàn)代碼,封裝的目的是便于在項(xiàng)目里更加簡單方便使用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03repeater隔行換色與鼠標(biāo)停留在上面達(dá)到變色效果
鼠標(biāo)停留在上面是變成其他的顏色,很多新手朋友都想實(shí)現(xiàn)這種效果,可是無從下手,本文整理了一些解決技巧,感興趣的朋友可以參考下啊2013-01-01開啟SQLSERVER數(shù)據(jù)庫緩存依賴優(yōu)化網(wǎng)站性能
2010-04-04asp.net 數(shù)據(jù)綁定的實(shí)例代碼
這篇文章介紹了asp.net 數(shù)據(jù)綁定的實(shí)例代碼,有需要的朋友可以參考一下2013-07-07MVC后臺(tái)創(chuàng)建Json(List)前臺(tái)接受并循環(huán)讀取實(shí)例
MVC后臺(tái)創(chuàng)建Json(List)同時(shí)前臺(tái)接受并循環(huán)讀取,具體實(shí)現(xiàn)代碼如下,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助2013-06-06利用noesis.Javascript開源組件.Net中執(zhí)行javascript腳本
利用Noesis.Javascript開源組件可以做到在.net中執(zhí)行js腳本,同時(shí)js腳本也能調(diào)用C#函數(shù)。這個(gè)組件的獲得方式:在NuGet中輸入搜索"Noesis"就能找到,我們來做個(gè)搜索功能:用戶能夠在textbox中輸入js腳本來篩選list記錄2013-12-12asp.net 簡單實(shí)現(xiàn)禁用或啟用頁面中的某一類型的控件
最近在一個(gè)winform項(xiàng)目中碰到的一個(gè)功能,勾選一個(gè)checkbox后窗體中的其他控件不可用。由此想到asp.net項(xiàng)目中有時(shí)候也要用到這種功能。2009-11-11