使用 .NET 的代码优先 gRPC 服务和客户端
作者:James Newton-King 和 Marc Gravell
代码优先 gRPC 使用 .NET 类型来定义服务和消息协定。
当整个系统使用 .NET 时,代码优先是一个不错的选择:
- 可以在 .NET 服务器和客户端之间共享 .NET 服务和数据协定类型。
- 无需在
.proto
文件和代码生成过程中定义协定。
不建议在具有多种语言的 polyglot 系统中使用代码优先。 .NET 服务和数据协定类型不能与非 .NET 平台一起使用。 其他平台若要调用使用代码优先编写的 gRPC 服务,必须创建一个与该服务匹配的 .proto
协定。
protobuf-net.Grpc
重要
有关 protobuf-net.Grpc 的帮助信息,请访问 protobuf-net.Grpc 网站或在 protobuf-net.Grpc GitHub 存储库上创建一个问题。
protobuf-net.Grpc 是一个社区项目,不受 Microsoft 支持。 它将对 Grpc.AspNetCore
和 Grpc.Net.Client
添加代码优先支持。 它使用通过属性批注的 .NET 类型来定义应用的 gRPC 服务和消息。
创建代码优先 gRPC 服务的第一步是定义代码协定:
- 创建一个将由服务器和客户端共享的新项目。
- 添加一个 protobuf-net.Grpc 包引用。
- 创建服务和数据协定类型。
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);
}
前面的代码:
- 定义
HelloRequest
和HelloReply
消息。 - 使用一元
SayHelloAsync
gRPC 方法定义IGreeterService
协定接口。
服务协定在服务器上实现并从客户端调用。
在服务接口上定义的方法必须与某些签名匹配,具体取决于它们的流式处理类型:
- 一元
- 服务器流式处理
- 客户端流式处理
- 双向流式传输
有关定义服务协定的详细信息,请参阅 protobuf-net.Grpc 入门文档。
创建代码优先 gRPC 服务
若要将 gRPC 代码优先服务添加到 ASP.NET Core 应用,请执行以下步骤:
添加一个 protobuf-net.Grpc.AspNetCore 包引用。
添加一个对共享代码协定项目的引用。
<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>
创建一个新的
GreeterService.cs
文件并实现IGreeterService
服务接口: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}" }); } }
更新
Program.cs
文件:using ProtoBuf.Grpc.Server; var builder = WebApplication.CreateBuilder(args); // Additional configuration is required to successfully run gRPC on macOS. // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682 // Add services to the container. builder.Services.AddCodeFirstGrpc(); var app = builder.Build(); // Configure the HTTP request pipeline. app.MapGrpcService<GreeterService>(); app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); app.Run();
前面突出显示的代码更新以下内容:
AddCodeFirstGrpc
注册启用了代码优先的服务。MapGrpcService<GreeterService>
添加代码优先的服务终结点。
使用代码优先和 .proto
文件实现的 gRPC 服务可在同一应用中共存。 所有 gRPC 服务都使用 gRPC 服务配置。
创建代码优先 gRPC 客户端
代码优先 gRPC 客户端使用服务协定来调用 gRPC 服务。
在 gRPC 客户端
.csproj
文件中:- 添加一个 protobuf-net.Grpc 包引用。
- 添加 Grpc.Net.Client 包引用。
- 添加一个对共享代码协定项目的引用。
<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>
<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>
更新客户端
program.cs
// See https://aka.ms/new-console-template for more information 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("Press any key to exit..."); Console.ReadKey(); } }
前面的 gRPC 客户端 Program.cs
代码执行以下操作:
- 创建一个 gRPC 通道。
- 使用
CreateGrpcService<IGreeterService>
扩展方法从通道创建代码优先客户端。 - 使用
SayHelloAsync
调用 gRPC 服务。
代码优先 gRPC 客户端是通过通道创建的。 与常规客户端一样,代码优先客户端使用其通道配置。
其他资源
代码优先 gRPC 使用 .NET 类型来定义服务和消息协定。
当整个系统使用 .NET 时,代码优先是一个不错的选择:
- 可以在 .NET 服务器和客户端之间共享 .NET 服务和数据协定类型。
- 无需在
.proto
文件和代码生成过程中定义协定。
不建议在具有多种语言的 polyglot 系统中使用代码优先。 .NET 服务和数据协定类型不能与非 .NET 平台一起使用。 其他平台若要调用使用代码优先编写的 gRPC 服务,必须创建一个与该服务匹配的 .proto
协定。
protobuf-net.Grpc
重要
有关 protobuf-net.Grpc 的帮助信息,请访问 protobuf-net.Grpc 网站或在 protobuf-net.Grpc GitHub 存储库上创建一个问题。
protobuf-net.Grpc 是一个社区项目,不受 Microsoft 支持。 它将对 Grpc.AspNetCore
和 Grpc.Net.Client
添加代码优先支持。 它使用通过属性批注的 .NET 类型来定义应用的 gRPC 服务和消息。
创建代码优先 gRPC 服务的第一步是定义代码协定:
- 创建一个将由服务器和客户端共享的新项目。
- 添加一个 protobuf-net.Grpc 包引用。
- 创建服务和数据协定类型。
[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);
}
前面的代码:
- 定义
HelloRequest
和HelloReply
消息。 - 使用一元
SayHelloAsync
gRPC 方法定义IGreeterService
协定接口。
服务协定在服务器上实现并从客户端调用。 在服务接口上定义的方法必须与某些签名匹配,具体取决于它们是一元、服务器流式处理、客户端流式处理还是双向流式处理。
有关定义服务协定的详细信息,请参阅 protobuf-net.Grpc 入门文档。
创建代码优先 gRPC 服务
若要将 gRPC 代码优先服务添加到 ASP.NET Core 应用,请执行以下步骤:
- 添加一个 protobuf-net.Grpc.AspNetCore 包引用。
- 添加一个对共享代码协定项目的引用。
创建一个新的 GreeterService.cs
文件并实现 IGreeterService
服务接口:
public class GreeterService : IGreeterService
{
public Task<HelloReply> SayHelloAsync(HelloRequest request, CallContext context = default)
{
return Task.FromResult(
new HelloReply
{
Message = $"Hello {request.Name}"
});
}
}
更新 Startup.cs
文件:
public void ConfigureServices(IServiceCollection services)
{
services.AddCodeFirstGrpc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();
});
}
在上述代码中:
AddCodeFirstGrpc
注册启用了代码优先的服务。MapGrpcService<GreeterService>
添加代码优先的服务终结点。
使用代码优先和 .proto
文件实现的 gRPC 服务可在同一应用中共存。 所有 gRPC 服务都使用 gRPC 服务配置。
创建代码优先 gRPC 客户端
代码优先 gRPC 客户端使用服务协定来调用 gRPC 服务。 若要使用代码优先客户端调用 gRPC 服务,请执行以下步骤:
- 添加一个 protobuf-net.Grpc 包引用。
- 添加一个对共享代码协定项目的引用。
- 添加 Grpc.Net.Client 包引用。
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = channel.CreateGrpcService<IGreeterService>();
var reply = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
Console.WriteLine($"Greeting: {reply.Message}");
前面的代码:
- 创建一个 gRPC 通道。
- 使用
CreateGrpcService<IGreeterService>
扩展方法从通道创建代码优先客户端。 - 使用
SayHelloAsync
调用 gRPC 服务。
代码优先 gRPC 客户端是通过通道创建的。 与常规客户端一样,代码优先客户端使用其通道配置。
其他资源
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈