Search code examples
c#.netasp.net-mvcattributerouting

MapMvcAttributeRoutes in Referenced/External Assembly


I am using dynamically loaded assemblies as a source for MVC Controllers (plugin/add-on framework). I can find no way to map the attribute routes for the Controllers in the referenced assembly.

I tried calling MapMvcAttributeRoutes from within the referenced assembly (like on article suggested would work in Web API) but that did not work.

How do I map attribute routes for Controllers in an referenced assembly?

EDIT:

I have a main MVC application which loads assemblies from a file. These assemblies are structured like so:

Add-On Assembly Structure

I extended the code for creating a controller and finding a View but I can find no instructions on how to handle (map) RouteAttributes specified in the external assembly like this:

[RoutePrefix("test-addon")]
public class MyTestController : Controller
{
    [Route]
    public ActionResult Page()
    {
        return View(new TestModel { Message = "This is a model test." });
    }
}

Solution

  • I managed to find a solution: manually parse Route Attributes into the Route Dictionary. Probably not doing it 100% right but this seems to work so far:

    public static void MapMvcRouteAttributes(RouteCollection routes)
    {
        IRouteHandler routeHandler = new System.Web.Mvc.MvcRouteHandler();
    
        Type[] addOnMvcControllers =
            AddOnManager.Default.AddOnAssemblies
                .SelectMany(x => x.GetTypes())
                .Where(x => typeof(AddOnWebController).IsAssignableFrom(x) && x.Name.EndsWith("Controller"))
                .ToArray();
    
        foreach (Type controller in addOnMvcControllers)
        {
            string controllerName = controller.Name.Substring(0, controller.Name.Length - 10);
            System.Web.Mvc.RoutePrefixAttribute routePrefix = controller.GetCustomAttribute<System.Web.Mvc.RoutePrefixAttribute>();
            MethodInfo[] actionMethods = controller.GetMethods();
            string prefixUrl = routePrefix != null ? routePrefix.Prefix.TrimEnd('/') + "/" : string.Empty;
    
            foreach (MethodInfo method in actionMethods)
            {
                System.Web.Mvc.RouteAttribute route = method.GetCustomAttribute<System.Web.Mvc.RouteAttribute>();
    
                if (route != null)
                {
                    routes.Add(
                        new Route(
                            (prefixUrl + route.Template.TrimStart('/')).TrimEnd('/'),
                            new RouteValueDictionary { { "controller", controllerName }, { "action", method.Name } },
                            routeHandler));
                }
            }
        }
    }
    

    The seemingly excessive trims are actually just to make sure that under no conditions are there any extra '/' at the start, middle or end.