У меня такая же потребность, и я нашел решение, хотя я его тщательно не тестировал. Мой сценарий представляет собой мультитенантный API, где все маршруты начинаются с «api/{tenant}/…». Арендаторы извлекаются из web.config, поэтому у меня есть дополнительная сложность, заключающаяся в том, что мой пользовательский распознаватель должен быть одноэлементным. Приведенное ниже решение предназначено для веб-API, но я ожидаю, что оно будет работать в MVC с несколькими настройками пространства имен.
Создайте реализацию IHttpRouteConstraint. Это мое:
public class TenantRouteConstraint : IHttpRouteConstraint
{
public const string TenantKey = "tenant";
private readonly ISet<string> _tenants;
public TenantRouteConstraint()
{
_tenants = new HashSet<string>();
foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings)
{
_tenants.Add(connectionString.Name.ToLowerInvariant());
}
}
private static string GetTenant(IDictionary<string, object> values)
{
object tenant;
if (values.TryGetValue(TenantKey, out tenant))
{
return tenant.ToString().ToLowerInvariant();
}
return null;
}
public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
var tenant = GetTenant(values);
return tenant != null && _tenants.Contains(tenant);
}
}
Эта часть была легкой, потом стало сложнее. Маршруты обычно инициализируются в WebApiConfig.Register, который передается как делегированный в GlobalConfiguration.Configure в Global.asax. Однако маршруты на основе атрибутов не заполняются в коллекции Routes в конце метода Register. Чтобы обойти это, я добавил в WebApiConfig метод RegisterRouteConstraints, который вызывается после Register.
Метод RegisterRouteConstraints перебирает коллекцию Routes и добавляет мое ограничение, если в шаблоне маршрута присутствует "{tenant}". Коллекция Routes содержит три типа маршрутов: RouteCollectionRoute, HostedHttpRoute и LinkGeneratioRoute. Маршруты на основе атрибутов находятся в RouteCollectionRoute, но эти классы являются внутренними, поэтому я не могу напрямую проверить тип. К счастью, он реализует IEnumerable<IHttpRoute>
, поэтому я проверяю это.
public static void RegisterRouteConstraints(HttpConfiguration config)
{
var tenantConstraint = new TenantRouteConstraint();
AddConstraint(config.Routes, "tenant", tenantConstraint);
}
private static void AddConstraint(IEnumerable<IHttpRoute> routes, string key, IHttpRouteConstraint constraint)
{
foreach (var route in routes)
{
if (route.RouteTemplate.Contains("{" + key + "}") && !route.Constraints.ContainsKey(key))
{
route.Constraints.Add(key, constraint);
}
var routeCollection = route as IEnumerable<IHttpRoute>;
if (routeCollection != null)
{
AddConstraint(routeCollection, key, constraint);
}
}
}
Это вызывается в Global.asax Application_Start:
// ...
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configure(WebApiConfig.RegisterRouteConstraints);
// ...
person
Jamie Ide
schedule
22.04.2014