I will show you how to easily bind parameters to your action methods without using the querystring.

I have a page, MyPage, with a action method that looks like this:

public async Task<ActionResult> Index(MyPage currentPage, int myId)  
{
    var response = await this.thirdPartyApi.Get(myId);
    // Do something with the response and return a view
    var model = MyModel.Create(response);
    return View(model);        
}

I've also created the page in editmode, I named it MyExamplePage so I can access it like this: https://example.com/MyExamplePage

So, in order to populate the myId parameter I can call my page like this:

https://example.com/MyExamplePage?myId=1337

Asp.net will automatically populate the myId parameter from the querystring and everything works just fine, great. But, the URL looks kinda ugly, don't you think?

I want it to look like this instead: https://example.com/MyExamplePage/1337

This doesn't work right out the box, we will need to write some code. I got some great help from Johan Björnfot in this thread over at Episerver World.

It's actually really easy to make this work, here's what you will need to do:

  1. Create a class that inherits from IPartialRouter<MyPage, MyPage>
  2. Implement GetPartialVirtualPath and RoutePartial. In my case I was only interested in the RoutePartial method so I just returned null in GetPartialVirtualPath
  3. Extract and parse/validate the values in the RoutePartial method.
  4. Return the content.
  5. Register the partialrouter in Global.asax(or wherever you configure your routes). routes.RegisterPartialRouter(new ParameterPartialRouter());
  6. Done!

Here's the full code of my PartialRouter.

public class ParameterPartialRouter : IPartialRouter<MyPage, MyPage>
{
    public PartialRouteData GetPartialVirtualPath(
        MyPage content,
        string language,
        RouteValueDictionary routeValues,
        RequestContext requestContext)
    {
        return null;
    }

    public object RoutePartial(
        MyPage content,
        SegmentContext segmentContext)
    {
        var nextValue = segmentContext.GetNextValue(segmentContext.RemainingPath);
        int myId;
        if (Int32.TryParse(nextValue.Next, out myId))
        {
            segmentContext.RouteData.Values["myId"] = myId;
            segmentContext.RemainingPath = nextValue.Remaining;
        }
        return content;
    }
}