Custom route for writing friendly URLs in ASP.NET MVC 3 I'm trying to build friendly URLs like /post/1/my-first-post. I started out with building my links like this: 

@Html.ActionLink(Model.BlogPost.Title, "Index", "Post", new
{
   id = Model.BlogPost.Id,
   title = Model.FriendlyUrl
}, 
new { })


which were processed by this route:

routes.MapRoute(
   "Post", // Route name
   "posts/{id}/{title}", // URL with parameters
    new { controller = "Post", action = "Index" }, // Parameter defaults
    new { id = "^[0-9]+$" }
 );


When I create my view model, I would give it an IUrlNiceName which it used to create the output of FriendlyUrl:

public string FriendlyUrl
{
    get{ return UrlNiceName.ConvertToNiceName(BlogPost.Title); }
}


Then I felt like I didn't want to manage UrlNiceName-ing on the controller level so then I build a custom Route to do this for me:

public class NiceNameRoute : RouteBase
{
    private IUrlNiceNames UrlNiceNames { get; set; }
    private string UrlPrefix { get { return "post/"; } }

    public NiceNameRoute(IUrlNiceNames urlNiceNames)
    {
        UrlNiceNames = urlNiceNames;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;
        string requestedURL = httpContext.Request.AppRelativeCurrentExecutionFilePath;

        //match e.g. post/1 or post/1/my-first-post
        Regex regex = new Regex(UrlPrefix + "[0-9]+($|/)");

        if (regex.Match(requestedURL).Success)
        {
            //get the start of the post id
            int prefixPos = requestedURL.IndexOf(UrlPrefix, StringComparison.OrdinalIgnoreCase);
            int startIdPos = prefixPos + UrlPrefix.Length;

            //get the end of the post id
            int endIdPos = requestedURL.IndexOf("/", startIdPos, StringComparison.OrdinalIgnoreCase);
            endIdPos = endIdPos == -1 ? requestedURL.Length : endIdPos;

            //get post id
            string id = requestedURL.Substring(startIdPos, endIdPos - startIdPos);

            result = new RouteData(this, new MvcRouteHandler());
            result.Values.Add("controller", "Post");
            result.Values.Add("action", "Index");
            result.Values.Add("id", id);
        }

        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext,
        RouteValueDictionary values)
    {
        VirtualPathData result = null;

        if (values.ContainsKey("title")
            &amp;&amp; Convert.ToString(values["action"]) == "Index"
            &amp;&amp; Convert.ToString(values["controller"]) == "Post")
        {
            string niceName = UrlNiceNames.ConvertToNiceName(Convert.ToString(values["title"]));

            result = new VirtualPathData(this, UrlPrefix + Convert.ToString(values["id"]) + "/" + niceName);
        }
        return result;
    }
}


which I registered like this:

routes.Add(new NiceNameRoute(new HyphenUrlNiceNames()));


and generate links like this:

@Html.ActionLink(Model.BlogPost.Title, "Index", "Post", new
{
   id = Model.BlogPost.Id,
   title = Model.BlogPost.Title
}, 
new { })


I first wanted to take a crack at this but now I want to know how industry experts do it. Am I over engineering? Is there a simpler approach that is also elegant? Are there any issues with my custom Route?
Personally I think you are over thinking it. Why not just create a string extension method called FriendlyString or PrepareForUrl and then use the original route 

@Html.ActionLink(Model.BlogPost.Title, "Index", "Post", new
{
   id = Model.BlogPost.Id,
   title = Model.BlogPost.Title.FriendlyString()
}, null)