我目前正在尝试 .NET Aspire。 根据文档,Aspire 用于简化应用程序中服务之间的连接和通信。 Aspire 提供的功能之一是通过为每个服务提供一个可以通过它们解析的特殊名称来简化服务之间的通信,从而无需手动设置端口并匹配地址来使服务连接。
在 .NET Aspire 快速入门文档中,是否解释了您可以在
AppHost
项目的 Program.cs
文件中为项目设置自定义名称,如下所示:
var builder = DistributedApplication.CreateBuilder (args);
var usersApi = builder
.AddProject<Projects.Bargeh_Users_API> ("usersapi"); // Setting the name "usersapi" to the project
builder.AddProject<Projects.Bargeh_Main_Wapp> ("bargehmainwapp")
.WithReference (usersApi)
.WithReference (smsApi)
.WithLaunchProfile ("https");
builder.Build ().Run ();
再次从文档中,您可以在想要访问其他服务的项目中添加此代码,并让 Aspire 知道您需要该服务并为您解析该 URL:
builder.Services.AddHttpClient<UsersApiHttpClientProvider>(
static client=> client.BaseAddress = new("http://usersapi"));
然后,您可以将
UsersApiHttpClientProvider
注入任何您想要的地方并使用它。
此方法有效,但仅适用于访问对普通 HTTP 请求开放的 API。问题是,我使用的
UsersApi
不是 REST API,而是 GRPC 服务。我可以连接到 API 并向其发送请求,但无法发送真正的 GRPC 请求。
我的问题是,如何让我的客户端项目(在本例中为 Blazor Web 应用程序)使用
Grpc.Net
包连接到我的后端 GRPC 服务,而它们之间的连接是由 .NET Aspire 建立的?
所以,经过两天的调查,与现有模块的实现进行比较以及大量的尝试,我想我想出了应该如何做。
我的 AppHost 代码如下所示:
using System.Net.Sockets;
var builder = DistributedApplication.CreateBuilder(args);
var server = builder.AddProject<Projects.Server>("server");
var apiservice = builder.AddProject<Projects.AspireHost_ApiService>("apiservice")
.WithReference(server);
builder.AddProject<Projects.AspireHost_Web>("webfrontend")
.WithReference(apiservice);
builder.Build().Run();
这里
Projects.Server
是一个带有Grpc服务器的应用程序。
现在是最棘手的部分。在分析了 MS 用于连接 Sql Server 等其他服务的方法之后,我可以得出结论,它们使用不同的
*Annotation
类,这些类能够将资源(在我的例子中是项目引用)转换为真实的连接字符串,例如从启动设置或 IP +来自运行容器的端口或一些静态值。
根据注释生成的连接字符串可以作为连接字符串传递,也可以作为
services__<registration name>__<index>
作为环境变量传递。
两者都可以从
IConfiguration
读取,因为默认应用程序构建器默认连接环境变量配置源。
例如,.AddSqlServerContainer(...)
和 .AddSqlServerConnection(...)
Produce 会生成具有注册名称的连接字符串。
.WithReference(<project>)
生成服务注释。所以你必须寻找像下面这样的连接字符串
_configuration.GetValue<string>("services:service:1")
作为替代方案,您可以使用选项模式方法进行绑定。 已经实现的客户端代码使用绑定到某个特定部分来选择主要设置集并将它们放入 Settings 类中,然后使用
.GetConnectionString()
类上的 IConfiguration
方法手动解析连接字符串,然后将连接字符串分配给 Settings 类。
所以我的结论是Grpc通道和客户端应该构建为
IConfiguration configuration = ???;
var conntectionString = configuration.GetValue<string>("services:service:1");
using var channel = GrpcChannel.ForAddress(conntectionString );
var client = new Greeter.GreeterClient(channel);
...
工厂或其他机制可以根据您的口味进行加工。
重要提示:对我来说
.WithReference()
会产生两个连接字符串,例如:
services__server__0 http://_http.localhost:55224
services__server__1 http://localhost:55224
第一个问题无法在本地使用,无法解决。第二个包含的端口与我在 Aspire UI 中看到的端口以及您在
launchSettings.json
中看到的端口不同,但它确实有效。我还不明白为什么我有两个网址,但至少我可以手动达到正确的峰值,或者跳过以 http://_http
开头的一个
理论上,在
.WithAnotation()
中添加注册项目后,您可以使用 Host
添加自己的注释,或者以相同的方法重新使用现有注释。例如,该注释还可能生成连接字符串,您将能够使用该连接字符串。
希望对你有帮助。