Web Api路由噩梦。无法使其适用于所有控制器

时间:2014-05-12 21:39:50

标签: asp.net-web-api asp.net-mvc-routing

我有一个MVC Web Api RESTful服务。我没有使用API​​版本2.

我使用默认的GET / POST / PUT / DELETE创建了一个Controller。一切都很好,直到我决定为我的控制器添加更多功能。

长话短说,我最终为我的控制器准备了十几个路线模板(非常讨厌的WebApiConfig文件)。它工作正常,直到....我需要第二个控制器。然后混乱就开始了。

DocumentController的所有路由显然不适用于CompanyController,因为我之前配置的只是一堆糟糕的补丁,使我的第一个Controller工作。我在这里四天后仍然无法上班。我真的无法理解这整个路由的事情。如此复杂和不灵活(在我看来)。

以下是一些供您理解的代码。

public class DocumentController : ApiController
{
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK,"This is GET");
    }

    [HttpGet]
    public HttpResponseMessage Metadata()
    {
        return Request.CreateResponse(HttpStatusCode.OK,"This is Metadata");
    }

    public HttpResponseMessage Get(int id)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is GET with ID");
    }

    public HttpResponseMessage Post([FromBody] DocumentDTO document)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is Post");
    }

    public HttpResponseMessage Put(int id, [FromBody] DocumentDTO document)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is PUT");
    }

    [HttpGet]
    public HttpResponseMessage Tags(int id)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is GET TAGS");
    }

    [HttpPost]
    public HttpResponseMessage Tags(int id, [FromBody] IEnumerable<TagDefinitionDTO> tagDefinitions)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is POST TAGS");
    }
}

所以,我最初的梦想是实现以下目标

GET /document/ =&gt;所有文件

GET /document/3 =&gt;文件ID = 3

POST /document/ =&gt;创建文档

PUT /document/3 =&gt;编辑文件

GET /document/metadata =&gt;退回所有DOC的一般配置

GET /document/6/tags =&gt;获取文件ID = 6的所有标签

POST /document/6/tags =&gt;为文件ID = 6创建标签

我甚至没有发布WebApi,因为它非常令人尴尬。就像我说的,我能够使用额外的方法,但它几乎是一对一的映射到我的控制器/动作。 AWFUL ......我知道。

当我添加第二个控制器......显然......不可能的任务。

现在,不要让你认为我没有做过一些研究(我已经使用过约束,默认等等,但是没有用...可怜)。一旦我让一个控制器工作,另一个打破。

我遇到各种各样的错误。从“多个GET方法”到“未找到资源”,“方法现在允许POST”。

我在这里,五天后进入圈子。这非常令人沮丧。

问题。

有没有人遇到过这些问题?路由协议SO是否限制每个控件只能进行4次操作?我应该在我的控制器中创建一个路径模板PER动作,这意味着如果我有10个控制器有10个动作,我应该添加100个路径模板吗?

2 个答案:

答案 0 :(得分:1)

是的,您可以切换到使用属性路由。

然后在每个动作或控制器上,您只需放置路径模板。

或以下路线应该适合您

config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
    name: "DefaultApi1",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional },
    constraints: new { id = @"\d+" }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi2",
    routeTemplate: "api/{controller}/{id}/{action}",
    defaults: null,
    constraints: new { id = @"\d+" }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi3",
    routeTemplate: "api/{controller}/{action}",
    defaults: new {id = RouteParameter.Optional}
);

答案 1 :(得分:1)

根据Yishai的回答,我认为将您的路线更改为以下内容应适合您的情况:

config.Routes.MapHttpRoute(
    name: "DefaultApi1",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional, action = "Default" },
    constraints: new { id = @"\d*" }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi2",
    routeTemplate: "api/{controller}/{action}",
    defaults: null,
    constraints: new { action = @"[a-zA-Z]+" }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi3",
    routeTemplate: "api/{controller}/{id}/{action}",
    defaults: null,
    constraints: new { id = @"\d+", action = @"[a-zA-Z]+" }
);

然后在默认操作中放置一个ActionName属性。

public class DocumentController : ApiController
{
    [ActionName("Default")]
    [HttpGet]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK,"This is GET");
    }

    [HttpGet]
    public HttpResponseMessage Metadata()
    {
        return Request.CreateResponse(HttpStatusCode.OK,"This is Metadata");
    }

    [ActionName("Default")]
    [HttpGet]
    public HttpResponseMessage Get(int id)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is GET with ID");
    }

    [ActionName("Default")]
    [HttpPost]
    public HttpResponseMessage Post([FromBody] DocumentDTO document)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is Post");
    }

    [ActionName("Default")]
    [HttpPut]
    public HttpResponseMessage Put(int id, [FromBody] DocumentDTO document)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is PUT");
    }

    [HttpGet]
    public HttpResponseMessage Tags(int id)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is GET TAGS");
    }

    [HttpPost]
    public HttpResponseMessage Tags(int id, [FromBody] IEnumerable<TagDefinitionDTO> tagDefinitions)
    {
        return Request.CreateResponse(HttpStatusCode.OK, "This is POST TAGS");
    }
}

如上所述,Web API 2是一种更好的方法。