在上一篇文章中,我讨论了GRPC如何工作并在.NET中序列化数据。现在将创建一个.NET 8中的GRPC的实例。 使用dotnet cli命令为客户端创建两个新项目,另一个为服务器创建一个新项目,或使用UI创建.NET 8的新项目。
dotnet new WebAPI -N grpcServer
对于客户,我将使用我为介绍hangfire 创建的旧项目,我们将从hangfire Background作业中调用我们的服务器,以了解GRPC的工作原理。
链接到旧的hangfire文章Boosting Productivity with HangFire。
在github Github Code Link上找到代码
让我们编辑我们的Hangfire项目并为GRPC添加Nuget软件包。
<PackageReference Include="Google.Protobuf" Version="3.23.4" />
<PackageReference Include="Grpc.Net.Client" Version="2.55.0" />
<PackageReference Include="Grpc.Net.Client.Web" Version="2.55.0" />
<PackageReference Include="Grpc.Tools" Version="2.56.0">
google.protobuf 我们可以使用此软件包创建Protobuf文件。
grpc.net.client
.NET中的grpc.net.client软件包提供了生成GRPC服务和客户端所需的工具。
grpc.net.client.web (由于HTTP Hander而使用)
.NET中的GRPC.NET.CLIENT.WEB软件包提供了一种从Web应用程序调用GRPC服务的方法。该软件包使用grpc.net.client软件包进行呼叫,但它还提供了一些针对Web应用程序的其他功能。
grpc.tools
该软件包提供了C#工具支持,用于从.csproj项目中的.proto文件生成C#代码。
创建GRPC文件
让我们在我们的Hangfire Project One中创建2个新文件夹,用于原始服务和其他服务。
- 在Protos文件夹中创建Hello World Proto(Helloworld.proto)。
- 在服务文件夹中创建hangfirejobservice(因为我们将从hangfire Service致电我们的GRPC) 现在我们的项目看起来像这样。
右键单击helloworld.proto文件,然后转到属性。我们需要将GRPC存根类设置为 client 和编译器 Protobuf 编译器,以使我们的客户工作。
//This line specifies the version of the Protocol Buffers language that is used in the file.
syntax = "proto3";
//This line specifies the C# namespace that will be used to generate the code for the messages and services defined in the file.
option csharp_namespace = "HangFire.Protos";
//This line specifies the package name for the messages and services defined in the file.
package HelloWorld;
//This line defines a service called HelloWorld. The service has a single method called SayHello. The SayHello method takes a HelloRequest message as input and returns a HelloReply message as output.
service HelloWorld {
// Sends a Hello to Server
rpc SayHello (HelloRequest) returns (HelloReply);
}
//This line defines a message called HelloRequest. The HelloRequest message has a single field called message. The message field is a string that contains the input we will send
//request payload
message HelloRequest {
string message = 1;
}
//This line defines a message called HelloReply. The HelloReply message has a single field called message. The message field is a string that contains the message that the server sent to the client.
//reponse payload
message HelloReply {
string message = 1;
}
//The number 1 in the line string message = 1; refers to the field number of the message field. In Protocol Buffers, field numbers are used to uniquely identify fields in messages. The field number 1 is the first field in the HelloRequest/HelloReply message.
右键单击并构建我们的项目以使原始文件编译。
现在,我们需要配置 hangfirejobmanager 使用后台作业调用GRPC服务器。代码看起来像这样
public class HangFireJobManager
{
public async Task<bool> ExecuteFireAndForgetJob()
{
try
{
//serviceEndpoint contains the address of the gRPC server.
var serviceEndpoint = "https://localhost:7218";
//The GrpcChannel.ForAddress() method creates a channel to the gRPC server. The GrpcChannelOptions object specifies that the channel will use the GrpcWebHandler to handle HTTP requests.
var channel = GrpcChannel.ForAddress(serviceEndpoint, new GrpcChannelOptions
{
HttpHandler = new GrpcWebHandler(new HttpClientHandler())
});
// The HelloWorld service is a gRPC service that is defined in the HelloWorld.proto file. The HelloWorld.HelloWorldClient class is a class that provides a client for the HelloWorld service.
var client = new HelloWorld.HelloWorldClient(channel);
//The helloRequest variable is a HelloRequest message. The Message field of the helloRequest message is set to the string "Calling Server From Client".
Console.WriteLine("Sending Request to Server");
var helloRequest = new HelloRequest
{
Message = "Calling Server From Client"
};
//The client.SayHello() method sends the helloRequest message to the server and returns a HelloReply message.
var ServerResponse = await Task.FromResult(client.SayHello(helloRequest));
// The Serverresponse variable is a HelloReply message.The Message field of the Serverresponse message is set to the greeting that the server sent to the client.
Console.WriteLine($"Server Reponse :{ServerResponse.Message}");
return true;
}
catch (Exception ex)
{
//logging needs to be implemeented
}
return true;
}
}
我们需要配置我们的 program.cs 用于注册背景作业。
//register hangfire service
builder.Services.AddSingleton<HangFireJobManager>();
//add background job in app builder
var backGroundJobSerivice = app.Services.GetService<IRecurringJobManager>();
backGroundJobSerivice
.AddOrUpdate("MyGrpcJob",() => app.Services.GetService<HangFireJobManager>().ExecuteFireAndForgetJob(),Cron.Daily);
我们创建了每天将执行的重复工作。
让我们进入我们的第二个项目,名为 grpcserver 我们新创建的。
添加这些Nuget软件包。
<PackageReference Include="Grpc.AspNetCore" Version="2.55.0" />
<PackageReference Include="Grpc.AspNetCore.Web" Version="2.55.0" />
<PackageReference Include="Grpc.Tools" Version="2.56.0">
创建新文件夹 protos 并添加2个新文件 helloworld.proto 和 helloworldservice 。忽略文件夹结构。
在 hellworld.proto 文件中粘贴以下代码
syntax = "proto3";
option csharp_namespace = "GrpcServer.Protos";
package HelloWorld;
// The HelloWorld service definition.
service HelloWorld {
// Sends a SayHello
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the HelloRequest.
message HelloRequest {
string message = 1;
}
// The response message containing the HelloReply.
message HelloReply {
string message = 1;
}
构建项目,以便我们可以在我们的C#类中使用原始文件。
将以下代码粘贴在 helloworldservice.cs 类中。
//The HelloWorldService class inherits from the HelloWorld.HelloWorldBase class. The HelloWorld.HelloWorldBase class is a base class that provides the implementation for the SayHello() method in HelloWorld.proto that we have created.
public class HelloWorldService : HelloWorld.HelloWorldBase
{
public override async Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
HelloReply responseModel = new HelloReply();
try
{
Console.WriteLine($"Request From the Client:{request.Message}");
responseModel.Message = "Hello From the Server";
Console.WriteLine("Server Response Sent");
return responseModel;
}
catch (Exception ex)
{
//log any error
throw;
}
}
}
让我们为GRPC服务器配置我们的 program.cs 。
//builder code
//This line of code registers the Grpc service in the ASP.NET Core application. The Grpc service provides the infrastructure for hosting gRPC services in ASP.NET Core applications.
builder.Services.AddGrpc();
//http request pipeline code
//This line of code enables gRPC-Web support in the ASP.NET Core application. gRPC-Web is a protocol that allows gRPC services to be accessed over HTTP.
app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
//This line of code maps the HelloWorldService class to a gRPC endpoint.
app.MapGrpcService<HelloWorldService>();
我们可以完成为GRPC配置服务器。现在,我们可以运行右键单击解决方案单击“设置启动项目”。
选择多个启动项目。设置GRPCServer和Hangfire项目的启动,然后单击“确定”。
现在运行该项目,然后访问hangfire仪表板,以从客户端调用我们的服务器(服务器地址可能会根据您的grpcserver project的启动设置而对其进行配置不同)。
用于访问hangfire仪表板的URL。
https://localhost:7077/hangfire
转发工作,请参阅我们创建的MyGrpcjob。
执行触发按钮并观察两个项目的控制台,响应正在生成。
您可以设置突破点以进一步检查代码并使用不同的数据类型。
Hangfire Console Repons(GRPC客户端)
GRPCSERVER控制台REPONS(GRPC服务器)
GRPC弱点
有限的浏览器支持
今天不可能直接从浏览器调用GRPC服务。 GRPC大量使用HTTP/2功能,没有浏览器提供支持Web请求的控制级别,以支持GRPC客户端。例如,浏览器不允许呼叫者要求使用HTTP/2,或提供对基础HTTP/2帧的访问。
ASP.NET Core上的GRPC提供两个浏览器兼容的解决方案
GRPC-WEB允许浏览器应用与GRPC-WEB客户端和Protobuf致电GRPC服务。 GRPC-WEB要求浏览器应用程序生成GRPC客户端。 GRPC-WEB允许浏览器应用程序受益于GRPC的高性能和低网络使用。
GRPC JSON TRANSCODING允许浏览器应用程序调用GRPC服务,就好像它们是与JSON的静止API一样。浏览器应用不需要生成GRPC客户端或有关GRPC的任何了解。可以通过使用HTTP Metadata注释.proto文件来自动创建RESTFUL API。转编码允许应用程序支持GRPC和JSON Web API,而无需重复为这两者构建单独服务的努力。
文章演示了如何在客户端(hangfire)和服务器之间建立GRPC通信> (grpcserver)。使用客户端
的一元RPC模式 向服务器发送请求并收到一个响应。
github存储库链接gRPCClient
gRPCServer.
任何问题的评论。
订阅我的新闻通讯,以直接交付给您的收件箱。
https://ahmedshahjr.substack.com/?r=bpctg&utm_campaign=pub&utm_medium=web