Additional route values with Alias?

Topics: Core, Customizing Orchard, General, Writing modules
Mar 13, 2012 at 10:12 PM

I have some aliases that point to a custom route, that gets handled by a custom controller. The format is "lists/{list_name}", and that maps to a route that uses the pattern: "/lists/{listId}/{start}/{skip}". Start and skip are optional parameters used for paging, with default values of 0 and 10 respectively. 

An example Alias mapping: 

"/lists/custom-list-a" -> "lists/12345"

I tried this and so far everything works OK. I can load /lists/custom-list-a in the browser and it loads the list with Id 12345. The problem is that these lists are paged (displaying custom data that isn't handled by orchard). The paging works, but I'm using Html.RouteLink() to generate the paging links, and so the paging href's are all the non-SEO friendly versions, e.g., "lists/12345/10/10" for page 2, "lists/12345/20/10" for page 3. 

How can I make the paging links use the alias, so that the paging URL's look like "lists/custom-list-a/10/10" for page 2, "lists/custom-list-a/20/10" for page 3, etc? Is there a way from my controller to find out what alias was used? I don't think I can use Html.RouteLink() since I don't have a route defined that uses the SEO friendly URL of the Alias. 

Alternatively I could use autoroutepart and move the custom stuff in my Controller into the Driver. But I have the same question, if I do it this way how do I get the paging params to work with the Autoroute?

Mar 14, 2012 at 4:18 AM

Got a little further along with this. No longer have issues with the skip and take params, those are being appended fine. I was using RouteLink() (by habbit) which only matched a single route (the one with the listId rather than listName). Once I specified a 2nd route for listName and updated paging to use that route's name the skip and take params started rendering fine in the paging nav. 

Just need to figure out how to look up listId by listName (slug) now. I'm sure there is a much better way of doing this that I'm overlooking. 

Mar 14, 2012 at 4:51 AM

Got it working.

//Controller
        public ActionResult DisplayByListName(string listSlug, int start, int skip) {
            var routeRecord = _contentManager.Query<AutoroutePart, AutoroutePartRecord>()
                .Where(part => part.DisplayAlias != null && part.DisplayAlias == "lists/" + listSlug).List()
                .FirstOrDefault();

            if (routeRecord == null) {
                return HttpNotFound();
            }

            return DisplayList(routeRecord.ContentItem.Id, start, skip); 
        }

  • I added AutoroutePart to these content Items, all following the pattern "lists/{listSlug}",
  • Defined a custom route matching that pattern. The custom route has a high priority so it takes precedence over Orchard.Autoroute, sending the request to the controller action pasted above. That action looks up the content item Id in the db and runs the request through my original controller action that does all my custom work using the contentItem Id. 
  • Also rendering a list of all the lists via a menu at the top of the view. Used this code to do it: 

<a href="@Url.ItemDisplayUrl(list)">@list.Title</a>