.NET6升级至.NET8时IEndpointRouteBuilder端点方法报错求助
Accepts/Produces错误解决方法 问题背景
原本在.NET 6中运行正常的Minimal API端点定义代码,升级到.NET 8后出现编译错误,提示IEndpointConventionBuilder不包含Accepts和Produces的定义,最佳扩展方法需要RouteHandlerBuilder类型的接收方。
原.NET 6端点定义代码
public static void DefineEndpoints(IEndpointRouteBuilder app) { app.MapPost(BaseRoute, CreateNoteAsync) .WithName("CreateNote") .Accepts<Note>(ContentType) .Produces<Note>(201).Produces<IEnumerable<ValidationFailure>>(400) .WithTags(Tag); app.MapGet(BaseRoute, GetAllNotesAsync) .WithName("GetNotes") .Produces<IEnumerable<Note>>(200) .WithTags(Tag); app.MapGet($"{BaseRoute}/{{symbol}}", GetNotesByTickerAsync) .WithName("GetNotesForSymbol") .Produces<IEnumerable<Note>>(200) .WithTags(Tag); app.MapGet($"{BaseRoute}/{{symbol}}/{{date}}", GetNotesForSymbolOnDateAsync) .WithName("GetNotesForSymbolByDate") .Produces<IEnumerable<Note>>(200) .WithTags(Tag); app.MapPut($"{BaseRoute}/{{symbol}}/{{date}}", UpdateNoteAsync) .WithName("UpdateNote") .Accepts<Note>(ContentType) .Produces<Note>(200).Produces<IEnumerable<ValidationFailure>>(400) .WithTags(Tag); app.MapDelete($"{BaseRoute}/{{symbol}}/{{date}}", DeleteNoteAsync) .WithName("DeleteNote") .Produces(204).Produces(404) .WithTags(Tag); // 其余代码省略 }
编译错误信息
严重性 代码 说明 项目 文件 行 抑制状态
Error CS1929 'IEndpointConventionBuilder' 不包含 'Accepts' 的定义,最佳扩展方法重载 'OpenApiRouteHandlerBuilderExtensions.Accepts(RouteHandlerBuilder, string, params string[])' 需要类型为 'Microsoft.AspNetCore.Builder.RouteHandlerBuilder' 的接收方 BATLWebApp.Net8.Api C:\Users\Trader\source\repos\BATLWebApp.Net8\BATLWebApp.Net8.Api\Endpoints\NoteEndpoints.cs 19 活动
同时Produces方法也出现相同错误。
示例处理方法
private static async Task<IResult> CreateNoteAsync(Note note, TableServiceManager tableServiceManager, IValidator<Note> validator) { var validationResult = await validator.ValidateAsync(note); if (!validationResult.IsValid) { return Results.BadRequest(validationResult.Errors); } var equityNote = MapNoteToEquityNoteEntity(note); try { var created = await tableServiceManager.AddEquityNoteAsync(equityNote); Results.Created($"/{BaseRoute}/{note.Ticker}", note); } catch (Exception ex) { var errorMessage = $"Error creating note for {note.Ticker} on {note.NoteDate} due to {ex.Message}"; Log.Error(ex, errorMessage); return Results.BadRequest(errorMessage); } return Results.BadRequest(); }
解决步骤
1. 确认NuGet包依赖
.NET 8里,Accepts和Produces这类OpenAPI相关的扩展方法,必须依赖Microsoft.AspNetCore.OpenApi包。如果项目里没装,赶紧通过NuGet安装:
Install-Package Microsoft.AspNetCore.OpenApi
或者直接在项目的.csproj文件里添加引用:
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.*" />
2. 修改端点定义代码
.NET 8中,MapPost/MapGet这类方法的返回类型会根据传入的处理方法签名变化。只要处理方法返回Task<IResult>(同步方法返回IResult),Map*就会返回RouteHandlerBuilder,这时候就能正常调用Accepts和Produces了。
修改后的代码如下:
using Microsoft.AspNetCore.OpenApi; public static void DefineEndpoints(IEndpointRouteBuilder app) { app.MapPost(BaseRoute, CreateNoteAsync) .WithName("CreateNote") .Accepts<Note>(ContentType) .Produces<Note>(StatusCodes.Status201Created) .Produces<IEnumerable<ValidationFailure>>(StatusCodes.Status400BadRequest) .WithTags(Tag); app.MapGet(BaseRoute, GetAllNotesAsync) .WithName("GetNotes") .Produces<IEnumerable<Note>>(StatusCodes.Status200OK) .WithTags(Tag); app.MapGet($"{BaseRoute}/{{symbol}}", GetNotesByTickerAsync) .WithName("GetNotesForSymbol") .Produces<IEnumerable<Note>>(StatusCodes.Status200OK) .WithTags(Tag); app.MapGet($"{BaseRoute}/{{symbol}}/{{date}}", GetNotesForSymbolOnDateAsync) .WithName("GetNotesForSymbolByDate") .Produces<IEnumerable<Note>>(StatusCodes.Status200OK) .WithTags(Tag); app.MapPut($"{BaseRoute}/{{symbol}}/{{date}}", UpdateNoteAsync) .WithName("UpdateNote") .Accepts<Note>(ContentType) .Produces<Note>(StatusCodes.Status200OK) .Produces<IEnumerable<ValidationFailure>>(StatusCodes.Status400BadRequest) .WithTags(Tag); app.MapDelete($"{BaseRoute}/{{symbol}}/{{date}}", DeleteNoteAsync) .WithName("DeleteNote") .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status404NotFound) .WithTags(Tag); // 其余代码省略 }
3. 额外提示
- .NET 8里,
RouteHandlerBuilder替代了之前部分IEndpointConventionBuilder的用法,OpenAPI相关的扩展方法现在只支持RouteHandlerBuilder。 - 保证所有端点处理方法都返回
Task<IResult>(同步方法返回IResult),这样Map*方法才会返回正确的RouteHandlerBuilder,链式调用才不会报错。 - 建议用
StatusCodes类里的常量代替硬编码的数字状态码,代码更易读也不容易写错。
内容的提问来源于stack exchange,提问作者dinotom

