Search code examples
c#asp.net-mvcasp.net-mvc-4routesasp.net-mvc-routing

Set a route to an area without specifying the area name in the url in MVC


I have an MVC 4 application. In that application I have certain Areas, whose URL is not resolved properly. The LocationAreaRegistration.cs is as follows:

context.MapRoute(
            "Location_default",
            "{culture}/{controller}/{action}/{id}",
            new { culture = "en", action = "LocationIndex", id = UrlParameter.Optional },
            new { controller = "(LocationIndex)" }
        );

My route.config is as follows:

routes.MapRoute(
                 name: "Default",
                 url: "{culture}/{controller}/{action}/{id}",
                 defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
                 namespaces: new[] { "Locator.Areas.Location.Controllers" }
               ).DataTokens.Add("area", "Location");

I have also tried to change the route.config as below:

routes.MapRoute(
             name: "Default",
             url: "{culture}/{controller}/{action}/{id}",
             defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
             namespaces: new[] { "Locator.Areas.Location.Controllers" }
           );

None of the approaches worked and I get The resource cannot be found error.

However when I change the LocationAreaRegistration.cs as follows, it works:

context.MapRoute(
            "Location_default",
            "{culture}/Location/{controller}/{action}/{id}",
            new { culture = "en", action = "LocationIndex", id = UrlParameter.Optional },
            new { controller = "(LocationIndex)" }
        );

But I do not want the URL to contain the Location(Area name). What am I doing wrong?

EDIT

The URLs that I would be going to will be somewhat like:

http://localhost/en/LocationIndex/LocationIndex

Here en is the current culture, Home is the controller name and Index is the action method name.


Solution

  • To make the Location area the default set of routes for your MVC application, you just need to define your RouteConfig.cs as follows:

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapRoute(
                name: "Default_Localized",
                url: "{culture}/{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                constraints: new { culture = new CultureConstraint(defaultCulture: "en", pattern: "[a-z]{2}") },
                namespaces: new string[] { "Locator.Areas.Location.Controllers" }
            ).DataTokens["area"] = "Location";
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
                namespaces: new string[] { "Locator.Areas.Location.Controllers" }
            ).DataTokens["area"] = "Location";
        }
    }
    

    Note that this will completely replace any functionality of your default controllers in the application and send all of the requests to the Location namespace.

    You should not put any route definitions into your LocationAreaRegistration.cs file. This will ensure they are run last and don't screw with any of your other area routes.

    Here is the definition of CultureConstraint. See this answer for more details about how to localize your routes.

    using System.Text.RegularExpressions;
    using System.Web;
    using System.Web.Routing;
    
    public class CultureConstraint : IRouteConstraint
    {
        private readonly string defaultCulture;
        private readonly string pattern;
    
        public CultureConstraint(string defaultCulture, string pattern)
        {
            this.defaultCulture = defaultCulture;
            this.pattern = pattern;
        }
    
        public bool Match(
            HttpContextBase httpContext, 
            Route route, 
            string parameterName, 
            RouteValueDictionary values, 
            RouteDirection routeDirection)
        {
            if (routeDirection == RouteDirection.UrlGeneration && 
                this.defaultCulture.Equals(values[parameterName]))
            {
                return false;
            }
            else
            {
                return Regex.IsMatch((string)values[parameterName], "^" + pattern + "$");
            }
        }
    }