.NET Core微服務開發服務間呼叫篇-GRPC

李明成發表於2020-07-16

在單體應用中,相互呼叫都是在一個程式內部呼叫,也就是說呼叫發生在本機內部,因此也被叫做本地方法呼叫;在微服務中,服務之間呼叫就變得比較複雜,需要跨網路呼叫,他們之間的呼叫相對於與本地方法呼叫,可稱為遠端過程呼叫,簡稱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 = "proto3";

option csharp_namespace = "AAStore.ProductCatalog.Api.V1"; 
package AAStore;

service ProductApi{

rpc GetProduct(GetProductRequest) returns (GetProductResponse);
}

//請求訊息體
message GetProductRequest{
int32 Id=1;
}
//返回訊息體 
message GetProductResponse{
string productName=1;
}

Grpc協議使用Protobuf簡稱proto檔案來定義介面名、呼叫引數以及返回值型別。比如product.api.proto檔案,定義一個介面GetProduct方法,它的請求結構體是GetProductRequest,包含一個int型別的id屬性,它的返回結構體GetProductResponse包含一個輸出string型別的產品名稱屬性。

4.新增product.api.proto檔案到專案中,雙擊專案或者右鍵-》編輯專案檔案,新增一下程式碼

<ItemGroup>
<ProjectReference Include="..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj" />
</ItemGroup>
然後build專案,此時gprc程式碼已經生成了,在obj檔案專案,如圖

步驟2:Grpc服務端實現

選擇專案AAStore.ProductCatalog(詳情見專案程式碼結構圖)安裝包Grpc.AspNetCore,同時新增引用專案AAStore.ProductCatalog.DataContracts

<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.29.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj" />
</ItemGroup>
然後定義獲取產品方法的邏輯和實現,供產品api站點專案呼叫
   public class GrpcProductServices
    {
        public Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context)
        {
            return Task.FromResult(new GetProductResponse
            {
                //todo 具體的邏輯 下面程式碼僅為顯示
                ProductName = "測試商品grpc"
            }) ;
        }
    }

選擇AAStore.ProductCatalog.Api產品api專案新增引用專案AAStore.ProductCatalog

  <ItemGroup>
    <ProjectReference Include="..\AAStore.ProductCatalog\AAStore.ProductCatalog.csproj" />
  </ItemGroup>

新增ProductServices.cs並繼承ProductApiBase類,實現grpc服務

    public class ProductServices : ProductApi.ProductApiBase
    {
        public override Task<GetProductResponse> GetProduct(GetProductRequest request, ServerCallContext context)
        {
            return new GrpcProductServices().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="..\AAStore.ProductCatalog.DataContracts\AAStore.ProductCatalog.DataContracts.csproj" />
</ItemGroup>

新建ProductGateway.cs,封裝產品微服務公開grpc服務的呼叫

public class ProductGateway
{
private readonly ProductApiClient _client;
public ProductGateway()
{
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
_client = new ProductApiClient(GrpcChannel.ForAddress("http://localhost:8081"));//TODO 根據動態配置
}

public async Task<GetProductResponse> GetProduct(GetProductRequest request)
{
return await _client.GetProductAsync(request);
}
}

新建OrderService.cs,新增GetOrder方法,在其方法內呼叫產品微服務GetProduct方法

   public async Task<string> GetOrder()
        {
            var productModel = await _productGateway.GetProduct(new GetProductRequest() { Id = 1 });
            return $"Order Service=>從產品微服務獲取產品資訊:{productModel.ProductName}";
        }

然後在訂單控制器中呼叫

[Route("api/[controller]")]
    [ApiController]
    public class OrderController : ControllerBase
    {
        private readonly RestOrderService _restOrderService;
        public OrderController() 
        {
            _restOrderService = new RestOrderService();
        }
        [HttpGet(template:"Get")]
        public async Task<string> GetOrder()
        {
            return await _restOrderService.GetOrder();
        }
    }

至此,客戶端程式碼已經完成,我們執行來看看

通過閘道器訪問訂單服務,檢視呼叫結果

我們發現結果也是一樣的,以上演示瞭如何使用grpc進行服務間的調,最後使用一張圖作結。

相關文章