Asp.net web api Web Api路由噩梦。Can';不能使它适用于所有控制器

Asp.net web api Web Api路由噩梦。Can';不能使它适用于所有控制器,asp.net-web-api,asp.net-mvc-routing,Asp.net Web Api,Asp.net Mvc Routing,我有一个MVC Web Api RESTful服务。我没有使用API版本2 我用默认的GET/POST/PUT/DELETE创建了一个控制器。一切都很好,直到我决定添加一些更多的功能到我的控制器 长话短说,我最终为我的控制器提供了近十几个路由模板(非常讨厌的WebApiConfig文件)。在……之前它一直运转良好。。。。我需要第二个控制器。然后混乱开始了 DocumentController的所有路由显然不适用于CompanyController,因为我之前配置的只是一堆蹩脚的补丁,使我的第一个

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

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

长话短说,我最终为我的控制器提供了近十几个路由模板(非常讨厌的WebApiConfig文件)。在……之前它一直运转良好。。。。我需要第二个控制器。然后混乱开始了

DocumentController的所有路由显然不适用于CompanyController,因为我之前配置的只是一堆蹩脚的补丁,使我的第一个控制器工作。四天后我到了这里,但仍然无法让它工作。我真的无法理解这整件事。(在我看来)如此复杂和僵硬

这里有一些代码供您理解

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");
    }
}
公共类文档控制器:ApiController
{
公共HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK,“这是GET”);
}
[HttpGet]
公共HttpResponseMessage元数据()
{
return Request.CreateResponse(HttpStatusCode.OK,“这是元数据”);
}
公共HttpResponseMessage获取(int id)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是带有ID的GET”);
}
公共httpresponsemessagepost([FromBody]DocumentDTO document)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是Post”);
}
公共httpresponsemessageput(int-id,[FromBody]documentd到document)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是PUT”);
}
[HttpGet]
公共HttpResponseMessage标记(int id)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是GET标签”);
}
[HttpPost]
公共HttpResponseMessage标记(int-id,[FromBody]IEnumerable标记定义)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是POST标签”);
}
}
因此,我最初的梦想是实现以下目标

获取所有文档

获取
/document/3
=>文档Id=3

发布
/document/
=>创建文档

放置
/document/3
=>编辑文档

GET
/document/metadata
=>返回所有文档的常规配置

获取
/document/6/tags
=>获取文档ID=6的所有标记

POST
/document/6/tags
=>为文档ID=6创建标记

我甚至不发布WebApi,因为这很尴尬。正如我所说,我能够使用额外的方法使其工作,但它几乎是到我的控制器/操作的一对一映射。可怕的。。。我知道

当我添加第二个控制器时。。。。明显地任务不可能完成

现在,我不想让你认为我没有做过一些研究(我使用了约束、默认值等,但没有用……可怜)。一旦我让一个控制器工作,另一个就会中断

我会犯各种各样的错误。从“获取的多个方法”到“未找到资源”,“现在允许发布的方法”

五天后,我就在这里转了一圈。这是非常令人沮丧的

问题


有人面对过这些问题吗?路由协议是否限制了每个控件只能执行这4个操作?我是否应该为控制器中的每个操作创建一个路由模板,这意味着如果我有10个控制器和10个操作,我应该添加100个路由模板?

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

然后,在每个操作或控制器上,您可以只放置路由模板

或者下面的路线应该适合你

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}
);

基于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");
    }
}
公共类文档控制器:ApiController
{
[ActionName(“默认”)]
[HttpGet]
公共HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK,“这是GET”);
}
[HttpGet]
公共HttpResponseMessage元数据()
{
return Request.CreateResponse(HttpStatusCode.OK,“这是元数据”);
}
[ActionName(“默认”)]
[HttpGet]
公共HttpResponseMessage获取(int id)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是带有ID的GET”);
}
[ActionName(“默认”)]
[HttpPost]
公共httpresponsemessagepost([FromBody]DocumentDTO document)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是Post”);
}
[ActionName(“默认”)]
[HttpPut]
公共httpresponsemessageput(int-id,[FromBody]documentd到document)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是PUT”);
}
[HttpGet]
公共HttpResponseMessage标记(int id)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是GET标签”);
}
[HttpPost]
公共HttpResponseMessage标记(int-id,[FromBody]IEnumerable标记定义)
{
return Request.CreateResponse(HttpStatusCode.OK,“这是POST标签”);
}
}

如前所述,WebAPI2是一种更好的方式。

我不能使用属性路由。我使用的是API v.1,而不是v.2。我要试试你的建议,我会让你知道的!当然-还有Tim McCall的Web API V1属性路由库安装包AttributeRouting.WebApi“找到多个与请求匹配的操作:System.Net.Http.HttpResponseMessage Get()”我在配置中遇到此错误。让我看看这个包。我的错是,这应该只适用于属性路由。如果可以的话,我会认真考虑升级到Web API 2。唯一的限制是您必须在.NET 4.5上运行您的解决方案对我有效。因此,到目前为止,我学到的是,您的action=“Default”基本上将调用“路由”到这4个方法(sin)