Reputation: 1
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.com/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.com/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?
Upvotes: 0
Views: 108
Reputation: 1
I 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.
Upvotes: 0