Interesting question (+1). I assume that the goal is to use the default middleware to bind the request parameters to your Action
parameters.
Out of the box, I do not believe that the ActionLink
method will do this for you (of course, there is nothing that prevents you from skating on your own). Looking at the reflector, we see that when an object
added to a RouteValueDictionary
, only pairs of key values ββare added. This is code that adds key value pairs, and, as you can see, there is no intersection of object properties.
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values)) { object obj2 = descriptor.GetValue(values); this.Add(descriptor.Name, obj2); }
So for your object
var values = new { Filter = new Filter { MessageFilter = item.Message } }
the Filter
key to add, and this is your Filter
object, which will evaluate the full name of your object type.
The result of this is Filter=Youre.Namespace.Filter
.
Change the solution to your specific needs.
The extension method does the job
Note that it uses the ExpressionHelper
and ModelMetadata
static structure ModelMetadata
(which are also used by existing helpers) to determine the appropriate names that will understand the default binder and property value, respectively.
public static class ExtentionMethods { public static MvcHtmlString ActionLink<TModel, TProperty>( this HtmlHelper<TModel> helper, string linkText, string actionName, string controllerName, params Expression<Func<TModel, TProperty>>[] expressions) { var urlHelper = new UrlHelper(helper.ViewContext.HttpContext.Request.RequestContext); var url = urlHelper.Action(actionName, controllerName); if (expressions.Any()) { url += "?"; foreach (var expression in expressions) { var result = ExpressionHelper.GetExpressionText(expression); var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, helper.ViewData); url = string.Concat(url, result, "=", metadata.SimpleDisplayText, "&"); } url = url.TrimEnd('&'); } return new MvcHtmlString(string.Format("<a href='{0}'>{1}</a>", url, linkText)); } }
Model Examples
public class MyViewModel { public string SomeProperty { get; set; } public FilterViewModel Filter { get; set; } } public class FilterViewModel { public string MessageFilter { get; set; } }
Act
public ActionResult YourAction(MyViewModel model) { return this.View( new MyViewModel { SomeProperty = "property value", Filter = new FilterViewModel { MessageFilter = "stuff" } }); }
Using
Any number of your view model properties can be added to the queue using the last parameter of the params
method.
@this.Html.ActionLink( "Your Link Text", "YourAction", "YourController", x => x.SomeProperty, x => x.Filter.MessageFilter)
Markup
<a href='/YourAction/YourController?SomeProperty=some property value&Filter.MessageFilter=stuff'>Your Link Text</a>
Instead of using string.Format
you can use TagBuilder
, querystring should be encoded to pass the URL safely, and this extension method will require additional verification, but I think it might be useful. Also note that although this extension method was created for MVC 4, it can easily be changed for previous versions. I did not understand that one of the MVC tags was for version 3 so far.