Blazor WASM部分API接口调用失败,返回index.html问题排查
问题:Blazor WASM调用部分API返回HTML导致JSON序列化异常
我有一个ASP.NET Core托管的Blazor WASM页面,调用托管应用内的API获取数据时,部分接口正常,但修改为新的WorkOrderController后,调用/api/workOrder/{Id}会抛出JSON序列化异常:
Unhandled exception rendering component: '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
实际服务器返回的是WASM应用的index.html内容。
正常工作的代码示例
CompanyController代码
[Authorize] [ApiController] [Route("api/[controller]")] public class CompanyController : ControllerBase { private readonly ApplicationDbContext _context; public CompanyController(ApplicationDbContext context) { _context = context; } [HttpGet("{id}")] public async Task<IActionResult> Get(long id) { Company? company = await _context.Companies.FindAsync(id); if (company == null) { return NotFound(); } return Ok(company); } }
对应的Blazor页面代码
@page "/companies/{id:long}" @attribute [Authorize] @inject HttpClient Http @inject NavigationManager Nav @if (company != null) { <div>@company.Name</div> } else { <div>Loading Company...</div> } @code { private Company? company; [Parameter] public long Id { get; set; } protected override async Task OnInitializedAsync() { try { company = await Http.GetFromJsonAsync<Company>($"/api/company/{Id}"); } catch (AccessTokenNotAvailableException exception) { exception.Redirect(); } } }
触发问题的修改操作
- 创建逻辑完全相同的
WorkOrderController,仅控制器名称不同; - Blazor页面中将请求改为
company = await Http.GetFromJsonAsync<Company>($"/api/workOrder/{Id}");。
原因分析
出现该问题的核心是请求的API路由未匹配到对应的控制器,触发了Blazor WASM的SPA fallback机制,返回了index.html页面,而非预期的JSON数据。具体可能的原因包括:
- 路由大小写不匹配:ASP.NET Core中
[Route("api/[controller]")]会将[controller]替换为控制器类名去掉Controller后缀的原始大小写(比如WorkOrderController对应api/WorkOrder),而请求的是/api/workOrder(小写w开头)。若项目配置了路由大小写敏感(options.CaseInsensitive = false),则会导致路由匹配失败。 - WorkOrderController缺少必要属性:若忘记添加
[ApiController]或[Route]属性,控制器的路由规则无法正确生效,请求无法被识别。 - 路由映射顺序错误:若
app.MapFallbackToFile("index.html");在app.MapControllers();之前执行,所有未匹配的请求会直接返回index.html,包括未正确匹配的API请求。 - 控制器未被扫描到:若WorkOrderController位于未被ASP.NET Core扫描的命名空间或程序集中,控制器无法被注册,自然无法处理请求。
解决方案
针对上述可能的原因,对应解决方案如下:
- 统一路由大小写:
- 修改Blazor请求URL与控制器路由大小写一致:将请求改为
/api/WorkOrder/{Id}; - 或修改控制器路由模板为小写:使用
[Route("api/[controller:lower]")],这样WorkOrderController的路由会自动转为api/workorder,请求时使用/api/workorder/{Id}即可匹配。
- 修改Blazor请求URL与控制器路由大小写一致:将请求改为
- 检查控制器属性:确保
WorkOrderController添加了[ApiController]和[Route("api/[controller]")]属性,与CompanyController保持一致。 - 调整路由映射顺序:在Program.cs中确保
app.MapControllers();在app.MapFallbackToFile("index.html");之前执行,让API请求优先被控制器处理:app.MapControllers(); app.MapFallbackToFile("index.html"); - 确保控制器被扫描:若控制器在单独的类库中,需在Program.cs中添加程序集引用:
builder.Services.AddControllers() .AddApplicationPart(typeof(WorkOrderController).Assembly);
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

