How to replace routes generated with MapMvcAttributeRoutes

Topics: ASP.NET MVC
Nov 5, 2013 at 12:05 PM
I'm trying to extend attribute generated routes with localization (http://www.nuget.org/packages/routelocalizationmvc, similar as it worked in AttributeRouting with MVC 4.0). Since there is no possibility to hook into the route generation process (e.g. custom route builder / etc) the only possibility is to replace the created routes afterwards with own routes.

This is feasible with 5.0 (since MapMvcAttributeRoutes just adds Route instances) but in 5.1 this is changed to RouteCollectionRoute and GenerationRoute. Both classes are internal, so without reflection it is not possible to wrap and extend those created instances. Will this be changed in future or would be your suggestion to achieve that?
Coordinator
Nov 5, 2013 at 4:18 PM
Hi Dresel,

We're working on some improvements to MVC's attribute routing right now so I'm forwarding this discussion to the two developers who are working on this and we can see what thoughts they have regarding this.

Thanks,
Eilon
Nov 25, 2013 at 5:16 PM
Edited Nov 25, 2013 at 5:16 PM
For 5.1, we added IDirectRouteProvider, which allows customizing the route instance on a per-attribute basis. The feature spec has further details.

If you want to customize a large number of route attributes, you could use a custom base class, something like CustomRouteAttribute, that derives from attribute and implements IDirectRouteProvider to customize the route as needed.

Does that answer your question?
Nov 25, 2013 at 9:44 PM
Edited Nov 25, 2013 at 9:44 PM
I think its going into a good direction. Is it possible to build upon the RouteAttribute (without replacing existing RouteAttributes)? For example, can a custom DirectRouteProviderContext be injected or is this "hardcoded"?

The extension should be easy to use and if it forces to replace every route attribute, this would be a big drawback.
Nov 25, 2013 at 10:25 PM
Dresel,

We currently don't provide a way to have a custom DirectRouteProviderContext implementation. If you want to customize how attribute routes are created everywhere, using a custom route base class is currently the only way to do so.

Feel free to log a bug if you'd like us to provide another mechanism. Notes about the details of your scenario would be particularly helpful.

Thanks,

David
Nov 26, 2013 at 7:41 AM
I see.

Well the usage scenario is quite simple. Consider existing attribute routes like this:
[Route("Products/{productID}")]
public ActionResult Products(int productID)
For SEO and other reasons it would be nice to have translated routes. The extension can be used like this (after MapMvcAttributeRoutes is called):
routes.Localization(configuration =>
{
    configuration.DefaultCulture = "en";
    configuration.AcceptedCultures.Add("de");

    configuration.AddCultureAsRoutePrefix = true;
}).Translate(localization =>
{
    localization
        .ForCulture("de")
        .ForController<ProductController>()
        .ForAction(x => x.Products())
        .AddTranslation("Produkte/{productID}");
});

// This replaces "Products/{productID}" by "en/Products/{productID}" and "de/Produkte/{productID}".
Atm translated routes are just replaced (RouteCollection.Remove and Insert) with an custom Route (TranslationRoute). This adds features like Culture detection from current route browsed or smart outbound route generation (a route generated uses the translated variant for the current culture).

I see that I can now use IDirectRouteProvider to hook into the RouteGeneration by modifying the RouteEntry returned from the builder, but it would be nicer if the user would not be forced replacing all attributes.

Is there any other possibility that comes in your mind that could achieve this?
Nov 26, 2013 at 8:11 PM
Thanks, Dresel.

I filed a work item to consider additional extensibility in this area, including a hook that would enable this scenario:
https://aspnetwebstack.codeplex.com/workitem/1464

David
Marked as answer by Dresel on 11/29/2013 at 12:01 AM
Nov 29, 2013 at 7:01 AM
Thanks, sounds good :)