Добавить глобальное ограничение маршрута на основе имени параметра

Используя библиотеку AttributeRouting, я смог настроить маршрутизацию атрибутов для использования маршрута по умолчанию. ограничение на основе имени параметра.

Например, чтобы добавить RegexRouteConstraint для всех параметров маршрута, оканчивающихся на год:

routes.MapAttributeRoutes(cfg =>
    {
        cfg.AddDefaultRouteConstraint(@"year$",
            new RegexRouteConstraint(@"^([1-2]\d{3})$"));
    }
);

Мне известно об пользовательские ограничения маршрута в MVC5, но мне бы очень хотелось иметь возможность добавлять некоторые ограничения по соглашению, основанному просто на имени параметра.

Можно ли сделать то же самое с функциями маршрутизации атрибутов MVC5.1?


person marapet    schedule 13.03.2014    source источник


Ответы (1)


У меня такая же потребность, и я нашел решение, хотя я его тщательно не тестировал. Мой сценарий представляет собой мультитенантный 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