I am trying to implement an endpoint that acts as a proxy to another endpoint.
Suppose I have the following:
// List Released Projects
[HttpGet("Projects")]
public async Task<ActionResult<List<ProjectAggrDto>>> GetReleasedProjectsAsync(
CancellationToken cancellationToken = default)
{
var query = new GetReleasedProjectsQuery();
return await _sender.Send(query, cancellationToken);
}
// List Released Projects From Central
[HttpGet("ProjectsFromCentral")]
public async Task<ActionResult<List<ProjectAggrDto>>> GetReleasedProjectsFromCentralAsync(
CancellationToken cancellationToken = default)
{
var authorizationHeader = Request.Headers[HeaderNames.Authorization].ToString();
var query = new GetReleasedProjectsFromCentralQuery(authorizationHeader);
return await _sender.Send(query, cancellationToken);
}
So the second endpoint would read an option entry from appsettings.json
to get the 'central' server IP, and would use an IHttpClientFactory
to create a simple HTTP client to communicate with the server, and would just ultimately call the first endpoint, and returning that data back to the user.
To reiterate,
- User send a request to
/api/ProjectsFromCentral
GetReleasedProjectsFromCentralAsync
will create a HTTP client to pass on the request to the first endpoint with the central server's IP:{central_server_ip}/api/Projects
GetReleasedProjectsFromCentralAsync
returns the response ofGetReleasedProjectsAsync
Now, I tried this out with Postman - and it does work as intended. However, I'd like to use this in an integration test. And the integration test uses a TestServer which create an in-memory server instance - however, TestServer's base address of http://localhost/
is not reachable.
public class EnvironmentFixure : IAsyncLifetime
{
private IDockerEnvironment? _environment;
private WebApplicationFactory<Program>? _application;
private string? _connectionString;
private string? _redisConnectionString;
public string ServerUrl { get; private set; }
public WebApplicationFactory<Program> WebApplication { get => _application ?? throw new Exception("Not initialized"); }
public EnvironmentFixure()
{
}
public async Task InitializeAsync()
{
_environment = new DockerEnvironmentBuilder()
.AddContainer(p => p with
{
Name = "test-minio",
ImageName = "minio/minio",
Ports = new Dictionary<ushort, ushort>
{
{ 9000, 9001 },
{ 9090, 9091 },
},
EnvironmentVariables = new Dictionary<string, string>
{
{ "MINIO_ROOT_USER", "admin" },
{ "MINIO_ROOT_PASSWORD", "password" },
},
ExposedPorts = new List<ushort> { 9000, 9090 },
Entrypoint = new List<string> { "minio", "server", "/home/share", "--console-address", ":9090" },
})
.AddRedisContainer(r => r with
{
Name = "test-redis"
})
.AddPostgresContainer(p => p with
{
Name = "test-postgres",
})
.Build();
await _environment.UpAsync();
var minio = _environment.GetContainer("test-minio");
if (minio is not null)
{
var result = await minio.ExecAsync(new string[] { "mc", "mb", "e-exam" });
}
var postgres = _environment.GetContainer<PostgresContainer>("test-postgres");
_connectionString = postgres?.GetConnectionString()
?? throw new ApplicationException("ConnectionString not specified");
var redis = _environment.GetContainer<RedisContainer>("test-redis");
var redisConnectionConfiguration = redis?.GetConnectionConfiguration()
?? throw new ApplicationException("Redis container is not initialized");
_redisConnectionString = $"{redisConnectionConfiguration.Host}:{redisConnectionConfiguration.Port},password={redisConnectionConfiguration.Password}";
_application = new MyWebApplicationFactory
{
ConnectionString = _connectionString,
RedisConnectionString = _redisConnectionString,
};
// ----- HERE --------
ServerUrl = _application.Server.BaseAddress.ToString(); // This returns "http://localhost/", but it doesn't work (I can't connect).
// -------------------
using var scope = _application.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
dbContext.Database.Migrate();
}
public async Task DisposeAsync()
{
await _application!.DisposeAsync();
await _environment!.DownAsync();
await _environment!.DisposeAsync();
}
private class MyWebApplicationFactory : WebApplicationFactory<Program>
{
public required string ConnectionString { get; init; }
public required string RedisConnectionString { get; init; }
protected override IHost CreateHost(IHostBuilder builder)
{
builder.ConfigureHostConfiguration(config =>
{
config.AddJsonFile("appsettings.Test.json", optional: false);
config.AddEnvironmentVariables();
config.AddInMemoryCollection(new Dictionary<string, string>
{
["ConnectionStrings:DefaultConnection"] = ConnectionString,
["RedisConfig:ConnectionString"] = RedisConnectionString,
}!);
});
return base.CreateHost(builder);
}
}
}
So during tests, I wanted the central_server_ip
to be the IP of the created WebApplication
.
Therefore, the tests are failing since it could not reach the "central" server (which in this instance, itself). What can I do here?
I expected the TestServer URL of http://localhost/
to be reachable, but it does not. Therefore, I cannot test if the second endpoint can call the first endpoint.