gRPC之.Net6中的客户端和服务端共用proto协议文件

1、🍕说明

在上一篇文章gRPC之.Net6中的初步使用介绍中,我们简单的介绍了gRPC在服务端、客户端以及Web项目中的使用。

有一个问题,不知道大家发现没有,就是不管在服务端项目还是客户端项目中,我们都需要创建相同的proto协议文件,这样就会显得很麻烦,有没有一种办法只创建一次proto协议文件呢?答案是肯定的:有。

在介绍实现之前,建议大家先查看一下前一篇文章gRPC之.Net6中的初步使用介绍,方便后面关联性的讲解。


2、🍔实现

2.1、🍟新建类库项目

首先我们新建一个名称为Quber.Grpc.Common的类库项目,目的就是用于存放proto协议文件协议文件生成的对应类文件,如下图所示:

image

image

image

2.2、🧇添加引用

接下来我们在Quber.Grpc.Common的类库项目中分别添加如下引用:

Google.Protobuf
Grpc.Core.Api
Grpc.Tools

image

2.3、🥗创建proto协议文件

我们在Quber.Grpc.Common类库项目中新建一个文件夹Protos,用于存放各种proto协议文件,然后我们把Quber.Grpc.Service项目中的user.proto协议文件复制过来,复制过来后,将user.proto协议文件中的命名空间修改为Quber.Grpc.Common.Protos(和该类库保持一致),如下图所示:

image

2.4、🥙修改协议文件属性

鼠标右键user.proto协议文件,选择属性(或者鼠标选中user.proto协议文件,然后按ALT+Enter快捷键打开文件属性窗体),在打开的属性窗体中,将Build Action选项设置为Protobuf compiler,将gRPC Stub Classes选项设置为Client and Server,然后点击应用确定即可,如下图所示:

image

此时,我们双击Quber.Grpc.Common类库项目,在项目文件中,我们会发现有一个Protobuf节点设置,并且该节点中的GrpcServices属性值为Both(Both表示我们刚才选择的Client and ServiceClient表示客户端,Service表示服务端),如下图所示:

image

注意:如果项目的编辑文件中,没有Protobuf节点设置,请手动增加进去,不然到时候在生成的时候不会生成协议文件对应的类文件

2.5、🥪生成项目

此时我们重新生成下Quber.Grpc.Common类库项目,会发现在obj\Debug\net6.0\Protos目录下生成了user.proto协议文件对应的2个类文件,如下图所示:

image

2.6、🍚改造服务端和客户端项目

  1. 改造Quber.Grpc.Service项目

    Quber.Grpc.Service项目中,我们添加对Quber.Grpc.Common类库项目的引用,如下图所示:

    image

    然后我们将Quber.Grpc.Service项目中的整个Protos文件夹删除掉,如下图所示:

    image

    修改UserService.cs服务文件中的命名空间,如下图所示:

    image

    此时我们注意到User.UserBaseUserInfoResultUserInfoRequest都来自我们新建的Quber.Grpc.Common类库项目。

    运行Quber.Grpc.Service项目,如下图所示:

    image

    如上图所示,Quber.Grpc.Service服务端就运行成功了。

  2. 改造Quber.Grpc.Client项目

    Quber.Grpc.Client项目中,我们添加对Quber.Grpc.Common类库项目的引用,如下图所示:

    image

    然后我们将Quber.Grpc.Client项目中的整个Protos文件夹删除掉,如下图所示:

    image

    修改服务文件UserTest.csUserTestIoc.cs以及启动文件Program.cs中的命名空间,如下图所示:

    image

    image

    image

    此时我们注意到User.UserClientUserInfoRequest都来自我们新建的Quber.Grpc.Common类库项目。

    运行Quber.Grpc.Client项目,如下图所示:

    image

    如上图所示,Quber.Grpc.Client客户端就运行成功了。


同理,我们可以将Quber.Grpc.Web项目也按照上述说明进行调整,此处就不一一演示了。

🎉🎉🎉🎉🎉🎉通过上述步骤的演示,我们就达到了客户端和服务端公用一份proto协议文件的目的,就不用在每个项目中新建相同的proto协议文件了,后期只需要维护一份proto协议文件即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用JSON作为序列化协议gRPC通信的客户端服务端的示例,其定义了一个名为`HelloWorld`的简单服务,客户端发送一个名为`name`的字符串,服务端返回一个包含`Hello, name!`的字符串: #### 服务端 ```cpp #include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #include <grpcpp/server.h> #include <grpcpp/server_builder.h> #include <grpcpp/server_context.h> #include "helloworld.grpc.pb.h" using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { std::string prefix("Hello, "); reply->set_message(prefix + request->name()); return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); GreeterServiceImpl service; grpc::EnableDefaultHealthCheckService(true); grpc::reflection::InitProtoReflectionServerBuilderPlugin(); ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); } int main(int argc, char** argv) { RunServer(); return 0; } ``` #### 客户端 ```cpp #include <iostream> #include <memory> #include <string> #include <grpcpp/grpcpp.h> #include <grpcpp/ext/proto_server_reflection_plugin.h> #include <grpcpp/health_check_service_interface.h> #include "helloworld.grpc.pb.h" using grpc::Channel; using grpc::ClientContext; using grpc::Status; using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; class GreeterClient { public: GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} std::string SayHello(const std::string& name) { HelloRequest request; request.set_name(name); HelloReply reply; ClientContext context; std::string serializedRequest, serializedReply; grpc::SerializationTraits<HelloRequest>::serialize(request, &serializedRequest); Status status = stub_->CallRPC("SayHello", serializedRequest, &serializedReply); if (status.ok()) { grpc::SerializationTraits<HelloReply>::deserialize(serializedReply, &reply); return reply.message(); } else { std::cout << "RPC failed: " << status.error_message() << std::endl; return ""; } } private: std::unique_ptr<Greeter::Stub> stub_; }; int main(int argc, char** argv) { std::string name("World"); GreeterClient greeter(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); std::string reply = greeter.SayHello(name); std::cout << "Received: " << reply << std::endl; return 0; } ``` 在这个例子,我们使用了`grpc::SerializationTraits`类将请求和响应对象序列化为JSON字符串。`GreeterClient`类实现了客户端的逻辑,`SayHello`函数发送一个`HelloRequest`对象到服务端,并返回一个包含`Hello, name!`的字符串。在`main`函数,我们使用`CreateChannel`函数创建一个与服务端通信的通道,并使用`GreeterClient`类进行通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值