title: Asp.Net mvc 5 - How can I pass a complex object as route value in Html.ActionLink() so default model binder can map it?
body: <p>I have an object containing searching, sorting and paging parameters as well as an id of a record to be edited.</p>
  
  <p>I'd like to pass this object into Html.ActionLink() as a route value object, so that the resulting query string will be correctly mapped by the default model binder into the Edit action's parameter, which is an EditViewModel.</p>
  
  <p>The idea is that after the Edit action completes, it can redirect back to the Index and maintain the same paging/sorting position, in the same data set, and filtered by the same search string.</p>
  
  <p>Edit View Model:</p>
  
  <pre><code>public class EditViewModel
  {
      public SearchSortPageViewModel SearchSortPageParams { get; set; }
      public int Id { get; set; }
  
      public EditViewModel() 
      {
          SearchSortPageParams = new SearchSortPageViewModel();
          Id = 0;
      }
  
      public EditViewModel(SearchSortPageViewModel searchSortPageParams, int id)
      {
          SearchSortPageParams = searchSortPageParams;
          Id = id;
      }
  }
  
  public class SearchSortPageViewModel
  {
      public string SearchString { get; set; }
      public string SortCol { get; set; }
      public string SortOrder { get; set; }
      public int Page { get; set; }
      public int PageSize { get; set; }
  }
  </code></pre>
  
  <p>Edit action:</p>
  
  <pre><code>public ActionResult Edit(EditViewModel evm)
      {
          /* ... */
      }
  </code></pre>
  
  <p>When I do this in the view:</p>
  
  <pre><code>@model MyApp.Areas.Books.ViewModels.Books.IndexViewModel
  ...
  @{EditViewModel evm = new EditViewModel(Model.SearchSortPageParams, item.ID);}
  @Html.ActionLink("Edit", "Edit", evm)
  </code></pre>
  
  <p>I get this:</p>
  
  <pre><code>http://localhost:63816/Books/Books/Edit/4?SearchSortPageParams=MyApp.Areas.Base.ViewModels.SearchSortPageViewModel
  </code></pre>
  
  <p>But I want this:</p>
  
  <pre><code>http://localhost:63816/Books/Books/Edit/4?SearchSortPageParams.SearchString=abc&amp;SearchSortPageParams.SortCol=name&amp;SearchSortPageParams.SortOrder=asc&amp;SearchSortPageParams.Page=1&amp;SearchSortPageParams.PageSize=3
  </code></pre>
  
  <p>The only way I have been able to pass the object so far has been to manually prepare the query string, like this:</p>
  
  <pre><code>@{string theQueryString = "?SearchSortPageParams.SearchString=" + @evm.SearchSortPageParams.SearchString + "&amp;SearchSortPageParams.SortCol=" + @evm.SearchSortPageParams.SortCol + "&amp;SearchSortPageParams.SortOrder=" + @evm.SearchSortPageParams.SortOrder + "&amp;SearchSortPageParams.Page=" + @evm.SearchSortPageParams.Page + "&amp;SearchSortPageParams.PageSize=" + @evm.SearchSortPageParams.PageSize;}
  &lt;a href="@Url.Action("Edit", new { evm.Id })@(theQueryString)"&gt;Edit&lt;/a&gt;
  </code></pre>
  
  <p>I thought of writing a custom model binder, but it seems silly given that the default model binder already handles nested objects if formatted as a query string in the way it expects.</p>
  
  <p>I also thought of writing a custom object serializer which outputs a serial format which the default model binder expects, but haven't yet gone down that route.</p>
  
  <p>Finally, I thought of flattening out the EditViewModel so there is nothing nested, just have all the properties listed out flatly. But, it's not ideal.</p>
  
  <p>So, what is the best way to go?</p>