Currently, my ASP.NET MVC website uses RouteConfig.RegisterRoutes
to map routes. I would like to convert this to the new Attribute routing system, but I am missing one small thing there.
The website is multi-language, so every URL needs to be prefixed with a two-letter ISO language code. In the current implementation, the website uses a custom RouteHandler
to handle the culture part of all routes. After registering all routes, a loop adds the custom handler and culture constraints to every route.
See below the current implementation:
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()));
}
}
}
}
Culture enum:
public enum Culture
{
nl = 1,
en = 2,
de = 3,
fr = 4
}
Custom routehandler:
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);
}
}
Culture constraints
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);
}
}
In order to convert this to the new AttributeRouting, I just thought I'd add a RoutePrefix
attribute to my base controller, which would handle the culture part. BUT it seems inheritance of route attributes is not supported...
The release notes of ASP.NET MVC 5.2 state that inherited route attributes are supported in that version by implementing a custom RouteAttribute
and DirectRouteProvider
. This is however for the RouteAttribute
, not for the RoutePrefixAttribute
.
What I have tried:
I've tried to create my own InheritedRoutePrefixAttribute
by inheriting from the RoutePrefixAttribute
, but then in order to actually support the inherited route, I still need to create a InheritedDirectRouteProvider
and override the GetControllerRouteFactories()
method, which returns a collection of IDirectRouteFactory
.
So in order to do that, my InheritedRoutePrefixAttribute
needs to implement the IDirectRouteFactory
interface, but what to do in the CreateRoute()
method?
My code so far:
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class InheritedRoutePrefixAttribute : RoutePrefixAttribute, IDirectRouteFactory
{
public RouteEntry CreateRoute(DirectRouteFactoryContext context)
{
// ...
}
}
Custom route provider
// 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();
}
}
Aucun commentaire:
Enregistrer un commentaire