【发布时间】:2015-09-25 19:43:54
【问题描述】:
我有一个包含 Web Api v2 的 asp.net WebForm 项目。我没有考虑 api 版本控制,而是用下面的简单路线添加了我的整个 api:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}"
);
但是,现在,我需要创建版本控制,因为我有很多更改并且不想让使用旧 API 的老客户失望。所以我创建了一个名为 APIv2 的新文件夹,并在那里创建了我的控制器(与旧 api 同名)。问题是我怎么能路由这样的东西:
MyWebsite/API/Item => For ItemController OF OLD API
MyWebsite/APIv2/Item => For ItemController Of New API (Version 2)
我已经阅读了很多帖子,但没有一个对我有用!我也创建了NamespaceHttpControllerSelector,但它也不起作用。
请举例说明如何处理。
P.S:当我为新 api 创建简单的路由(例如旧路由)时,它说找到了重复的控制器! (虽然我使用不同的命名空间)
编辑(添加我的完整代码):
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));
RouteTable.Routes.MapHttpRoute(
name: "VersionedApi",
routeTemplate: "api/v2/{controller}");
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}");
还有 NamespaceHttpControllerSelector:
public class NamespaceHttpControllerSelector : DefaultHttpControllerSelector
{
private const string ControllerKey = "controller";
private readonly HttpConfiguration _configuration;
private readonly Lazy<IEnumerable<Type>> _duplicateControllerTypes;
public NamespaceHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
{
_configuration = configuration;
_duplicateControllerTypes = new Lazy<IEnumerable<Type>>(GetDuplicateControllerTypes);
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var routeData = request.GetRouteData();
if (routeData == null || routeData.Route == null || routeData.Route.DataTokens == null || routeData.Route.DataTokens["Namespaces"] == null)
return base.SelectController(request);
// Look up controller in route data
object controllerName;
routeData.Values.TryGetValue(ControllerKey, out controllerName);
var controllerNameAsString = controllerName as string;
if (controllerNameAsString == null)
return base.SelectController(request);
//get the currently cached default controllers - this will not contain duplicate controllers found so if
// this controller is found in the underlying cache we don't need to do anything
var map = base.GetControllerMapping();
if (map.ContainsKey(controllerNameAsString))
return base.SelectController(request);
//the cache does not contain this controller because it's most likely a duplicate,
// so we need to sort this out ourselves and we can only do that if the namespace token
// is formatted correctly.
var namespaces = routeData.Route.DataTokens["Namespaces"] as IEnumerable<string>;
if (namespaces == null)
return base.SelectController(request);
//see if this is in our cache
var found = _duplicateControllerTypes.Value
.Where(x => string.Equals(x.Name, controllerNameAsString + ControllerSuffix, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault(x => namespaces.Contains(x.Namespace));
if (found == null)
return base.SelectController(request);
return new HttpControllerDescriptor(_configuration, controllerNameAsString, found);
}
private IEnumerable<Type> GetDuplicateControllerTypes()
{
var assembliesResolver = _configuration.Services.GetAssembliesResolver();
var controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
//we have all controller types, so just store the ones with duplicate class names - we don't
// want to cache too much and the underlying selector caches everything else
var duplicates = controllerTypes.GroupBy(x => x.Name)
.Where(x => x.Count() > 1)
.SelectMany(x => x)
.ToArray();
return duplicates;
}
}
【问题讨论】:
-
你读过this article吗?你提到
NamespaceHttpControllerSelector,是从那里来的吗?请发布有关 WebAPI 配置的完整代码。 -
@SergRogovtsev 我读了那篇文章和另一篇,都不起作用!我还编辑帖子并发布我的完整代码(到目前为止的最新版本)。
-
按照文章做到底有什么不行的?
-
@SergRogovtsev 我收到此错误:对“项目”的请求已找到以下匹配的控制器:Pooshanet.API.v2.ItemController Pooshanet.API.ItemController,可能是因为它自己的命名空间?
-
您确定您指的是我上面链接的文章,而不是您发布的代码吗?它们是不同的。
标签: c# asp.net asp.net-web-api2