多个控制器类型具有相同的路由前缀ASP.NET Web Api

use*_*404 19 c# asp.net-web-api attributerouting asp.net-web-api-routing

是否可以将GET和POST分离为单独的API控制器类型并使用相同的路径前缀访问它们?

这是我的控制器:

[RoutePrefix("api/Books")]
public class BooksWriteController : EventStoreApiController
{
    [Route("")]
    public void Post([FromBody] CommandWrapper commandWrapper){...}
}

[RoutePrefix("api/Books")]
public class BooksReadController : MongoDbApiController
{
    [Route("")]
    public Book[] Get() {...}


    [Route("{id:int}")]
    public Book Get(int id) {...}
}
Run Code Online (Sandbox Code Playgroud)

Yis*_*zer 34

Web API(1.x-2.x)不支持在不同控制器上具有相同路径的多个属性路由.结果是404,因为所有路由都匹配多个控制器,此时Web API会认为结果不明确.

请注意,MVC Core确实支持此场景说明:MVC Core既可用作MVC,也可用作Web API.

如果选择使用Web API 2.11(或更新版本),则可以为每个控制器的http方法创建路径约束,并使用它来代替内置的路径属性.下面的示例显示您可以使用RoutePrefix或直接路由(如kmacdonald的答案).

using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Routing;

public class BooksWriteController : ApiController
{
    [PostRoute("api/Books")]
    public void Post() { }
}

[RoutePrefix("api/books")]
public class BooksReadController : ApiController
{
    [GetRoute]
    public void Get() { }

    [GetRoute("{id:int}")]
    public void Get(int id) { }
}
Run Code Online (Sandbox Code Playgroud)

这两个类简化了约束路由属性的使用

class GetRouteAttribute : MethodConstraintedRouteAttribute
{
    public GetRouteAttribute(string template) : base(template ?? "", HttpMethod.Get) { }
}

class PostRouteAttribute : MethodConstraintedRouteAttribute
{
    public PostRouteAttribute(string template) : base(template ?? "", HttpMethod.Post) { }
}
Run Code Online (Sandbox Code Playgroud)

此类允许为生成的路径添加约束

class MethodConstraintedRouteAttribute : RouteFactoryAttribute
{
    public MethodConstraintedRouteAttribute(string template, HttpMethod method)
        : base(template)
    {
        Method = method;
    }

    public HttpMethod Method
    {
        get;
        private set;
    }

    public override IDictionary<string, object> Constraints
    {
        get
        {
            var constraints = new HttpRouteValueDictionary();
            constraints.Add("method", new MethodConstraint(Method));
            return constraints;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这只是一个标准的路由约束,你可能想要缓存约束对象以减少分配.

class MethodConstraint : IHttpRouteConstraint
{
    public HttpMethod Method { get; private set; }

    public MethodConstraint(HttpMethod method)
    {
        Method = method;
    }

    public bool Match(HttpRequestMessage request,
                      IHttpRoute route,
                      string parameterName,
                      IDictionary<string, object> values,
                      HttpRouteDirection routeDirection)
    {
        return request.Method == Method;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 关键在于限制路线本身.内置属性仅在操作选择中起作用,其运行得太晚. (2认同)