使用WebHostFactory HttpClient测试.NET Core API时出现404错误
问题:ASP.NET Core集成测试中API端点返回404 Not Found
我用WebHostFactory为ASP.NET Core应用搭建集成测试,已配置带自定义认证和内存数据库的测试服务器,此前的401未授权问题通过模拟认证解决,但当前调用API端点时持续返回404 Not Found。相关代码如下:
测试类代码
public class MyIntegrationTests : IClassFixture<WebApplicationFactory<Startup>> { private readonly HttpClient _client; public MyIntegrationTests(WebApplicationFactory<Startup> factory) { _client = factory.WithWebHostBuilder(builder => { builder.ConfigureServices(services => { var descriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions<AppDbContext>)); services.Remove(descriptor); services.AddDbContext<AppDbContext>(options => { options.UseInMemoryDatabase("InMemoryDbForTesting"); }); services.AddAuthentication("Test") .AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", options => { }); }); builder.Configure(app => { app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); app.UseMiddleware<MockAuthenticationMiddleware>(); }); }) .CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false, }); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test"); } }
控制器代码
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; [AllowAnonymous] [Route("api/[controller]")] public class WeatherForecastController : ControllerBase { [HttpGet("GetToday")] public IActionResult Get() { return Ok(new { Weather = "Sunny" }); } }
测试调用代码
[Given("the second number is (.*)")] public async Task GivenTheSecondNumberIs(int number) { _response = await _client.GetAsync("/api/WeatherForecast/GetToday"); _response.EnsureSuccessStatusCode(); var content = await _response.Content.ReadAsStringAsync(); Assert.True(_response.IsSuccessStatusCode); }
排查与解决思路
1. 修正中间件顺序
你将MockAuthenticationMiddleware放在了UseEndpoints之后,这会导致该中间件无法参与请求处理——端点匹配完成后,后续中间件不会再被执行。调整中间件顺序,将其移至UseAuthentication与UseAuthorization之间(或至少在UseEndpoints之前):
builder.Configure(app => { app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseMiddleware<MockAuthenticationMiddleware>(); // 调整位置 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); });
2. 确认控制器路由与程序集引用
- 控制器路由
api/[controller]结合动作路由GetToday,完整路径/api/WeatherForecast/GetToday是正确的,但需确保测试项目已引用Web项目,且WebApplicationFactory<Startup>使用的是Web项目中的Startup类,保证控制器程序集被正确加载。 - 如果原项目
Startup中存在额外路由配置(如MapControllerRoute),测试配置需同步保留,避免覆盖核心路由逻辑。
3. 避免完全重写中间件管道
若无需完全替换原项目的中间件配置,可改为在原管道基础上添加自定义中间件,而非重写整个Configure方法:
builder.Configure(app => { // 仅添加需要的自定义中间件,复用原项目的管道配置 app.UseMiddleware<MockAuthenticationMiddleware>(); });
4. 验证端点注册状态
可在测试代码中添加日志或打印逻辑,确认测试服务器是否正确注册了控制器端点:
var server = factory.WithWebHostBuilder(...).Server; var endpointDataSource = server.Services.GetService<IEnumerable<EndpointDataSource>>()?.FirstOrDefault(); if (endpointDataSource != null) { foreach (var endpoint in endpointDataSource.Endpoints) { Console.WriteLine(endpoint.DisplayName); } }
若未找到WeatherForecastController.Get相关端点,说明控制器未被正确注册,需检查项目引用或Startup类的控制器扫描配置。
内容的提问来源于stack exchange,提问作者Hasan Kanaan
相关产品推荐
相关产品推荐

