skip to Main Content

Im trying to get my urls to look nice and seo friendly with slugs. I tought I suceeded but then my default routing stopped working.
When I go to this example.com/location/viewlocation/528 then the url ends up like example.com/528/a-nice-location

So thats good!
But now my normal stuff dosent work.
Typing in example.com/home/index results in the error

The parameters dictionary contains a null entry for parameter ‘id’ of non-nullable type ‘System.Int32’ for method ‘System.Web.Mvc.ActionResult ViewLocation(Int32, System.String)’ in ‘Oplev.Controllers.LocationController’. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

I have tried different solutions but I a missing something. Cant get it to work.

My code:
RouteConfig

routes.MapRoute(
            name: "view_location",
            url: "{id}/{slug}",
            defaults: new { controller = "Location", action = "ViewLocation", id = UrlParameter.Optional, slug = UrlParameter.Optional }
        );

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

Location controller

public ActionResult ViewLocation(int id, string slug)
    {
        if (string.IsNullOrEmpty(slug))
        {
            slug = "a-nice-location"; // testing..
            return RedirectToRoute("view_location", new { id = id, slug = slug });
        }
        return View();
    }

Home controller

    public ActionResult Index()
{
    return View();
}

3

Answers


  1. Chosen as BEST ANSWER

    Ok so I somehow ended up with something that works! Changed routing for view_location to this:

                routes.MapRoute(
                name: "view_location",
                url: "{id}/{slug}",
                defaults: new { controller = "Location", action = "ViewLocation", slug = UrlParameter.Optional},
                constraints: new { id = @"d+" }
            );
    

  2. Your first route matches anything with 0, 1 or 2 segments in the url. For example it matches ../Home/Index. You need some way to distinguish it, for example you could make it

    routes.MapRoute(
        name: "view_location",
        url: "ViewLocation/{id}/{slug}",
        defaults: new { controller = "Location", action = "ViewLocation", slug = UrlParameter.Optional }
    );
    

    or you could add a route constraint

    Note also that only the last parameter can be marked as UrlParameter.Optional, but in your case the id is not optional anyway

    Login or Signup to reply.
  3. This is meant to supplement the already given answers. Attribute routing with route constraints will also work.

    First make sure attribute routing is enabled in RouteConfig

    //Attribute routing
    routes.MapMvcAttributeRoutes(); // placed before convention-based routes
    
    //convention-based routes
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
    

    Next use the necessary Route attributes on the controller

    [HttpGet]
    [Route("{id:int}/{*slug?}", Name = "view_location")] // Matches GET 528/some-nice-location
    public ActionResult ViewLocation(int id, string slug) {
        if (string.IsNullOrEmpty(slug)) {
            slug = "a-nice-location"; // testing..
            return RedirectToRoute("view_location", new { id = id, slug = slug });
        }
        return View();
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search