ASP.NET Core中DELETE路由处理器无法工作问题排查
问题描述
我正在学习用ASP.NET Core构建REST API,GET和POST请求都能正常运行,但DELETE请求始终报错,收到405 Method Not Allowed响应,响应头显示允许的方法只有GET和POST。
我的DELETE路由配置:
app.MapDelete("/todo/{id}", Results<Ok, NotFound> ([FromRoute] int id, [FromServices] TodoDb db) => { var result = db.todos.Where<TodoModel>(model => model.id == id).First(); if (result is null) { return TypedResults.NotFound(); } db.todos.Remove(result); db.SaveChanges(); return TypedResults.Ok(); });
请求URL:
http://localhost:5168/todo?id=2
收到的响应:
HTTP/1.1 405 Method Not Allowed Content-Length: 0 Connection: close Date: Fri, 13 Dec 2024 04:46:32 GMT Server: Kestrel Allow: GET, POST
核心原因:路由不匹配
你配置的DELETE路由是路由参数模式:/todo/{id},但实际请求用的是查询参数格式:/todo?id=2。
ASP.NET Core的路由系统会严格匹配端点模板,当你发送DELETE请求到/todo?id=2时,系统找不到对应的DELETE端点(只有/todo的GET、POST端点存在),因此返回405错误。
修复方案(二选一)
修改请求URL(推荐,符合REST规范)
使用路由参数格式发送请求:DELETE http://localhost:5168/todo/2修改路由模板(不推荐,不符合REST设计原则)
将DELETE路由改为查询参数模式:app.MapDelete("/todo", Results<Ok, NotFound> ([FromQuery] int id, [FromServices] TodoDb db) => { // 原有逻辑保持不变 });
代码中的其他潜在问题优化
除了路由不匹配,你的代码还有几个可优化的点:
1. 避免First()引发异常
当找不到对应ID的Todo时,db.todos.Where(model => model.id == id).First()会直接抛出InvalidOperationException,后续的if (result is null)判断永远不会执行。应改用FirstOrDefault():
var result = db.todos.FirstOrDefault(model => model.id == id);
2. 删除冗余中间件
这段中间件没有任何实际功能,建议删除:
app.Use((context, next) => next(context));
3. 优化GET列表的判断逻辑
db.todos.ToList()永远不会返回null,只会返回空列表,因此result is null的判断可以简化:
app.MapGet("/todo", Results<Ok<List<TodoModel>>, NotFound> ([FromServices] TodoDb db) => { List<TodoModel> result = db.todos.ToList(); return result.Any() ? TypedResults.Ok(result) : TypedResults.NotFound(); });
4. 删除无用的转换运算符
TodoModel中的public static implicit operator List<object>(TodoModel v)方法未被使用,且会抛出异常,建议删除。
修复后的DELETE端点代码
app.MapDelete("/todo/{id}", Results<Ok, NotFound> ([FromRoute] int id, [FromServices] TodoDb db) => { var result = db.todos.FirstOrDefault(model => model.id == id); if (result is null) { return TypedResults.NotFound(); } db.todos.Remove(result); db.SaveChanges(); return TypedResults.Ok(); });
内容的提问来源于stack exchange,提问作者dagmawi

