admin管理员组文章数量:1313001
I am tring to connect to a custom container with a client in an Aspire project. The problem is, the service discovery does not works. My expectation is, that I receive a fully configured httpClient in the LabseClient.LabseTest when the LabseClient is instantieted by the ServiceProvider, but it does not happens. The configuration looks like some default with port 80, so it can not find the service in the container. It should be configured on the fly.
I created a test solution to explicitly demonstrate this specific problem. To reproduce the problem just run the AppHost, and then click one of the endpoints of the apiservice. (downloading the container takes some time, i do not wanted to change it to introduce possible addtional problems)
Here you can find the solution:
.ServiceDiscovery.Problem
For explanation, I copy here the relevant code parts:
Ainizeml.Labse.Hosting project was created for encapsulating the container, and provide a IResourceWithConnectionString implementation. It is necessary for the WithReference call. (or at least currently i think it is necessary)
I followed this example to creating it:
public sealed class LabseResource(string name) : ContainerResource(name), IResourceWithConnectionString
{
internal const string HttpEndpointName = "http";
internal const int LabseRestAPIPort = 8501;
private EndpointReference? _httpReference;
public EndpointReference HttpEndpoint =>
_httpReference ??= new(this, HttpEndpointName);
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create(
$"http://{HttpEndpoint.Property(EndpointProperty.Host)}:{HttpEndpoint.Property(EndpointProperty.Port)}"
);
}
public static class LabseResourceBuilderExtensions
{
public static IResourceBuilder<LabseResource> AddLabse(
this IDistributedApplicationBuilder builder,
string name,
int? httpPort = null)
{
var resource = new LabseResource(name);
return builder.AddResource(resource)
.WithImage(LabseContainerImageTags.Image)
.WithImageRegistry(LabseContainerImageTags.Registry)
.WithImageTag(LabseContainerImageTags.Tag)
.WithHttpEndpoint(
targetPort: LabseResource.LabseRestAPIPort,
port: httpPort,
name: LabseResource.HttpEndpointName);
}
}
internal static class LabseContainerImageTags
{
internal const string Registry = "docker.io";
internal const string Image = "ainizeml/labse";
internal const string Tag = "latest";
}
The Aspire.ServiceDiscovery.AppHost Program.cs contains only the definitions for the container and the project, linked together.
using Ainizeml.Labse.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var labseModel = builder.AddLabse("labse");
var apiService = builder.AddProject<Projects.Aspire_ServiceDiscovery_WebAPI>("apiservice")
.WithReference(labseModel)
.WaitFor(labseModel);
builder.Build().Run();
The Aspire.ServiceDiscovery.ServiceDefaults project is auto generated by the Aspire VS project template.
In the Aspire.ServiceDiscovery.WebAPI project the LabseTest class was created as the service class for the request. The problem with the HttpClient configuration (or lack of it) appears here.
internal class LabseClient(HttpClient httpClient)
{
public async Task<string> LabseTest()
{
try
{
var response = await httpClient.GetAsync("/v1/models/ainize/metadata");
return response.ToString();
}
catch (Exception ex)
{
return ex.Message;
}
}
}
The service app builder configuration in the WebAPI Program.cs looks like this
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();
builder.Services.AddHttpClient<LabseClient>(
static (client) =>
{
client.BaseAddress = new Uri("http://labse");
}
);
var app = builder.Build();
app.UseExceptionHandler();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", (LabseClient labseClient) => labseClient.LabseTest());
app.MapDefaultEndpoints();
app.Run();
What I am doing wrong?
I am tring to connect to a custom container with a client in an Aspire project. The problem is, the service discovery does not works. My expectation is, that I receive a fully configured httpClient in the LabseClient.LabseTest when the LabseClient is instantieted by the ServiceProvider, but it does not happens. The configuration looks like some default with port 80, so it can not find the service in the container. It should be configured on the fly.
I created a test solution to explicitly demonstrate this specific problem. To reproduce the problem just run the AppHost, and then click one of the endpoints of the apiservice. (downloading the container takes some time, i do not wanted to change it to introduce possible addtional problems)
Here you can find the solution:
https://github/MiklosPathy/Aspire.ServiceDiscovery.Problem
For explanation, I copy here the relevant code parts:
Ainizeml.Labse.Hosting project was created for encapsulating the container, and provide a IResourceWithConnectionString implementation. It is necessary for the WithReference call. (or at least currently i think it is necessary)
I followed this example to creating it:
https://learn.microsoft/en-us/dotnet/aspire/extensibility/custom-hosting-integration?tabs=windows
public sealed class LabseResource(string name) : ContainerResource(name), IResourceWithConnectionString
{
internal const string HttpEndpointName = "http";
internal const int LabseRestAPIPort = 8501;
private EndpointReference? _httpReference;
public EndpointReference HttpEndpoint =>
_httpReference ??= new(this, HttpEndpointName);
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create(
$"http://{HttpEndpoint.Property(EndpointProperty.Host)}:{HttpEndpoint.Property(EndpointProperty.Port)}"
);
}
public static class LabseResourceBuilderExtensions
{
public static IResourceBuilder<LabseResource> AddLabse(
this IDistributedApplicationBuilder builder,
string name,
int? httpPort = null)
{
var resource = new LabseResource(name);
return builder.AddResource(resource)
.WithImage(LabseContainerImageTags.Image)
.WithImageRegistry(LabseContainerImageTags.Registry)
.WithImageTag(LabseContainerImageTags.Tag)
.WithHttpEndpoint(
targetPort: LabseResource.LabseRestAPIPort,
port: httpPort,
name: LabseResource.HttpEndpointName);
}
}
internal static class LabseContainerImageTags
{
internal const string Registry = "docker.io";
internal const string Image = "ainizeml/labse";
internal const string Tag = "latest";
}
The Aspire.ServiceDiscovery.AppHost Program.cs contains only the definitions for the container and the project, linked together.
using Ainizeml.Labse.Hosting;
var builder = DistributedApplication.CreateBuilder(args);
var labseModel = builder.AddLabse("labse");
var apiService = builder.AddProject<Projects.Aspire_ServiceDiscovery_WebAPI>("apiservice")
.WithReference(labseModel)
.WaitFor(labseModel);
builder.Build().Run();
The Aspire.ServiceDiscovery.ServiceDefaults project is auto generated by the Aspire VS project template.
In the Aspire.ServiceDiscovery.WebAPI project the LabseTest class was created as the service class for the request. The problem with the HttpClient configuration (or lack of it) appears here.
internal class LabseClient(HttpClient httpClient)
{
public async Task<string> LabseTest()
{
try
{
var response = await httpClient.GetAsync("/v1/models/ainize/metadata");
return response.ToString();
}
catch (Exception ex)
{
return ex.Message;
}
}
}
The service app builder configuration in the WebAPI Program.cs looks like this
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();
builder.Services.AddHttpClient<LabseClient>(
static (client) =>
{
client.BaseAddress = new Uri("http://labse");
}
);
var app = builder.Build();
app.UseExceptionHandler();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.MapGet("/", (LabseClient labseClient) => labseClient.LabseTest());
app.MapDefaultEndpoints();
app.Run();
What I am doing wrong?
Share Improve this question asked Feb 1 at 18:17 Miklós PathyMiklós Pathy 211 silver badge4 bronze badges1 Answer
Reset to default 1I got an answer for this in the Aspire Github repo. If no connection string is necessary, simpler if the IResourceWithServiceDiscovery
is implemented instead of the IResourceWithConnectionString
. (LabseResource
class in my case) IResourceWithServiceDiscovery
also has an implementation of the WithReference
extension method.
Unfortunatelly no mention about IResourceWithServiceDiscovery
in the hosting integration example in the docs, so it can be a bit misleading.
本文标签: Service Discovery for custom container in NET AspireStack Overflow
版权声明:本文标题:Service Discovery for custom container in .NET Aspire - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741867455a2401996.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论