与路由暧昧控制器名称属性:具有相同名称和不同的命名空间的版本控制器

问题描述 投票:15回答:2

我想补充的API版本和我的计划是建立在不同的命名空间的每个版本的控制器。我的项目结构如下(注意:没有单独的区域每个版本)

Controllers
 |
 |---Version0
 |      |
 |      |----- ProjectController.cs
 |      |----- HomeController.cs
 |
 |---Version1
       |
       |----- ProjectController.cs
       |----- HomeController.cs

我使用RoutingAttribute的路线。因此,在ProjectController具有Version0与功能作为路线

namespace MyProject.Controllers.Version0
{
   class ProjectController : BaseController
   {
     ...

     [Route(api/users/project/getProjects/{projectId})]
     public async GetProjects(string projectId) 
     {
       ...
     }
  }
}

和ProjectController在版本1具有的功能与路线为

namespace MyProject.Controllers.Version1
{
   class ProjectController : BaseController
   {
     ...

     [Route(api/v1/users/project/getProjects/{projectId})]
     public async GetProjects(string projectId) 
     {
      ...
     }
  }
}

但是,我得到当我试图打服务404-NOTFOUND。

如果我重命名控制器具有唯一的名称(Project1Controller和Project2Controller)路由的作品。但是,我想,以避免重命名为简单起见。

我跟着这个链接来解决问题,但它并没有帮助。我没有创建领域,但仍然没有成功。在global.aspx文件中添加路由逻辑没有帮助。命名空间也不能工作。 http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx/

上面的链接提示创建领域,但属性路由不支持领域的每个链接:http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

有另一种解决方案?与RoutingAttributes一个错误?

谢谢!

c# asp.net asp.net-web-api asp.net-web-api2 asp.net-web-api-routing
2个回答
21
投票

首先,网页API路由和路由MVC并不完全以相同的方式工作。

你的第一个链接指向MVC路由,与地区。区域未正式支持的Web API,虽然你可以尝试让类似他们的东西。但是,即使你试图做这样的事情,你会得到同样的错误,因为在至极的Web API的方式寻找一个控制器不考虑控制器的命名空间。

所以,开箱即用的,它永远不会工作。

但是,您可以修改大多数Web API的行为,这是不是一个例外。

网络API使用控制器选择以获得所需的控制器。行为上面解释是DefaultHttpControllerSelector,其自带的Web API的行为,但你可以实现你自己的选择,以取代默认的一个,并支持新的行为。

如果谷歌为“自定义Web API控制器选择”,你会发现许多样品,但我觉得这是最有趣的正是您的问题:

这个实现也很有意思:

正如你看到没有,基本上你需要:

  • 实现自己的IHttpControllerSelector,其中考虑到命名空间找到控制器和命名空间的路线变量,选择其中之一。
  • 取代通过Web API配置原来选择与此有关。

7
投票

我知道这是回答了,同时一展身手,并已经由原始的海报所接受。然而,如果你和我一样,需要使用属性的路由,并已尝试了建议的答案,你就会知道,它不会完全奏效。

当我尝试这样做,我发现,它实际上是缺少应该已经通过调用theMapHttpAttributeRoutes类的扩展方法HttpConfiguration产生的路由信息​​:

config.MapHttpAttributeRoutes();

这意味着更换SelectController实现的方法IHttpControllerSelector实际上从未被调用,这就是为什么请求产生一个HTTP 404响应。

该问题是由一个内部类称为HttpControllerTypeCache这是在System.Web.Http命名空间下的System.Web.Http.Dispatcher装配一个内部类引起的。有问题的代码如下:

    private Dictionary<string, ILookup<string, Type>> InitializeCache()
    {
      return this._configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(this._configuration.Services.GetAssembliesResolver()).GroupBy<Type, string>((Func<Type, string>) (t => t.Name.Substring(0, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length)), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, Type>, string, ILookup<string, Type>>((Func<IGrouping<string, Type>, string>) (g => g.Key), (Func<IGrouping<string, Type>, ILookup<string, Type>>) (g => g.ToLookup<Type, string>((Func<Type, string>) (t => t.Namespace ?? string.Empty), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase)), (IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
    }

您将在此代码,它是由类型名称没有命名空间分组看。所述DefaultHttpControllerSelector类使用该功能时,它积聚HttpControllerDescriptor的每个控制器的内部缓存。当使用MapHttpAttributeRoutes方法它使用另一种内部类称为AttributeRoutingMapper这是System.Web.Http.Routing命名空间的一部分。该类使用GetControllerMapping的方法IHttpControllerSelector以配置路由。

所以,如果你要编写自定义IHttpControllerSelector那么你需要重载为它工作的GetControllerMapping方法。我提到这一点的原因是,我没有看到在互联网上实现这一点。

© www.soinside.com 2019 - 2024. All rights reserved.