Search code examples
asp.net-mvcseot4mvc

T4MVC Links for SEO


I'm trying to switch our links over to T4MVC, and I'm having a small problem with parameters that aren't part of an action's signature. We have a route that goes something like this:

http://www.mydomain.com/{fooKey}/{barKey}/{barID}

==> leads to BarController.Details(barID).

fooKey and barKey are only added to the links for SEO purposes. (since bar is a child entity of foo, and we want to represent that hierarchy in the URL)

Up until now, we would use

<% =Html.ActionLink(bar.Name, "Details", "Bar", new {barID = bar.ID, fooKey = bar.Foo.Key, barKey = bar.Key}, null)%>

And that would lead us to BarController.Details(barID), while keeping fooKey and barKey in the URL.

Now that we started with T4MVC, we tried changing it to

<% =Html.ActionLink(bar.Name, MVC.Bar.Details(bar.ID), null)%>

Since barKey and fooKey are not part of the Details action signature, they are no longer visible in the URL.

Is there a way around this without having to add these parameters to the action signature?


Solution

  • Similar thing also came up on the T4MVC Forum (this thread). I think I'll go ahead and add support for it in T4MVC.

    Actually, I just thought of an interesting way to solve this. The problem with adding an overload to pass extra arguments is that you'd need to add similar overloads to all the other T4MVC extension methods that take an ActionResult, which can get messy.

    Instead, we can use a fluent approach to make this available everywhere with little effort. The idea is that you'll write:

    <%= Html.ActionLink(
        bar.Name,
        MVC.Bar.Details(bar.ID)
            .AddRouteValues(new {fooKey = bar.Foo.Key, barKey = bar.Key}))%>
    

    Or if you only needed to add one value:

    <%= Html.ActionLink(
        bar.Name,
        MVC.Bar.Details(bar.ID)
            .AddRouteValue("fooKey", bar.Foo.Key))%>
    

    Here is how AddRouteValues is implemented:

    public static ActionResult AddRouteValues(this ActionResult result, object routeValues) {
        return result.AddRouteValues(new RouteValueDictionary(routeValues));
    }
    
    public static ActionResult AddRouteValues(this ActionResult result, RouteValueDictionary routeValues) {
        RouteValueDictionary currentRouteValues = result.GetRouteValueDictionary();
    
        // Add all the extra values
        foreach (var pair in routeValues) {
            currentRouteValues.Add(pair.Key, pair.Value);
        }
    
        return result;
    }
    
    public static ActionResult AddRouteValue(this ActionResult result, string name, object value) {
        RouteValueDictionary routeValues = result.GetRouteValueDictionary();
        routeValues.Add(name, value);
        return result;
    }
    

    It would be great if you could give this a try and let me know how that works for you.

    thanks, David