Web Api 属性路由与 POST 请求不匹配
Posted
技术标签:
【中文标题】Web Api 属性路由与 POST 请求不匹配【英文标题】:Web Api attribute routing won't match POST request 【发布时间】:2019-11-25 17:04:37 【问题描述】:我的控制器上的所有操作都有属性路由(尽管定义了默认的常规路由)。我已经(我认为)尝试了是否使用 [HttpPost] 以及是否使用 [FromBody] 的所有组合。
如果我尝试使用仅定义了控制器名称的属性...
[HttpPost]
[Route("Relationships")]
private async Task<IHttpActionResult> PostRelationship([FromBody]Relationship relationship)
Request URL:http://localhost:51599/api/Relationships
Request method:POST
...我得到一个 405。
它似乎正在使用属性路由 - 调试 GetRouteData() 显示了一个子路由,它正在解析为“GetController”操作。
subroutes System.Web.Http.Routing.IHttpRouteData[1] System.Collections.Generic.IEnumerable<System.Web.Http.Routing.IHttpRouteData> System.Web.Http.Routing.IHttpRouteData[]
- [0] System.Web.Http.Routing.HttpRouteData System.Web.Http.Routing.IHttpRouteData System.Web.Http.Routing.HttpRouteData
- Route System.Web.Http.Routing.HttpRoute System.Web.Http.Routing.IHttpRoute System.Web.Http.Routing.HttpRoute
+ Constraints Count = 0 System.Collections.Generic.IDictionary<string, object> System.Web.Http.Routing.HttpRouteValueDictionary
- DataTokens Count = 2 System.Collections.Generic.IDictionary<string, object> System.Web.Http.Routing.HttpRouteValueDictionary
- [0] [actions, System.Web.Http.Controllers.HttpActionDescriptor[]] System.Collections.Generic.KeyValuePair<string, object>
Key "actions" string
- Value System.Web.Http.Controllers.HttpActionDescriptor[1] object System.Web.Http.Controllers.HttpActionDescriptor[]
- [0] System.Web.Http.Controllers.ReflectedHttpActionDescriptor System.Web.Http.Controllers.HttpActionDescriptor System.Web.Http.Controllers.ReflectedHttpActionDescriptor
+ ActionBinding System.Web.Http.Controllers.HttpActionBinding System.Web.Http.Controllers.HttpActionBinding
ActionName "GetRelationships" string
如果我尝试使用带有动作名称的路由...
[HttpPost]
[Route("Relationships/PostRelationship")]
private async Task<IHttpActionResult> PostRelationship([FromBody]Relationship relationship)
http://localhost:51599/api/Relationships/PostRelationship
Request method:POST
...我得到一个 404。
在这种情况下,它似乎正在使用默认控制器 - 调试 GetRouteData() 表明它认为我正在提供“控制器”和“id”。
routeData System.Web.Routing.RouteData System.Web.Routing.RouteData
+ DataTokens System.Web.Routing.RouteValueDictionary System.Web.Routing.RouteValueDictionary
+ Route System.Web.Http.WebHost.Routing.HttpWebRoute System.Web.Routing.RouteBase System.Web.Http.WebHost.Routing.HttpWebRoute
+ RouteHandler System.Web.Http.WebHost.HttpControllerRouteHandler System.Web.Routing.IRouteHandler System.Web.Http.WebHost.HttpControllerRouteHandler
- Values System.Web.Routing.RouteValueDictionary System.Web.Routing.RouteValueDictionary
Count 2 int
- Keys Count = 2 System.Collections.Generic.Dictionary<string, object>.KeyCollection
[0] "controller" string
[1] "id" string
- Values Count = 2 System.Collections.Generic.Dictionary<string, object>.ValueCollection
[0] "Relationships" object string
[1] "PostRelationship" object string
这是整个控制器:
[RoutePrefix("api")]
public class RelationshipsController : ApiController
private CMDBContext db = new CMDBContext();
[Route("Relationships")]
public IQueryable<Relationship> GetRelationships()
return db.Relationships;
[Route("Relationships/id:int")]
private async Task<Relationship> GetRelationship(int id)
Relationship relationship = await db.Relationships.FindAsync(id);
if (relationship == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return relationship;
[HttpPost]
[Route("Relationships/PostRelationship")]
private async Task<IHttpActionResult> PostRelationship([FromBody]Relationship relationship)
if (!ModelState.IsValid)
return BadRequest(ModelState);
db.Relationships.Add(relationship);
await db.SaveChangesAsync();
return CreatedAtRoute("DefaultApi", new id = relationship.Id , relationship);
[HttpGet]
[Route("Relationships/RelTypes")]
public Dictionary<string, string> RelTypes() // returns a list of available Relationship types
var RelTypesDict = new Dictionary<string, string>();
foreach (var type in Relationship.RelTypes)
RelTypesDict.Add(type, Regex.Replace(type, @"(\B[A-Z]+?(?=[A-Z][^A-Z])|\B[A-Z]+?(?=[^A-Z]))", " $1")); // expands camel case with spaces for display
return RelTypesDict;
private bool RelationshipExists(int id)
return db.Relationships.Count(e => e.Id == id) > 0;
和 WebApiConfig:
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/controller/id",
defaults: new id = RouteParameter.Optional
);
以及我用来调用它的 AJAX:
async function postEdge() // persists a new edge to data store from form
var ItemLeftId = $('#ItemLeftId').val();
var ItemRightId = $('#ItemRightId').val();
var RelType = $('#ddlRelType').val();
var Description = $('#Description').val();
$.ajax(
method: "POST",
contentType: "application/json; charset=utf-8",
url: '/api/Relationships',
data:
Id: 0, // TESTING
ItemLeftId: ItemLeftId,
ItemRightId: ItemRightId,
RelType: RelType,
Description: Description,
,
【问题讨论】:
【参考方案1】:我想通了——如果你看上面的话,GetRelationship 和 PostRelationship 方法都设置为 Private。这是我从另一个基类继承关系并使用不同的公共方法进行区分时遗留下来的。愚蠢的错误,但如果症状看起来不那么奇怪/无关,就会更容易发现。
【讨论】:
以上是关于Web Api 属性路由与 POST 请求不匹配的主要内容,如果未能解决你的问题,请参考以下文章