.NET Core微服务开发服务间调用篇-GRPC

在单体应用中,相互调用都是在一个进程内部调用,也就是说调用发生在本机内部,因此也被叫做本地方法调用;在微服务中,服务之间调用就变得比较复杂,需要跨网络调用,他们之间的调用相对于与本地方法调用,可称为远程过程调用,简称RPC(Remote procedure call)。

看过上篇API网关篇,知道案例中包含商品、订单两个微服务,本文将会演示如何采用开源的,高性能rpc框架(grpc),通过订单微服务调用产品微服务内的接口。没有看过上篇文章不影响,我先提供下项目代码结构图,方便你阅读。下面将会一步一步分享如何使用Grpc进行服务之间调用。

步骤1:首先定义服务锲约-proto文件

1.创建类库(.NET Standard),作为服务契约项目,命名为-AAStore.ProductCatalog.DataContracts如图:

2.安装三个nuget包

Google.Protobuf
Grpc
Grpc.Tools

3.开始定义proto文件:product.api.proto

syntax = <span data-raw-text="" "="" data-textnode-index="11" data-index="445" class="character">"proto3<span data-raw-text="" "="" data-textnode-index="11" data-index="452" class="character">";


optioncsharp_namespace = <span data-raw-text="" "="" data-textnode-index="15" data-index="480" class="character">"AAStore.ProductCatalog.Api.V1<span data-raw-text="" "="" data-textnode-index="15" data-index="510" class="character">";
packageAAStore;

serviceProductApi{

rpcGetProduct(GetProductRequest) returns(GetProductResponse);
}

//请求消息体
messageGetProductRequest{
int32Id=1;
}
//返回消息体 
messageGetProductResponse{
stringproductName=1;
}

Grpc协议使用Protobuf简称proto文件来定义接口名、调用参数以及返回值类型。比如product.api.proto文件,定义一个接口GetProduct方法,它的请求结构体是GetProductRequest,包含一个int类型的id属性,它的返回结构体GetProductResponse包含一个输出string类型的产品名称属性。

4.添加product.api.proto文件到项目中,双击项目或者右键-》编辑项目文件,添加一下代码

<ItemGroup>
<Protobuf Include=<span data-raw-text="" "="" data-textnode-index="58" data-index="972" class="character">"..\Schema\grpc\v1\product.api.proto<span data-raw-text="" "="" data-textnode-index="58" data-index="1008" class="character">"GrpcServices=<span data-raw-text="" "="" data-textnode-index="60" data-index="1023" class="character">"Both<span data-raw-text="" "="" data-textnode-index="60" data-index="1028" class="character">"Link=<span data-raw-text="" "="" data-textnode-index="62" data-index="1035" class="character">"product.api.proto<span data-raw-text="" "="" data-textnode-index="62" data-index="1053" class="character">"/>
</ItemGroup>

然后build项目,此时gprc代码已经生成了,在obj文件项目,如图

步骤2:Grpc服务端实现

选择项目AAStore.ProductCatalog(详情见项目代码结构图)安装包Grpc.AspNetCore,同时添加引用项目AAStore.ProductCatalog.DataContracts

<ItemGroup>
<PackageReference Include=<span data-raw-text="" "="" data-textnode-index="74" data-index="1262" class="character">"Grpc.AspNetCore<span data-raw-text="" "="" data-textnode-index="74" data-index="1278" class="character">"Version=<span data-raw-text="" "="" data-textnode-index="76" data-index="1288" class="character">"2.29.0<span data-raw-text="" "="" data-textnode-index="76" data-index="1295" class="character">"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="85" data-index="1356" class="character">"..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj<span data-raw-text="" "="" data-textnode-index="85" data-index="1440" class="character">"/>
</ItemGroup>

然后定义获取产品方法的逻辑和实现,供产品api站点项目调用

publicTask<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context)
{
returnTask.FromResult(newGetProductResponse
{
//todo 具体的逻辑下面代码仅为显示
ProductName = <span data-raw-text="" "="" data-textnode-index="110" data-index="1730" class="character">"测试商品grpc<span data-raw-text="" "="" data-textnode-index="112" data-index="1739" class="character">"
}) ;
}

选择AAStore.ProductCatalog.Api产品api项目添加引用项目AAStore.ProductCatalog

<ItemGroup>
<ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="121" data-index="1871" class="character">"..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj<span data-raw-text="" "="" data-textnode-index="121" data-index="1927" class="character">"/>
</ItemGroup>

新增ProductServices.cs并继承ProductApiBase类,实现grpc服务

public classProductServices : ProductApi.ProductApiBase
{
public override Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context)
{
return newGrpcProductServices().GetProduct(request, context);
}
}

由于AAStore.ProductCatalog.Api项目不是通过grpc模板项目创建的,所以在Startup类中手工添加gprc服务和中间件代码:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddGrpc();
}
 
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<ProductServices>();
endpoints.MapControllers();
});

最后在Program文件配置站点启动监听8081端口,我们并运行它

webBuilder.ConfigureKestrel(options =>
{
// Setup a HTTP/2 endpoint without TLS.
options.ListenLocalhost(8081, o => o.Protocols =
HttpProtocols.Http2);
});

步骤3:Grpc客户端实现-调用Grpc服务

选择AAStore.Orde项目(具体见项目代码结构图),安装Grpc.AspNetCore包,并且添加项目引用AAStore.ProductCatalog.DataContracts

<ItemGroup>
<ProjectReference Include=<span data-raw-text="" "="" data-textnode-index="171" data-index="3123" class="character">"..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj<span data-raw-text="" "="" data-textnode-index="171" data-index="3207" class="character">"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include=<span data-raw-text="" "="" data-textnode-index="180" data-index="3268" class="character">"Grpc.AspNetCore<span data-raw-text="" "="" data-textnode-index="180" data-index="3284" class="character">"Version=<span data-raw-text="" "="" data-textnode-index="182" data-index="3294" class="character">"2.29.0<span data-raw-text="" "="" data-textnode-index="182" data-index="3301" class="character">"/>
</ItemGroup>

新建ProductGateway.cs,封装产品微服务公开grpc服务的调用

publicclassProductGateway
{
privatereadonlyProductApiClient _client;
publicProductGateway()
{
AppContext.SetSwitch(<span data-raw-text="" "="" data-textnode-index="206" data-index="3514" class="character">"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport<span data-raw-text="" "="" data-textnode-index="206" data-index="3573" class="character">", true);
_client = newProductApiClient(GrpcChannel.ForAddress(<span data-raw-text="" "="" data-textnode-index="213" data-index="3648" class="character">"http://localhost:8081<span data-raw-text="" "="" data-textnode-index="213" data-index="3670" class="character">"));//TODO 根据动态配置
}

publicasyncTask<GetProductResponse> GetProduct(GetProductRequest request)
{
returnawait_client.GetProductAsync(request);
}
}

新建OrderService.cs,添加GetOrder方法,在其方法内调用产品微服务GetProduct方法

publicasyncTask<string> GetOrder()
{
varproductModel = await_productGateway.GetProduct(newGetProductRequest() { Id = 1});
return$<span data-raw-text="" "="" data-textnode-index="256" data-index="4081" class="character">"Order Service=>从产品微服务获取产品信息:{productModel.ProductName}<span data-raw-text="" "="" data-textnode-index="259" data-index="4136" class="character">";
}

然后在订单控制器中调用

[Route(<span data-raw-text="" "="" data-textnode-index="264" data-index="4167" class="character">"api/[controller]<span data-raw-text="" "="" data-textnode-index="264" data-index="4184" class="character">")]
[ApiController]
publicclassOrderController: ControllerBase
{
privatereadonlyRestOrderService _restOrderService;
publicOrderController()
{
_restOrderService = newRestOrderService();
}
[HttpGet(template:<span data-raw-text="" "="" data-textnode-index="294" data-index="4451" class="character">"Get<span data-raw-text="" "="" data-textnode-index="294" data-index="4455" class="character">")]
publicasyncTask<string> GetOrder()
{
returnawait_restOrderService.GetOrder();
}
}

至此,客户端代码已经完成,我们运行来看看

通过网关访问订单服务,查看调用结果

我们发现结果也是一样的,以上演示了如何使用grpc进行服务间的调用,最后使用一张图作结。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值