1

I have two routes in my asp.net mvc app

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                name: "Default",
                url: "{culture}/{controller}/{action}/{id}",
                defaults: new { culture = CultureHelper.GetDefaultCulture(), controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

            routes.MapRoute(
                name: "Default no language",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

When i enter url http://localhost/galleryin browser, i'm redirected to http://localhost/, when i try http://localhost/gallery/index, i'm geting 404 error

 The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly.

Requested URL: /gallery/index

when i add any implemented language to url (http://localhost/en/gallery), app is working.

I'm new to routes and webapp programing, so i would appriciate if anyone could help me with this with detailed explanation how to fix this.

0

1 Answer 1

1

The problem is that you have two routes, but the first route will always bind because it can't tell the difference between {culture}/{controller}/{action}/{id} and {controller}/{action}/{id} when binding /gallery - is it a culture or just a controller name?

There's no way to tell without checking, it will just bind the first match.

If you remove the default values then it might work, but you will always have to specify the action and controller:

routes.MapRoute(
    name: "Default",
    url: "{culture}/{controller}/{action}/{id}",
    defaults: new { culture = CultureHelper.GetDefaultCulture(), 
    /* controller = "Home", action = "Index",*/ id = UrlParameter.Optional }
);

{culture}/{controller}/{action}/{id} will now bind:

  • /en/gallery/actionName
  • /en/controllerName/actionName
  • /en/controllerName/actionName/idValue

and {controller}/{action}/{id} will bind:

  • /gallery
  • /gallery/actionName
  • /gallery/actionName/idValue

Your other option is to create a custom route constraint to validate that the first value is a valid culture value:

public class IsValidCultureConstraint : IRouteConstraint
{
    public bool Match
        (
            HttpContextBase httpContext, 
            Route route, 
            string parameterName, 
            RouteValueDictionary values, 
            RouteDirection routeDirection
        )
    {

        if (string.IsNullOrWhiteSpace(values["culture"]))
        {
            return this.IsValidCulture();
        }

        return false;
    }

    private bool IsValidCulture(string cultureString)
    {
        //
        // Logic here to check valid culture(s)
        //

        // Example
        if (String.Equals(cultureString.Trim(), "en", 
               StringComparison.OrdinalIgnoreCase))
        {
            // English is valid
            return true;
        }

        return false;
    }
}


routes.MapRoute(
    name: "Default",
    url: "{culture}/{controller}/{action}/{id}",
    defaults: new { culture = CultureHelper.GetDefaultCulture(), 
    id = UrlParameter.Optional,
    constraints: new { culture = new IsValidCultureConstraint() }
});

With that in place, it will only ever match the first route if the value entered into the URL is a valid culture. Of course, you will need to provide the logic to perform the check properly.

Sign up to request clarification or add additional context in comments.

3 Comments

This works, and solves main problem as i could test it in short time, but now app is ignoring my default set culture, and takes default browser culture on start... Also, instead url like localhost/ on app start, it always goes to localhost/culture/home/index when i enter localhost in browser...
It's not possible for the two routes to coexist. If you have a default value for the culture constraint then your second route will never be used.
You could add the culture inbetween the action and the id {controller}/{action}/{culture}/{id},

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.