Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC5 routing namespace prioritize

In MVC5 routing I need one situation. I have 2 namespaces with same controller name. I want to dynamically chose between controllers without conflict

routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                new[] { "Namespace1","Namespace2" });

In here if there are 2 controllers with same name and actions under both namespaces it gives conflict error. What I want to do is prioritize namespaces.

If both namespaces has Home.Index action I want Namespace1 take the lead instead of error. If namespace1 does not have the action I want system check for Namespace2.

I tried few ways but I don't want to use attribute routing better architecture.

We have a BaseECommerce asp.net mvc project and UI projects that are taking inherit of BaseEcommerce project. Purpose is if there is same Controller and Action in UI project use that. Else use base project.

Thanks for help.

like image 945
Bahtiyar Özdere Avatar asked Mar 09 '23 16:03

Bahtiyar Özdere


1 Answers

You prioritize routes by registering them in the correct order - the first match wins.

You cannot prioritize namespaces. The namespaces field is for specifying all of the namespaces for a specific route (which is usually a single namespace). These are the set of namespaces where the specific route will scan for controllers.

So, if you want to avoid a conflict between similar named controllers, you need to have a route for each namespace. But, since the first matching route always wins, for it to work each controller action will need a unique URL.

routes.MapRoute(
            "Default", // Route name
            "Namespace2/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new[] { "Namespace2.Controllers" });

routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new[] { "Namespace1.Controllers" });

There are other ways of making routes match requests than above - for ideas, see this answer.

Note that you could use a custom route constraint to check whether some module is loaded into your application and if so, disable the route.

public class ModuleNotInstalledConstraint : IRouteConstraint
{
    public bool Match(
        HttpContextBase httpContext, 
        Route route, 
        string parameterName, 
        RouteValueDictionary values, 
        RouteDirection routeDirection)
    {
        if (module is installed)
        {
            return false;
        }

        return true;
    }
}

Usage

    routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new { _ = new ModuleNotInstalledConstraint() },
            new[] { "Namespace1.Controllers" });

This way, the route is ignored if the module is available, so you can use a route with the exact same signature and it will be "overridden" when the module is available. But you will still need to specify namespaces to ensure the scan doesn't conflict with controllers that have the same name.

like image 152
NightOwl888 Avatar answered Mar 31 '23 06:03

NightOwl888