我想补充的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一个错误?
谢谢!
首先,网页API路由和路由MVC并不完全以相同的方式工作。
你的第一个链接指向MVC路由,与地区。区域未正式支持的Web API,虽然你可以尝试让类似他们的东西。但是,即使你试图做这样的事情,你会得到同样的错误,因为在至极的Web API的方式寻找一个控制器不考虑控制器的命名空间。
所以,开箱即用的,它永远不会工作。
但是,您可以修改大多数Web API的行为,这是不是一个例外。
网络API使用控制器选择以获得所需的控制器。行为上面解释是DefaultHttpControllerSelector,其自带的Web API的行为,但你可以实现你自己的选择,以取代默认的一个,并支持新的行为。
如果谷歌为“自定义Web API控制器选择”,你会发现许多样品,但我觉得这是最有趣的正是您的问题:
这个实现也很有意思:
正如你看到没有,基本上你需要:
IHttpControllerSelector
,其中考虑到命名空间找到控制器和命名空间的路线变量,选择其中之一。我知道这是回答了,同时一展身手,并已经由原始的海报所接受。然而,如果你和我一样,需要使用属性的路由,并已尝试了建议的答案,你就会知道,它不会完全奏效。
当我尝试这样做,我发现,它实际上是缺少应该已经通过调用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
方法。我提到这一点的原因是,我没有看到在互联网上实现这一点。