Configuring .NET Aspire Tests to Use Specific Ports from launchSettings.json
When testing .NET Aspire applications, you can configure your tests to use specific ports from each project's launchSettings.json instead of random ports. Here's how to achieve this:
Solution Approach
1. Create a Port Assignment Helper
First, create a helper class to read and manage port assignments:
public static class LaunchSettingsReader
{
public static int GetPortForProject(string projectName)
{
var launchSettingsPath = Path.Combine(
Directory.GetCurrentDirectory(),
"..", "..", "..", "..", // Adjust path based on your test project location
projectName,
"Properties",
"launchSettings.json");
if (!File.Exists(launchSettingsPath))
{
throw new FileNotFoundException($"launchSettings.json not found for project {projectName}");
}
var launchSettings = JsonSerializer.Deserialize(
File.ReadAllText(launchSettingsPath));
return launchSettings.Profiles[projectName].ApplicationUrl
.Split(';')
.Select(url => new Uri(url))
.First()
.Port;
}
private class LaunchSettings
{
public Dictionary<string, Profile> Profiles { get; set; }
}
private class Profile
{
public string ApplicationUrl { get; set; }
}
}
2. Configure Your Test to Use Specific Ports
Modify your test setup to use the ports from launchSettings.json
:
var appHost = await DistributedApplicationTestingBuilder.CreateAsync();
// Configure ports for each project
var apiPort = LaunchSettingsReader.GetPortForProject("MyApiProject");
var servicePort = LaunchSettingsReader.GetPortForProject("MyServiceProject");
appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
{
clientBuilder.AddStandardResilienceHandler();
});
// Build with explicit port assignments
var app = await appHost.BuildAsync();
await app.StartAsync(new DistributedApplicationOptions
{
Args = new[]
{
"--port", apiPort.ToString(),
"--service-port", servicePort.ToString()
// Add more ports as needed
}
});
// Now the HttpClient will use the configured port
var http = App.CreateHttpClient("myApi");
string url = http.BaseAddress.Authority; // Should now use your configured port
Alternative Approach Using Environment Variables
If you prefer, you can set ports via environment variables in your test setup:
// Set environment variables before creating the app host
Environment.SetEnvironmentVariable("ASPIRE_API_PORT", "5000");
Environment.SetEnvironmentVariable("ASPIRE_SERVICE_PORT", "5001");
var appHost = await DistributedApplicationTestingBuilder.CreateAsync();
// In your AppHost, use these environment variables to configure endpoints
Ensuring Port Availability
To handle cases where ports might be in use:
public static int GetAvailablePort(int preferredPort)
{
var listener = new TcpListener(IPAddress.Loopback, preferredPort);
try
{
listener.Start();
return preferredPort;
}
catch (SocketException)
{
// Port in use, get a random available port
listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
finally
{
listener.Stop();
}
}
Important Notes
- Path Configuration: Adjust the path inÂ
LaunchSettingsReader
 to correctly locate your projects'ÂlaunchSettings.json
 files. - Port Conflicts: Be aware that ports might be in use when running tests in parallel.
- Aspire Version: This solution assumes .NET Aspire preview 5 or later. The API might change in future versions.
- Cleanup: Ensure proper disposal of resources after tests complete to free up ports.