使用 C# 的 gRPC 服务gRPC services with C#

本文档概述在 C# 中编写 gRPC 应用所需的概念。This document outlines the concepts needed to write gRPC apps in C#. 此处涵盖的主题适用于基于 C-core 和基于 ASP.NET Core 的 gRPC 应用。The topics covered here apply to both C-core-based and ASP.NET Core-based gRPC apps.

警告

Azure 应用服务或 IIS 当前不支持 ASP.NET Core gRPCASP.NET Core gRPC is not currently supported on Azure App Service or IIS. Http.Sys 的 HTTP/2 实现不支持 gRPC 依赖的 HTTP 响应尾随标头。The HTTP/2 implementation of Http.Sys does not support HTTP response trailing headers which gRPC relies on. 有关详细信息,请参阅此 GitHub 问题For more information, see this GitHub issue.

proto 文件proto file

gRPC 使用协定优先方法进行 API 开发。gRPC uses a contract-first approach to API development. 默认情况下,协议缓冲区 (protobuf) 用作接口定义语言 (IDL)。Protocol buffers (protobuf) are used as the Interface Definition Language (IDL) by default. *.proto 文件包含:The *.proto file contains:

  • gRPC 服务的定义。The definition of the gRPC service.
  • 在客户端与服务器之间发送的消息。The messages sent between clients and servers.

有关 protobuf 文件语法的详细信息,请参阅 为 .NET 应用创建 Protobuf 消息For more information on the syntax of protobuf files, see 为 .NET 应用创建 Protobuf 消息.

例如,请考虑开始使用 gRPC 服务中使用的 greet.proto 文件:For example, consider the greet.proto file used in Get started with gRPC service:

  • 定义 Greeter 服务。Defines a Greeter service.
  • Greeter 服务定义 SayHello 调用。The Greeter service defines a SayHello call.
  • SayHello 发送 HelloRequest 消息并接收 HelloReply 消息:SayHello sends a HelloRequest message and receives a HelloReply message:
syntax = "proto3";

option csharp_namespace = "GrpcGreeter";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

若要查看翻译为非英语语言的代码注释,请在 此 GitHub 讨论问题中告诉我们。If you would like to see code comments translated to languages other than English, let us know in this GitHub discussion issue.

将 .proto 文件添加到 C# 应用Add a .proto file to a C# app

通过将 *.proto 文件添加到 <Protobuf> 项组中,可将该文件包含在项目中:The *.proto file is included in a project by adding it to the <Protobuf> item group:

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

默认情况下,<Protobuf> 引用将生成具体的客户端和服务基类。By default, a <Protobuf> reference generates a concrete client and a service base class. 可使用引用元素的 GrpcServices 特性来限制 C# 资产生成。The reference element's GrpcServices attribute can be used to limit C# asset generation. 有效 GrpcServices 选项如下:Valid GrpcServices options are:

  • Both(如果不存在,则为默认值)Both (default when not present)
  • Server
  • Client
  • None

.proto 文件的 C# 工具支持C# Tooling support for .proto files

需要工具包 Grpc.Tools 才能从 *.proto 文件生成 C# 资产。The tooling package Grpc.Tools is required to generate the C# assets from *.proto files. 生成的资产(文件):The generated assets (files):

  • 在每次生成项目时按需生成。Are generated on an as-needed basis each time the project is built.
  • 不会添加到项目中或是签入到源代码管理中。Aren't added to the project or checked into source control.
  • 是包含在 obj 目录中的生成工件。Are a build artifact contained in the obj directory.

服务器和客户端项目都需要此包。This package is required by both the server and client projects. Grpc.AspNetCore 元包中包含对 Grpc.Tools 的引用。The Grpc.AspNetCore metapackage includes a reference to Grpc.Tools. 服务器项目可以使用 Visual Studio 中的包管理器或通过将 <PackageReference> 添加到项目文件来添加 Grpc.AspNetCoreServer projects can add Grpc.AspNetCore using the Package Manager in Visual Studio or by adding a <PackageReference> to the project file:

<PackageReference Include="Grpc.AspNetCore" Version="2.28.0" />

客户端项目应直接引用 Grpc.Tools 以及使用 gRPC 客户端所需的其他包。Client projects should directly reference Grpc.Tools alongside the other packages required to use the gRPC client. 运行时不需要工具包,因此依赖项标记为 PrivateAssets="All"The tooling package isn't required at runtime, so the dependency is marked with PrivateAssets="All":

<PackageReference Include="Google.Protobuf" Version="3.11.4" />
<PackageReference Include="Grpc.Net.Client" Version="2.28.0" />
<PackageReference Include="Grpc.Tools" Version="2.28.1">

生成的 C# 资产Generated C# assets

工具包会生成表示在所包含 *.proto 文件中定义的消息的 C# 类型。The tooling package generates the C# types representing the messages defined in the included *.proto files.

对于服务器端资产,会生成抽象服务基类型。For server-side assets, an abstract service base type is generated. 基类型包含 .proto 文件中包含的所有 gRPC 调用的定义。The base type contains the definitions of all the gRPC calls contained in the .proto file. 创建一个派生自此基类型并为 gRPC 调用实现逻辑的具体服务实现。Create a concrete service implementation that derives from this base type and implements the logic for the gRPC calls. 对于 greet.proto(前面所述的示例),会生成一个包含虚拟 SayHello 方法的抽象 GreeterBase 类型。For the greet.proto, the example described previously, an abstract GreeterBase type that contains a virtual SayHello method is generated. 具体实现 GreeterService 会替代该方法,并实现处理 gRPC 调用的逻辑。A concrete implementation GreeterService overrides the method and implements the logic handling the gRPC call.

public class GreeterService : Greeter.GreeterBase
{
    private readonly ILogger<GreeterService> _logger;
    public GreeterService(ILogger<GreeterService> logger)
    {
        _logger = logger;
    }

    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = "Hello " + request.Name
        });
    }
}

对于客户端资产,会生成一个具体客户端类型。For client-side assets, a concrete client type is generated. .proto 文件中的 gRPC 调用会转换为具体类型中的方法,可以进行调用。The gRPC calls in the .proto file are translated into methods on the concrete type, which can be called. 对于 greet.proto(前面所述的示例),会生成一个 GreeterClient 类型。For the greet.proto, the example described previously, a concrete GreeterClient type is generated. 调用 GreeterClient.SayHelloAsync 以发起对服务器的 gRPC 调用。Call GreeterClient.SayHelloAsync to initiate a gRPC call to the server.

static async Task Main(string[] args)
{
    // The port number(5001) must match the port of the gRPC server.
    using var channel = GrpcChannel.ForAddress("https://localhost:5001");
    var client =  new Greeter.GreeterClient(channel);
    var reply = await client.SayHelloAsync(
                      new HelloRequest { Name = "GreeterClient" });
    Console.WriteLine("Greeting: " + reply.Message);
    Console.WriteLine("Press any key to exit...");
    Console.ReadKey();
}

默认情况下,会为 <Protobuf> 项组中包含的每个 *.proto 文件都生成服务器和客户端资产。By default, server and client assets are generated for each *.proto file included in the <Protobuf> item group. 若要确保服务器项目中仅生成服务器资产,请将 GrpcServices 属性设置为 ServerTo ensure only the server assets are generated in a server project, the GrpcServices attribute is set to Server.

<ItemGroup>
  <Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>

同样,该属性在客户端项目中设置为 ClientSimilarly, the attribute is set to Client in client projects.

其他资源Additional resources