【问题标题】:Add global route constraint based on parameter name根据参数名称添加全局路由约束
【发布时间】:2014-03-13 08:59:17
【问题描述】:

使用库AttributeRouting,我能够将属性路由配置为使用基于参数名称的默认路由约束

例如,为所有以 year 结尾的路由参数添加 RegexRouteConstraint

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

我知道custom route constraints in MVC5,但我真的希望能够根据参数名称按约定添加一些约束。

MVC5.1的属性路由特性是否也能做到这一点?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-routing attributerouting asp.net-mvc-5.1


    【解决方案1】:

    我有同样的需求并找到了解决方案,虽然我没有彻底测试过。我的场景是一个多租户 API,其中路由都以“api/{tenant}/...”开头。租户是从 web.config 中提取的,因此我的自定义解析器应该是一个单例,这增加了复杂性。下面的解决方案适用于 Web 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 中初始化,它作为委托传递给 Global.asax 中的 GlobalConfiguration.Configure。但是,基于属性的路由不会填充到 Register 方法末尾的 Routes 集合中。为了解决这个问题,我向 WebApiConfig 添加了一个 RegisterRouteConstraints 方法,该方法在 Register 之后被调用。

    RegisterRouteConstraints 方法循环遍历 Routes 集合,如果路由模板中存在“{tenant}”,则添加我的约束。 Routes 集合包含三种类型的路由:RouteCollectionRoute、HostedHttpRoute 和 LinkGeneatioRoute。基于属性的路由在 RouteCollectionRoute 中,但这些类是内部的,所以我无法直接测试类型。幸运的是它实现了IEnumerable&lt;IHttpRoute&gt;,所以我检查了一下。

    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);
    // ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-11
      • 1970-01-01
      相关资源
      最近更新 更多