ASP.NET Core 3.0使用gRPC的具体方法
ä¸.ç®ä»
gRPC æ¯ä¸ä¸ªç±Googleå¼æºçï¼è·¨è¯è¨çï¼é«æ§è½çè¿ç¨è¿ç¨è°ç¨ï¼RPCï¼æ¡æ¶ã gRPC使客æ·ç«¯åæå¡ç«¯åºç¨ç¨åºå¯ä»¥éæå°è¿è¡éä¿¡ï¼å¹¶ç®åäºè¿æ¥ç³»ç»çæ建ãå®ä½¿ç¨HTTP/2ä½ä¸ºéä¿¡åè®®ï¼ä½¿ç¨ Protocol Buffers ä½ä¸ºåºåååè®®ã
å®ç主è¦ä¼ç¹ï¼
- ç°ä»£é«æ§è½è½»é级 RPC æ¡æ¶ã
- 约å®ä¼åç API å¼åï¼é»è®¤ä½¿ç¨ Protocol Buffers ä½ä¸ºæè¿°è¯è¨ï¼å许ä¸è¯è¨æ å³çå®ç°ã
- å¯ç¨äºå¤ç§è¯è¨çå·¥å·ï¼ä»¥çæ强类åçæå¡å¨å客æ·ç«¯ã
- æ¯æ客æ·ç«¯ï¼æå¡å¨ååæµè°ç¨ã
- éè¿Protocol Buffersäºè¿å¶åºåååå°ç½ç»ä½¿ç¨ã
- ä½¿ç¨ HTTP/2 è¿è¡ä¼ è¾
è¿äºä¼ç¹ä½¿gRPCé常éåï¼
- é«æ§è½è½»é级微æå¡ - gRPC设计为ä½å»¶è¿åé«ååééä¿¡ï¼é常éåéè¦é«æ§è½çè½»é级微æå¡ã
- å¤è¯è¨æ··åå¼å - gRPCå·¥å·æ¯ææææµè¡çå¼åè¯è¨ï¼ä½¿gRPCæ为å¤è¯è¨å¼åç¯å¢ççæ³éæ©ã
- ç¹å¯¹ç¹å®æ¶éä¿¡ - gRPC对ååæµè°ç¨æä¾åºè²çæ¯æãgRPCæå¡å¯ä»¥å®æ¶æ¨éæ¶æ¯èæ é轮询ã
- ç½ç»åéç¯å¢ - ä½¿ç¨ Protocol Buffersäºè¿å¶åºååæ¶æ¯ï¼è¯¥åºååå§ç»å°äºçæçJSONæ¶æ¯ï¼å¯¹ç½ç»å¸¦å®½éæ±æ¯JSONå°
ä¸å»ºè®®ä½¿ç¨gRPCçåºæ¯ï¼
- æµè§å¨å¯è®¿é®çAPI - æµè§å¨ä¸å®å¨æ¯ægRPCãè½ç¶gRPC-Webå¯ä»¥æä¾æµè§å¨æ¯æï¼ä½æ¯å®æå±éæ§ï¼å¼å¥äºæå¡å¨ä»£ç
- 广æå®æ¶éä¿¡ - gRPCæ¯æéè¿æµè¿è¡å®æ¶éä¿¡ï¼ä½ä¸åå¨å已注åè¿æ¥å¹¿ææ¶æ¯çæ¦å¿µ
- è¿ç¨é´éä¿¡ - è¿ç¨å¿é¡»æ¿è½½HTTP/2æè½æ¥åä¼ å¥çgRPCè°ç¨ï¼å¯¹äºWindowsï¼è¿ç¨é´é信管éæ¯ä¸ç§æ´å¿«éçæ¹æ³ã
æ¯æçè¯è¨å¦ä¸ï¼
äº.gRPC on .NET Core
gRPC ç°å¨å¯ä»¥é常ç®åçå¨ .NET Core å ASP.NET Core ä¸ä½¿ç¨ï¼å¨ .NET Core ä¸çå®ç°çå¼æºå°åï¼https://github.com/grpc/grpc-dotnet ï¼å®ç®åç±å¾®è½¯å®æ¹ ASP.NET 项ç®ç人åè¿è¡ç»´æ¤ï¼è¯å¥½çæ¥å¥ .NET Core çæã
.NET Core ç gRPC åè½å¦ä¸ï¼
- Grpc.AspNetCore ä¸ä¸ªç¨äºå¨ASP.NET Coreæ¿è½½gRPCæå¡çæ¡æ¶ï¼å° gRPCåASP.NET Core åè½éæå¨ä¸èµ·ï¼å¦ï¼æ¥å¿ãä¾èµæ³¨å¥ã身份认è¯åææã
- Grpc.Net.Client åºäºHttpClient ï¼HttpClientç°å·²æ¯æHTTP/2ï¼ç gRPC客æ·ç«¯
- Grpc.Net.ClientFactory ä¸gRPC客æ·ç«¯éæç
HttpClientFactory
ï¼å许对gRPC客æ·ç«¯è¿è¡éä¸éç½®ï¼å¹¶ä½¿ç¨DI注å¥å°åºç¨ç¨åºä¸
ä¸.ä½¿ç¨ ASP.NET Core å建 gRPC æå¡
éè¿ Visual Studio 2019 ï¼16.3.0ï¼æä¾ç模æ¿ï¼å¯ä»¥å¿«éå建 gRPC æå¡ã
æ¥ææä¸ä¸é»è®¤æºç åå«äºä»ä¹ä¸ä¸ã
â éç½®æ件 appsettings.json
ï¼å¤äºKestrel å¯ç¨ HTTP/2 çéç½®ï¼å 为 gRPC æ¯åºäº HTTP/2 æ¥éä¿¡ç
â¡ PBåè®®æ件 greet.proto
ç¨äºèªå¨çææå¡ã客æ·ç«¯åæ¶æ¯ï¼è¡¨ç¤ºä¼ éçæ°æ®ï¼çC# Class
⢠æå¡ç±» GreeterService
ï¼æå¡ç±»éæç Greeter.GreeterBase
æ¥èªäºæ ¹æ®protoæ件èªå¨çæçï¼çæçç±»å¨ obj\Debug\netcoreapp3.0
ç®å½ä¸
èªå¨çæçç±»ï¼
⣠Startup.cs
ç±»ï¼å° gRPCæå¡æ·»å å°äºç»ç»ç¹è·¯ç±ä¸
⤠csproj 项ç®æ件ï¼åå«äº proto æ件å¼ç¨
2.è¿è¡
第ä¸æ¬¡è¿è¡ä¼æ示æ¯å¦ä¿¡ä»»è¯ä¹¦ï¼ç¹å»âæ¯â
è¿æ¯å 为HTTP/2éè¦HTTPSï¼å°½ç®¡HTTP/2å议没ææç¡®è§å®éè¦HTTPSï¼ä½æ¯ä¸ºäºå®å¨å¨æµè§å¨å®ç°ä¸é½è¦æ±äºHTTPSï¼æ以ç°å¨çHTTP/2åHTTPSåºæ¬é½æ¯ä¸å¯¹ã
å. å建 gRPC 客æ·ç«¯
1.æ·»å ä¸ä¸ª.NET Core æ§å¶å°åºç¨ç¨åº
2.éè¿nugetæ·»å åï¼Grpc.Net.ClientãGoogle.ProtobufãGrpc.Tools
3.å°æå¡ç proto æ件å¤å¶å°å®¢æ·ç«¯
4.ç¼è¾å®¢æ·ç«¯é¡¹ç®æ件ï¼æ·»å å³äºprotoæ件çæè¿°
<ItemGroup> <Protobuf Include="Protos\greet.proto" GrpcServices="Client" /> </ItemGroup>
注æ GrpcServices="Client"
è¿éæ¯Clientåæå¡æ¯ä¸ä¸æ ·ç
5.çæ客æ·ç«¯é¡¹ç®å¯ä»¥éè¿protoæ件çæç±»
6.æ·»å 客æ·ç«¯è°ç¨ä»£ç
static async Task Main(string[] args) { var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync( new HelloRequest { Name = "ææ¨" }); Console.WriteLine("Greeter æå¡è¿åæ°æ®: " + reply.Message); Console.ReadKey(); }
7.åå¯å¨æå¡ï¼ç¶åè¿è¡å®¢æ·ç«¯
è¿éå¯ä»¥çå°ï¼å®¢æ·ç«¯æåè°ç¨äºæå¡ï¼æ¶å°äºè¿åçæ¶æ¯ã
äº.èªå·±å¨æåä¸ä¸ªæå¡
åé¢æ们使ç¨ç Greeter æå¡æ¯ç±æ¨¡æ¿èªå¨ç»æ们å建çï¼ç°å¨æ们æ¥èªå·±å¨æåä¸ä¸ªæå¡ã
1.å®ä¹ proto æ件 LuCat.proto
ï¼å¹¶å¨csproj项ç®æ件ä¸æ·»å æè¿°
syntax = "proto3"; option csharp_namespace = "AspNetCoregRpcService"; import "google/protobuf/empty.proto"; package LuCat; //å®ä¹åå //å®ä¹æå¡ service LuCat{ //å®ä¹å¸ç«æ¹æ³ rpc SuckingCat(google.protobuf.Empty) returns(SuckingCatResult); } message SuckingCatResult{ string message=1; }
2.å®ç°æå¡ LuCatService.cs
public class LuCatService:LuCat.LuCatBase { private static readonly List<string> Cats=new List<string>(){"è±çé¶æ¸å±","è±çéæ¸å±","ç¾ç","èç«","ç¸è±ç«","æ©ç«"}; private static readonly Random Rand=new Random(DateTime.Now.Millisecond); public override Task<SuckingCatResult> SuckingCat(Empty request, ServerCallContext context) { return Task.FromResult(new SuckingCatResult() { Message = $"æ¨å¸äºä¸åª{Cats[Rand.Next(0, Cats.Count)]}" }); } }
3.å¨ Startup
ç»ç»ç¹è·¯ç±ä¸æ³¨å
endpoints.MapGrpcService<LuCatService>();
4.æ·»å 客æ·ç«¯è°ç¨
var catClient = new LuCat.LuCatClient(channel); var catReply = await catClient.SuckingCatAsync(new Empty()); Console.WriteLine("è°ç¨æ¸ç«æå¡ï¼"+ catReply.Message);
5.è¿è¡æµè¯
å.å®é使ç¨ä¸çæå·§
æå·§1
ä¸é¢ç« èçæä½æ¥éª¤ä¸ï¼æ们éè¦å¨æå¡å客æ·ç«¯ä¹é´å¤å¶protoï¼è¿æ¯ä¸ä¸ªå¯ä»¥çç¥æçæ¥éª¤ã
1.å¤å¶ Protos æ件夹å°è§£å³æ¹æ¡æ ¹ç®å½ï¼slnæ件æå¨ç®å½ï¼
2.å é¤å®¢æ·ç«¯åæå¡é¡¹ç®ä¸ç Protos æ件夹
3.å¨å®¢æ·ç«¯é¡¹ç®æ件csprojä¸æ·»å å³äºprotoæ件çæè¿°
<ItemGroup> <Protobuf Include="..\..\Protos\greet.proto" GrpcServices="Client" Link="Protos\greet.proto" /> </ItemGroup>
4.å¨æå¡é¡¹ç®æ件csprojä¸æ·»å å³äºprotoæ件çæè¿°
<ItemGroup> <Protobuf Include="..\..\Protos\greet.proto" GrpcServices="Server" Link="Protos\greet.proto" /> </ItemGroup>
å¨å®é项ç®ä¸ï¼è¯·èªå·±è®¡ç®ç¸å¯¹è·¯å¾
5.è¿æ ·ä¸¤ä¸ªé¡¹ç®é½æ¯ä½¿ç¨çä¸ä¸ªprotoæ件ï¼åªç¨ç»´æ¤è¿ä¸ä¸ªæ件å³å¯
æå·§2
æ们å¨å®é项ç®ä¸ä½¿ç¨ï¼è¯å®æå¤ä¸ª proto æ件ï¼é¾éæ们æ¯æ·»å ä¸ä¸ª proto æ件é½è¦å»æ´æ° csprojæ件ï¼
æ们å¯ä»¥ä½¿ç¨MSBuildåéæ¥å¸®æ们å®æï¼æä»¬å° csproj 项ç®æ件ä¸å¼å¥protoæ件信æ¯è¿è¡ä¿®æ¹ã
æå¡ç«¯ï¼
<ItemGroup> <Protobuf Include="..\..\Protos\*.proto" GrpcServices="Server" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" /> </ItemGroup>
客æ·ç«¯ï¼
<ItemGroup> <Protobuf Include="..\..\Protos\*.proto" GrpcServices="Client" Link="Protos\%(RecursiveDir)%(Filename)%(Extension)" /> </ItemGroup>
示ä¾ï¼
ä¸.æ»ç»
gRPC ç°ç®åæ¯ä¸æ¬¾é常æççé«æ§è½RPCæ¡æ¶ï¼å½åççææ¯é常好çï¼å¾å¤å¬å¸ç产åæèå¼æºé¡¹ç®é½æå¨ä½¿ç¨gRPCï¼æäºå®ï¼ç¸ä¿¡å¯ä»¥è®©æ们æ´å®¹æçæ建.NET Core å¾®æå¡ï¼å¯ä»¥è®© .NET Core æ´å¥½çæ¥å¥ gRPC çæãä¸å¾ä¸è¯´è¿æ¯ .NET Core 3.0 带æ¥çæ令人æ¯å¥çç¹æ§ä¹ä¸ã
åèèµæï¼
å¨ASP.NET Coreä¸å建gRPC客æ·ç«¯åæå¡
以ä¸å°±æ¯æ¬æçå¨é¨å容ï¼å¸æ对大家çå¦ä¹ ææ帮å©ï¼ä¹å¸æ大家å¤å¤æ¯æèæ¬ä¹å®¶ã