Home MVC url routing with slug and id. Makes a mess with default routing
Reply: 3

MVC url routing with slug and id. Makes a mess with default routing

Christian Thoresson Dahl
1#
Christian Thoresson Dahl Published in 2017-09-14 09:23:04Z

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();
}
Christian Thoresson Dahl
2#
Christian Thoresson Dahl Reply to 2017-09-14 09:36:51Z

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+" }
        );
Stephen Muecke
3#
Stephen Muecke Reply to 2017-09-14 09:38:02Z

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

Nkosi
4#
Nkosi Reply to 2017-09-14 09:57:14Z

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();
}
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.375173 second(s) , Gzip On .

© 2016 Powered by cudou.com design MATCHINFO