Dịch vụ và client gRPC code-first với .NET
Bởi James Newton-King và Marc Gravell
gRPC code-first sử dụng các kiểu .NET để định nghĩa service (dịch vụ) và message contracts (hợp đồng tin nhắn).
Code-first là lựa chọn tốt khi toàn bộ hệ thống sử dụng .NET:
- Các kiểu service và data contract của .NET có thể được chia sẻ giữa server và client .NET.
- Tránh phải định nghĩa contracts trong các file
.protovà sinh code.
Code-first không được khuyến nghị trong các hệ thống đa ngôn ngữ (polyglot). Các kiểu service và data contract .NET không thể sử dụng với các nền tảng không phải .NET. Để gọi một gRPC service được viết bằng code-first, các nền tảng khác phải tạo một .proto contract phù hợp với service đó.
protobuf-net.Grpc
Quan trọng: Để được trợ giúp về protobuf-net.Grpc, hãy truy cập website protobuf-net.Grpc hoặc tạo issue trên GitHub repository protobuf-net.Grpc.
protobuf-net.Grpc là một dự án cộng đồng và không được Microsoft hỗ trợ chính thức. Nó thêm hỗ trợ code-first vào Grpc.AspNetCore và Grpc.Net.Client. Nó sử dụng các kiểu .NET được chú thích bằng attributes để định nghĩa các gRPC service và message của ứng dụng.
Bước đầu tiên để tạo một gRPC service code-first là định nghĩa code contract (hợp đồng code):
- Tạo một project mới được chia sẻ giữa server và client.
- Thêm tham chiếu package protobuf-net.Grpc.
- Tạo các kiểu service và data contract.
using ProtoBuf.Grpc;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading.Tasks;
namespace Shared.Contracts;
[DataContract]
public class HelloReply
{
[DataMember(Order = 1)]
public string Message { get; set; }
}
[DataContract]
public class HelloRequest
{
[DataMember(Order = 1)]
public string Name { get; set; }
}
[ServiceContract]
public interface IGreeterService
{
[OperationContract]
Task<HelloReply> SayHelloAsync(HelloRequest request,
CallContext context = default);
}Code trên:
- Định nghĩa các message
HelloRequestvàHelloReply. - Định nghĩa interface contract
IGreeterServicevới phương thức gRPC unarySayHelloAsync.
Service contract được triển khai trên server và được gọi từ client.
Các phương thức được định nghĩa trên service interface phải khớp với một số chữ ký nhất định tùy thuộc vào loại:
- Unary
- Server streaming (stream từ server)
- Client streaming (stream từ client)
- Bidirectional streaming (stream hai chiều)
Để biết thêm thông tin về định nghĩa service contracts, xem tài liệu bắt đầu với protobuf-net.Grpc.
Tạo gRPC service code-first
Để thêm gRPC code-first service vào ứng dụng ASP.NET Core:
- Thêm tham chiếu package protobuf-net.Grpc.AspNetCore.
- Thêm tham chiếu đến project shared code-contract.
```xml <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <TargetFramework>net6.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup>
<ItemGroup> <PackageReference Include="protobuf-net.Grpc.AspNetCore" Version="1.0.152" /> </ItemGroup>
<ItemGroup> <ProjectReference Include="..\Shared\Shared.Contracts.csproj" /> </ItemGroup>
</Project> ```
- Tạo file
GreeterService.csmới và triển khai interface serviceIGreeterService:
```csharp using Shared.Contracts; using ProtoBuf.Grpc;
public class GreeterService : IGreeterService { public Task<HelloReply> SayHelloAsync(HelloRequest request, CallContext context = default) { return Task.FromResult( new HelloReply { Message = $"Hello {request.Name}" }); } } ```
- Cập nhật file
Program.cs:
```csharp using ProtoBuf.Grpc.Server;
var builder = WebApplication.CreateBuilder(args);
// Cần cấu hình bổ sung để chạy gRPC thành công trên macOS. // Để biết hướng dẫn cấu hình Kestrel và gRPC clients trên macOS, truy cập https://go.microsoft.com/fwlink/?linkid=2099682
// Thêm services vào container. builder.Services.AddCodeFirstGrpc();
var app = builder.Build();
// Cấu hình HTTP request pipeline. app.MapGrpcService<GreeterService>(); app.MapGet("/", () => "Giao tiếp với gRPC endpoints phải được thực hiện qua gRPC client. Để biết cách tạo client, truy cập: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run(); ```
Code trên:
AddCodeFirstGrpcđăng ký các service cho phép code-first.MapGrpcService<GreeterService>thêm code-first service endpoint.
Các gRPC service được triển khai bằng code-first và .proto files có thể cùng tồn tại trong cùng một ứng dụng. Tất cả gRPC service đều sử dụng cấu hình gRPC service.
Tạo gRPC client code-first
Một gRPC client code-first sử dụng service contract để gọi các gRPC service.
- Trong file
.csprojcủa gRPC client: - Thêm tham chiếu package protobuf-net.Grpc.
- Thêm tham chiếu package Grpc.Net.Client.
- Thêm tham chiếu đến project shared code-contract.
```xml <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup>
<ItemGroup> <PackageReference Include="Grpc.Net.Client" Version="2.52.0" /> <PackageReference Include="protobuf-net.Grpc" Version="1.0.152" /> </ItemGroup>
<ItemGroup> <ProjectReference Include="..\Shared\Shared.Contracts.csproj" /> </ItemGroup>
</Project> ```
- Cập nhật
Program.cscủa client:
```csharp using Grpc.Net.Client; using ProtoBuf.Grpc.Client; using Shared.Contracts;
namespace GrpcGreeterClient;
internal class Program { private static async Task Main(string[] args) { using var channel = GrpcChannel.ForAddress("https://localhost:7184"); var client = channel.CreateGrpcService<IGreeterService>();
var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" });
Console.WriteLine($"Greeting: {reply.Message}"); Console.WriteLine("Nhấn phím bất kỳ để thoát..."); Console.ReadKey(); } } ```
Code Program.cs của gRPC client trên:
- Tạo một gRPC channel.
- Tạo một code-first client từ channel bằng extension method
CreateGrpcService<IGreeterService>. - Gọi gRPC service với
SayHelloAsync.
Một gRPC client code-first được tạo từ một channel. Giống như một client thông thường, một code-first client sử dụng cấu hình channel của nó.