使用库AttributeRouting,我能够将属性路由配置为根据参数名称使用默认路由约束。
例如,要为以年结尾的所有路径参数添加 RegexRouteConstraint :
routes.MapAttributeRoutes(cfg =>
{
cfg.AddDefaultRouteConstraint(@"year$",
new RegexRouteConstraint(@"^([1-2]\d{3})$"));
}
);
我知道custom route constraints in MVC5,但我真的希望能够根据参数名称按惯例添加一些约束。
是否可以对MVC5.1的属性路由功能执行相同的操作?
答案 0 :(得分: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和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);
// ...