目前,我的 ASP.NET MVC 网站使用 RouteConfig.RegisterRoutes
来映射路由。我想将其转换为新的属性路由系统,但我遗漏了一件小事。
该网站是多语言的,因此每个 URL 都需要以两个字母的 ISO 语言代码作为前缀。
在当前的实现中,该网站使用自定义 RouteHandler
来处理所有路由的文化部分。注册所有路由后,循环将自定义处理程序和文化约束添加到每个路由。
请参阅下面的当前实现:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.RouteExistingFiles = true;
// various calls to routes.MapRoute()
foreach (Route r in routes)
{
if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
{
r.RouteHandler = new MultiCultureMvcRouteHandler();
r.Url = "{culture}/" + r.Url;
// Add the default language
if (r.Defaults == null)
r.Defaults = new RouteValueDictionary();
r.Defaults.Add("culture", Culture.nl.ToString());
// Add language constraints
if (r.Constraints == null)
r.Constraints = new RouteValueDictionary();
r.Constraints.Add("culture", new CultureConstraint(Culture.nl.ToString(), Culture.de.ToString(), Culture.en.ToString(), Culture.fr.ToString()));
}
}
}
}
文化枚举:
public enum Culture
{
nl = 1,
en = 2,
de = 3,
fr = 4
}
自定义路由处理器:
public class SingleCultureMvcRouteHandler : MvcRouteHandler { }
public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var culture = requestContext.RouteData.Values["culture"].ToString();
var ci = new CultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("nl-NL");
return base.GetHttpHandler(requestContext);
}
}
文化限制
public class CultureConstraint : IRouteConstraint
{
private string[] _values;
public CultureConstraint(params string[] values)
{
this._values = values;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string value = values[parameterName].ToString();
return _values.Contains(value);
}
}
为了将其转换为新的 AttributeRouting,我只是想向我的基本 Controller 添加一个 RoutePrefix
属性,它会处理文化部分。 但是 似乎不支持继承路由属性...
release notes ASP.NET MVC 5.2 声明,通过实现自定义 RouteAttribute
和 DirectRouteProvider
,该版本支持继承的路由属性。然而,这是针对 RouteAttribute
,而不是针对 RoutePrefixAttribute
。
我尝试过的:
我尝试通过从 RoutePrefixAttribute
继承来创建我自己的 InheritedRoutePrefixAttribute
,但是为了真正支持继承的路由,我仍然需要创建一个 InheritedDirectRouteProvider
并覆盖 GetControllerRouteFactories()
方法,该方法返回 IDirectRouteFactory
的集合。
所以为了做到这一点,我的 InheritedRoutePrefixAttribute
需要实现 IDirectRouteFactory
接口(interface),但是在 CreateRoute()
方法中做什么呢?
到目前为止我的代码:
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class InheritedRoutePrefixAttribute : RoutePrefixAttribute, IDirectRouteFactory
{
public RouteEntry CreateRoute(DirectRouteFactoryContext context)
{
// ...
}
}
自定义路由提供者
// Custom direct route provider which supports attribute route inheritance.
public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory> GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
{
return controllerDescriptor.GetCustomAttributes(typeof(InheritedRoutePrefixAttribute), inherit: true).Cast<IDirectRouteFactory>().ToArray();
}
}
最佳答案
我目前正在从事一个 ASP.NET Web Api 项目,并且一直在研究属性路由(我认为这与 MVC 路由类似)。我想为我的 Controller 定义一个全局路由前缀。我为我的 Controller 创建了一个基类,我用 RoutePrefixAttribute
对其进行了修饰。
想法是在 Controller 基类中定义全局路由前缀,但也允许从它继承的 Controller 拥有自己的路由前缀。
例如:
[RoutePrefix("api")]
public abstract class BaseController : ApiController
{
}
[RoutePrefix("values")]
public class ValuesController : BaseController
{
[Route("{id}")]
public int Get(int id)
{
return id;
}
}
调用 Get 的路由将是:http://{base}:{port}/api/values/{id}
为此,我还继承自 DefaultDirectRouteProvider 类,但我重写了 GetRoutePrefix 方法:
public class InheritedRoutePrefixDirectRouteProvider : DefaultDirectRouteProvider
{
protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor)
{
var sb = new StringBuilder(base.GetRoutePrefix(controllerDescriptor));
var baseType = controllerDescriptor.ControllerType.BaseType;
for (var t = baseType; typeof(ApiController).IsAssignableFrom(t); t = t.BaseType)
{
var a = (t as MemberInfo).GetCustomAttribute<RoutePrefixAttribute>(false);
if (a != null)
{
sb.Insert(0, $"{a.Prefix}{(sb.Length > 0 ? "/": "")}");
}
}
return sb.ToString();
}
}
所以它所做的是在 Controller 继承链中将路由前缀链接在一起。
关于c# - ASP.NET MVC 中继承的 RoutePrefixAttribute,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30071772/