VS2022 开发Grpc ,使用Docker支持
使用VS2022开发遇到了不少坑,记录一下
-
VS貌似没有类似WebService添加接口的模板,需要手动添加.proto文件,而且.proto文件,也没有对应模板,需要添加一个文本文件,改成需要的名字
-
添加完.proto文件,需要用Grpc.Tools编译生成对应所需的文件,使用dotnet add package Grpc.Tools
这里我遇到一个坑,就是添加完了chatGPT告诉我,Grpc会在项目路径下的package里面,但最后查的实际在C盘的全局路径下
C:\Users{用户名}.nuget\packages\grpc.tools\2.58.0\tools\windows_x64 -
安装完之后,将我们找到路径添加到系统环境变量PATH里面
-
接着我们执行编译命令,chatGPT最开始给我的有问题,经过几次反馈最终终于执行成功了
这是最终给我的命令:
protoc --proto_path="D:\{项目路径,包含.csproj文件那个}\Protos" --csharp_out=. --grpc_out=. --plugin=protoc-gen-grpc="C:\Users\{用户名}\.nuget\packages\grpc.tools\2.58.0\tools\windows_x64\grpc_csharp_plugin.exe" "D:\{项目路径,包含.csproj文件那个}\Protos\inventory.proto"
-
添加Service文件
Service文件需要继承刚才工具生成的文件
以我的代码为例
using Grpc.Core;
namespace YourName.Services
{
public class InitialInventoryServiceImpl : InitialInventoryService.InitialInventoryServiceBase
{
public override Task<InitialInventoryResponse> InitialInventory(InitialInventoryRequest request, ServerCallContext context)
{
// ToDo
return Task.FromResult(new InitialInventoryResponse { Result = true });
}
}
}
- 注册服务
app.MapGrpcService<InitialInventoryServiceImpl>();
就这一句
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddGrpc();
// Initialize IOC modules
InitializeIOC.Initialize();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService<InitialInventoryServiceImpl>();
app.Run();
}
}
- 测试GRpc调用
新建控制台程序,然后安装nuget包。
dotnet add package Grpc.Tools
dotnet add package Grpc.Core
dotnet add package Google.Protobuf
接着像service一样通过proto文件生成类文件。这个proto生成的文件可能会导致警告冲突,调整一下结构就好了
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
// 创建gRPC客户端
var client = new InitialInventoryServiceClient(channel);
var testList = FileHelper.ReadTestAsIds();
var sucList = FileHelper.ReadSucAsIds();
testList = testList.Except(sucList).ToList();
foreach(var asId in testList)
{
// 调用服务方法
var reply = client.InitialInventory(
new InitialInventoryRequest { AsId = asId }
);
ConsoleHelper.ShowMessage($"账套{asId}处理{(reply.Result ? "成功" : "失败")}");
if(reply.Result)
{
FileHelper.WriteSucAsId(asId);
}
else
{
FileHelper.WriteErrorAsId(asId);
}
}
8 使用Docker
8.0 启动Docker Desktop
8.1 右键项目添加docker支持
8.2 将生成的docker文件复制到解决方案的根目录,因为dockerfile只能访问他的根目录及子目录
8.3 找到 NuGet.Config,因为公司通常会有私有的nuget包,nuget.config在%AppData%\NuGet\NuGet.Config中应该可以找到
8.4 修改dockerfile,注意大小写,文件名路径会区分大小写
...
# Copy the NuGet configuration file.
COPY NuGet.Config /root/.nuget/NuGet/
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["NuGet.Config", "./"]
...
8.5 执行命令
docker build -t my-service-name .
注意不要把 .丢了
8.6 我在生成的过程中报了个错,因为,我有两个项目都有相同的配置文件,需要先取消一个项目的配置文件输出
error NETSDK1152: Found multiple publish output files with the same relative path:
8.7 保存镜像文件
docker save -o D:\Images\my-service.tar my-service
- 启动docker联调
联调后出现很多问题,主要是https协议引起的,本身,我这个不需要https协议,只是内部调用。所以直接使用http协议就行
本地直接调用grpc没问题,但调用docker的时候,就不行了,需要gRPC 服务配置为允许非加密的 HTTP/2 连接。默认情况下,许多 gRPC 实现只允许通过 HTTPS 使用 HTTP/2。
需要调整一下代码:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://localhost:5001");
//增加下面这句就可以用http调用grpc了
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
docker 常用命令
>docker stop my_container
>docker rm my_container
>docker build -t inv-s-2 .
>docker stop my_container
>docker run -d --name=my_container -p 5001:5001 inv-s-2:latest tail -f /dev/null
>docker exec -it my_container /bin/bash