dotnet core gRPC
原文在本人公眾號中,歡迎關注我,時不時的會分享一些心得
HTTP和RPC是現代微服務架構中很常用的資料傳輸方式,兩者有很多相似之處,但是又有很大的不同,HTTP是一種規范性、通用性、非常標準的傳輸協議,幾乎所有的語言都支持,如果要確保各平臺無縫銜接,可以考慮使用HTTP協議,例如現在常規的RestFUL,整個傳輸程序通常使用Json資料格式,以至于不管是前端還是后端都可以很好的對接,
RPC協議不僅僅是服務間通信協議,甚至是行程間也存在,可以降低諸多微服務之間呼叫成本,屏蔽了通訊細節,呼叫遠程方法處理資料時像呼叫本地方法一樣絲滑順暢,但是對前端和瀏覽器不是特別友好,
GRPC是google制定實作的一種Rpc形式,官網解釋是:
gRPC是可以在任何環境中運行的現代開源高性能RPC框架,它可以通過可插拔的支持來有效地連接資料中心內和跨資料中心的服務,以實作負載平衡,跟蹤,運行狀況檢查和身份驗證,它也適用于分布式計算的最后一英里,以將設備,移動應用程式和瀏覽器連接到后端服務,
gRPC主要包括四個特點:
- 簡單的服務定義且不局限于語言:gRPC基于ProtoBuf協議構建,該協議提供了強大的系列化工具和語言定義服務,
- 跨語言和平臺:可自動為多語言或平臺生成客戶端和服務端內容,
- 快速啟動和擴展性:只需極少代碼就可以生成整個通訊環境,可以擴展數百萬rpc請求,
- 雙向流和集成身份驗證:基于HTTP/2的傳輸機制以及雙向流和而完全可集成的插入式身份驗證機制,
ProtoBuf協議:
該協議是一種序列化結構化資料的靈活,高效,自動化的機制,比xml更小,更快,更簡單,您定義要一次構造資料的方式,然后可以使用生成的特殊源代碼輕松地使用各種語言在各種資料流中寫入和讀取結構化資料,您甚至可以更新資料結構,而不會破壞已針對“舊”格式編譯的已部署程式,
協議檔案定義方式:
這是一個簡單的定義,此檔案在.proto檔案中定義,與語言無關,每個訊息型別都有一個或多個唯一編號的欄位,每個欄位都有一個名稱和一個值型別,其中值型別可以是數字(整數或浮點數),布林值,字串等,定義好后可以使用編譯器生成對應語言的操作物件,
更多協議內容請參閱:https://developers.google.com/protocol-buffers/docs/overview,
.net Core3.0 中的Grpc
- 使用Visual Stduio 2019 創建一個gRPC服務
請注意:此處創建的是使用ASP.NET Core的Grpc服務,也就是說,有WebHost去托管服務的,
后面,我們使用Host通用主機進行托管, - 先來看看Startup類
圖中這兩行代碼是關鍵,services.AddGrpc();將rpc注入到應用程式服務中,
endpoints.MapGrpcService();則是在中間件啟用監聽rpc請求,
默認情況下此時生成專案后,proto檔案只會生成Serve的代碼,客戶端代碼生成需要單獨做配置,
微軟檔案中是將proto檔案拷貝到client中,去生成client代碼,此時服務和客戶端生成配置就不一樣了:
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
我本人習慣將生成的server和client放在一起,打包后供client端和server端使用,只需要這樣設定:
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server;Client" />
</ItemGroup>
配置好后重新生成專案,grpctool會自動生成服務端,客戶端代碼,
client呼叫方式(asp.net core gRPC):
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHello(
new HelloRequest { Name = "World" });
Console.WriteLine(response.Message);
接下來,我們創建一個簡單的示例
- 創建兩個個Core控制臺專案并添加檔案夾Protos和Services,分別新增一個demo.proto檔案和DemoService.cs檔案
- 引入nuget包:
<PackageReference Include="Google.Protobuf" Version="3.10.1" />
<PackageReference Include="Grpc" Version="2.24.0" />
<PackageReference Include="Grpc.Tools" Version="2.24.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0" />
- 編輯csproj檔案:使得支持同時生成client和server代碼(作為demo,server端 應該只作為server,生成client和server的代碼的應該單獨抽出來)
- 服務端:重寫GrpcExampleService.GrpcExampleServiceBase中的rpc方法(也就是.proto檔案生成的代碼內容中的rpc服務方法)
public class DemoService: GrpcExampleService.GrpcExampleServiceBase
{
public override Task<AskResponse> Ask(AskRequest request, ServerCallContext context)
{
return Task.FromResult(new AskResponse {Content = "Hello from Ask"});
}
public override Task<ResponseModel> GetName(RequestModel request, ServerCallContext context)
{
return Task.FromResult(new ResponseModel { Name = "Hello Pluto" });
}
}
- 接下來就是創建啟動項(HOST)了(GrpcServer):
這次使用通用主機,不適用asp.net core webhost,
public class GrpcServer:IHostedService
{
private readonly GrpcExampleService.GrpcExampleServiceBase _sampleServiceBase;
public GrpcServer(GrpcExampleService.GrpcExampleServiceBase sampleServiceBase)
{
_sampleServiceBase = sampleServiceBase;
}
/// <summary>
/// 啟動自己定義的rpc服務
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
GrpcServiceManager.Start(GrpcExampleService.BindService(_sampleServiceBase));
}, cancellationToken);
}
/// <summary>
/// 停止
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.Factory.StartNew(() =>
{
GrpcServiceManager.Stop();
}, cancellationToken);
}
}
GrpcServiceManager中就是真正的啟動和停止grpc服務:
public class GrpcServiceManager
{
static Server server;
public static void Start(ServerServiceDefinition bindService)
{
if (bindService == null)
throw new ArgumentNullException("bindService");
var services = new List<ServerServiceDefinition>() { bindService };
Start(services); //todo 添加配置,攔截器等等
}
private static void Start(List<ServerServiceDefinition> services)
{
try
{
server = new Server()
{
Ports = { new ServerPort("0.0.0.0", 8890, ServerCredentials.Insecure) }
};
foreach (var service in services)
{
server.Services.Add(service);
}
server.Start();
//todo consul 注冊
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public static void Stop()
{
try
{
server?.ShutdownAsync().Wait();
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
注意:這里應該將proto協議 服務端客戶端端進行分離,協議生成的代碼打包后 被客戶端專案和服務端專案參考,這里只是為了簡便客戶端直接會參考服務,因為要用到GrpcExampleService.GrpcExampleServiceClient
上邊的todo 后再后續增加對應的功能,
這樣服務端就創建完了,接下來就是創建客戶端進行呼叫:
控制臺客戶端:
main中實作呼叫邏輯
static void Main(string[] args)
{
var channel=new Grpc.Core.Channel("127.0.0.1",8890,ChannelCredentials.Insecure);
var democlient=new GrpcExampleService.GrpcExampleServiceClient(channel);
var res= democlient.Ask(new AskRequest
{
Cate = 0,
Key = "1312"
});
var res2 = democlient.GetName(new RequestModel
{
Key = "1313"
});
Console.WriteLine($"Ask={res}.GetName={res2}");
}
然后就可以了,啟動服務端,然后再啟動客戶端,就可以看到呼叫結果了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/98034.html
標籤:.NET Core
上一篇:我來告訴你:VS2019開發ASP.NET Core 3.0 Web專案,修改視圖后,重繪瀏覽器看不到修改后的效果怎么處理
