文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

浅议 C# 客户端和服务端通信的几种方法: Rest 和 Grpc 和其他

2024-12-02 10:59

关注

在C#客户端和C#服务器之间进行通信的方法有很多。一些功能强大,而其他功能则不是很多。有些非常快,有些则不是。知道不同的选择很重要,这样您才能决定最适合自己的选择。

本文将介绍当今最流行的技术,以及为何如此广泛地使用它们。我们将讨论REST,gRPC及其两者之间的所有内容。

最佳方案

让我们考虑一下我们希望如何在最佳环境中使客户端与服务器之间的通信看起来像。我在想像这样的东西:

  1. // on client side 
  2. public void Foo() 
  3.     var server = new MyServer(new Uri("https://www.myserver.com/");) 
  4.     int sum = server.Calculator.SumNumbers(12,13);  
  1. // on server side 
  2. class CalculatorController : Controller{ 
  3.     public int SumNumbers(int a, int b) 
  4.     { 
  5.         return a + b; 
  6.     } 

我当然想要完整的Intellisense。当我单击server并. 希望Visual Studio显示所有控制器时。当我单击CalculatorController和时.,我想查看所有操作。我还想要一流的性能,很少的网络负载和双向通信。而且我想要一个能够完美处理版本控制的强大系统,这样我就可以毫不费力地部署新的客户端版本和新的服务器版本。

要求太多吗?

请注意,我在这里谈论的是无状态API。这等效于C#项目,其中只有两种类型的类:

?静态类,只有静态方法。

?POCO类[1]仅具有类型为基本类型或其他POCO类的字段和属性。

在API中使用状态会带来复杂性,而这正是万恶之源。因此,为了本文的方便,让我们保持美好和无状态。

传统REST

REST API出现在2000年代初期,席卷了整个互联网。到目前为止,它是创建Web服务的最流行的方法。

REST为客户端到服务器的请求定义了一组固定的操作GET,POST,PUT和DELETE。每个请求都将通过包含有效负载(通常为JSON)的响应来回答。请求包含在查询本身中的参数,或者在它是POST请求时包含为有效负载(通常为JSON)的参数。

有一个称为RESTful API的标准,它定义了以下规则(您实际上不必使用它):

如果您到目前为止还不熟悉REST,则上面的解释可能不会减少它,因此这里有一个示例。在.NET中,内置了对REST的支持。实际上,默认情况下,ASP.NET Web API被构建为REST Web服务。这是典型的客户端和ASP.NET服务器的外观:

在服务器中:

  1. [Route("People")] 
  2. public class PeopleController : Controller 
  3.     [HttpGet] 
  4.     public Person GetPersonById(int id) 
  5.     { 
  6.         Person person = _db.GetPerson(id); 
  7.         return person;//Automatically serialized to JSON 
  8.     } 
  9. }    

在客户中:

  1. var client = new HttpClient(); 
  2. string resultJson =  
  3.     await client.GetStringAsync("https://www.myserver.com/People/GetPersonById?id=123"); 
  4. Person person = JsonConvert.DeserializeObject(resultJson); 

REST非常方便,但是并没有达到最佳方案。因此,让我们看看是否可以做得更好。

ReFit

ReFit不能替代REST。相反,它建立在REST之上,并允许我们像调用简单方法一样调用服务器端点。这是通过在客户端和服务器之间共享接口来实现的。在服务器端,您的控制器将实现一个接口:

  1. public interface IMyEmployeeApi 
  2.     [Get("/employee/{id}")] 
  3.     Task GetEmployee(string id); 

然后,在客户端,您需要包括相同的接口并使用以下代码:

  1. var api = RestService.For("https://www.myserver.com"); 
  2. var employee = await api.GetEmployee("abc"); 

就这么简单。除了几个NuGet软件包外,无需运行困难的自动化程序或使用任何第三方工具。

这更接近最佳方案。现在,我们有了IntelliSense,并且客户端和服务器之间的合同很牢固。但是还有另一种选择,在某些方面甚至更好。

昂首阔步

像ReFit一样,Swagger也建立在REST之上。OpenAPI[2]或Swagger是REST API的规范。它描述了具有简单JSON文件的REST Web服务。这些文件是Web服务的API架构。它们包括:

?API中的所有路径(URL)。

?每个路径的预期操作(GET,POST等)。每个路径可以处理不同的操作。例如,单个路径https://mystore.com/Product可能接受添加产品的POST操作和返回产品的GET操作。

该JSON文件实质上是客户端和服务器之间的合同。这是一个描述一个称为Swagger Petstore[3]的Web服务的swagger文件的示例(为清楚起见,我删除了一些部分):

  1. {  
  2.    "swagger":"2.0"
  3.    "info":{  
  4.       "version":"1.0.0"
  5.       "title":"Swagger Petstore"
  6.       "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
  7.    }, 
  8.    "host":"petstore.swagger.io"
  9.    "basePath":"/api"
  10.    "schemes":[  
  11.       "http" 
  12.    ], 
  13.    "consumes":[  
  14.       "application/json" 
  15.    ], 
  16.    "produces":[  
  17.       "application/json" 
  18.    ], 
  19.    "paths":{  
  20.       "/pets":{  
  21.          "get":{  
  22.             "description":"Returns all pets from the system that the user has access to"
  23.             "operationId":"findPets"
  24.             "produces":[  
  25.                "application/json"
  26.                "application/xml"
  27.             ], 
  28.             "parameters":[  
  29.                {  
  30.                   "name":"tags"
  31.                   "in":"query"
  32.                   "description":"tags to filter by"
  33.                   "required":false
  34.                   "type":"array"
  35.                   "items":{  
  36.                      "type":"string" 
  37.                   }, 
  38.                   "collectionFormat":"csv" 
  39.                }, 
  40.                {  
  41.                   "name":"limit"
  42.                   "in":"query"
  43.                   "description":"maximum number of results to return"
  44.                   "required":false
  45.                   "type":"integer"
  46.                   "format":"int32" 
  47.                } 
  48.             ], 
  49.             "responses":{  
  50.                "200":{  
  51.                   "description":"pet response"
  52.                   "schema":{  
  53.                      "type":"array"
  54.                      "items":{  
  55.                         "$ref":"#/definitions/Pet" 
  56.                      } 
  57.                   } 
  58.                }, 
  59. ... 

让我们考虑一下这个结果。使用上面的JSON文件,您可以潜在地创建具有完整IntelliSense的C#客户端。毕竟,您知道所有路径,操作,它们期望的参数,什么参数类型,什么是响应等等。

有几种工具可以做到这一点。对于服务器端,可以使用Swashbuckle.AspNetCore[4]将Swagger添加到ASP.NET中并生成所述JSON文件。对于客户端,您可以使用swagger-codegen[5]和AutoRest[6]来使用这些JSON文件并生成客户端。让我们看一个如何做到这一点的例子:

将Swagger添加到ASP.NET服务器

首先添加NuGet包Swashbuckle.AspNetCore[7]。在中ConfigureServices,注册Swagger生成器:

  1. services.AddSwaggerGen(options =>  
  2.     options.SwaggerDoc("v1", new OpenApiInfo {Title = "My Web API", Version = "v1"})); 

在添加Configure方法中Startup.cs:

  1. app.UseSwagger(); 

最后,控制器内部的动作应使用[HttpXXX]和[FromXXX]属性修饰:

  1. [HttpPost] 
  2. public async Task AddEmployee([FromBody]Employee employee) 
  3.     //... 
  4.  
  5. [HttpGet] 
  6. public async Task Employee([FromQuery]string id) 
  7.     //... 

就像服务器端一样简单。运行项目时,swagger.json将生成一个文件,可用于生成客户端。

使用AutoRest从Swagger生成客户端

要开始使用AutoRest[8],与安装NPM[9]:npm install -g autorest。安装后,您将需要使用AutoRest的命令行界面从该swagger.json文件生成C#客户端。这是一个例子:

  1. autorest --input-file="./swagger.json" --output-folder="GeneratedClient" --namespace="MyClient" --override-client-name="MyClient" --csharp 

这将产生一个GeneratedClient包含生成的C#文件的文件夹。请注意,名称空间和客户端名称被覆盖。从这里,将此文件夹添加到Visual Studio中的客户端项目。

您需要安装Microsoft.Rest.ClientRuntimeNuGet软件包,因为生成的代码取决于该软件包。安装后,您可以像使用常规C#类一样使用API:

  1. var client = new MyClient(); 
  2. Employee employee = client.Employee(id: "abc"); 

您可以在AutoRest的文档中[10]阅读一些细微之处。而且您需要使该过程自动化,因此我建议阅读Patrik Svensson的教程,[11]以获得一些好的建议以及Peter Jausovec的这篇文章[12]。

Swagger的问题是JSON文件是在运行时创建的,因此这使得在CI / CD流程中实现自动化有点困难。

传统REST vs Swagger vs ReFit

进行选择时,请注意以下几点。

但是在决定任何事情之前,请检查与REST无关的第四个选项。

gRPC

gRPC[13](gRPC远程过程调用)是Google开发的开源远程过程调用系统。它有点像REST,它提供了一种将请求从客户端发送到服务器的方式。但这在许多方面都不同,这是相同点和不同点:

有两种使用gRPC的方法。对于.NET Core 3.0,有一个完全托管的库,称为.NET的gRPC[15]。对于其中的任何内容,您都可以使用gRPC C#[16],它是使用本机代码构建的。这并不意味着适用于.NET的gRPC可以替代gRPC C#。让我们来看一个用于.NET的更新gRPC的示例。

.NET的gRPC的服务器端

这不是教程,而是更多有关预期内容的一般性想法。这是示例控制器在gRPC中的外观:

  1. public class GreeterService : Greeter.GreeterBase 
  2.     public override Task SayHello(HelloRequest request, 
  3.         ServerCallContext context) 
  4.     { 
  5.         _logger.LogInformation("Saying hello to {Name}", request.Name); 
  6.         return Task.FromResult(new HelloReply  
  7.         { 
  8.             Message = "Hello " + request.Name 
  9.         }); 
  10.     } 

您需要添加以下的Configure在Startup.cs:

  1. app.UseEndpoints(endpoints => 
  2.     endpoints.MapGrpcService(); 
  3. }); 

API在.proto文件中描述,该文件是项目的一部分:

  1. syntax = "proto3"
  2.  
  3. service Greeter { 
  4.   rpc SayHello (HelloRequest) returns (HelloReply); 
  5.  
  6. message HelloRequest { 
  7.   string name = 1; 
  8.  
  9. message HelloReply { 
  10.   string message = 1; 

此.proto文件添加到.csproj:

  1.  
  2.   "Protos\greet.proto" /> 
  3.  

 

.NET的gRPC客户端

客户端是从.proto文件生成的。代码本身非常简单:

  1. var channel = GrpcChannel.ForAddress("https://localhost:5001"); 
  2. var client = new Greeter.GreeterClient(channel); 
  3.  
  4. var response = await client.SayHello( 
  5.     new HelloRequest { Name = "World" }); 
  6.  
  7. Console.WriteLine(response.Message); 

gRPC与REST

gRPC听起来不错。它在框架下更快,更简单。那么,我们都应该从REST变为gRPC吗?答案是,这取决于你的应用场景。

以下是一些注意事项:

从我的印象来看,使用gRPC和ASP.NET仍然不是很好。借助对REST的成熟支持,您会变得更好。就基于契约的通信而言,这很不错,除了在REST中有我们已经讨论过的类似替代方案:Swagger和ReFit。

最大的优势是性能。根据这些基准[17],在大多数情况下,gRPC更快。特别是对于大型有效载荷,Protobuf序列化确实有所作为。这意味着对于高负载服务器而言,这是一个巨大的优势。

在大型ASP.NET应用程序中从REST过渡到gRPC将非常困难。但是,如果您具有基于微服务的体系结构,那么逐步完成此过渡就变得容易得多。

其他沟通方式

还有其他一些我完全没有提及的通信方式,但是值得一提的是:

References

[1] POCO类: https://www.c-sharpcorner.com/UploadFile/5d065a/poco-classes-in-entity-framework/

[2] OpenAPI: https://swagger.io/specification/

[3] Swagger Petstore: https://bfanger.nl/swagger-explained/#operationObject

[4] Swashbuckle.AspNetCore: https://github.com/domaindrivendev/Swashbuckle.AspNetCore

[5] swagger-codegen: https://github.com/swagger-api/swagger-codegen

[6] AutoRest: https://azure.github.io/autorest/

[7] Swashbuckle.AspNetCore: https://www.nuget.org/packages/Swashbuckle.AspNetCore

[8] AutoRest: https://github.com/Azure/autorest

[9] NPM: https://www.w3schools.com/nodejs/nodejs_npm.asp

[10] 文档中: https://azure.github.io/autorest/client/ops.html

[11] 教程,: https://www.patriksvensson.se/2018/10/generating-api-clients-using-autorest

[12] 文章: https://medium.com/@pjausovec/creating-c-client-library-for-web-api-projects-be132c831f9c

[13] gRPC: https://grpc.io/

[14] 协议缓冲区(Protobuf): https://en.wikipedia.org/wiki/Protocol_Buffers

[15] .NET的gRPC: https://github.com/grpc/grpc-dotnet

[16] gRPC C#: https://github.com/grpc/grpc/tree/master/src/csharp

[17] 根据这些基准: https://www.yonego.com/nl/why-milliseconds-matter/#gref

[18] GraphQL: https://graphql.org/

[19] SignalR: https://github.com/SignalR/SignalR

[20] TcpClient: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient?view=netframework-4.8

[21] TcpListener: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=netframework-4.8

[22] UdpClient: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.udpclient?view=netframework-4.8

 

[23] WCF: https://docs.microsoft.com/en-us/dotnet/framework/wcf/whats-wcf

 

来源:DotNET技术圈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯