ASP.NET MVC Passing models by ActionLink

You'll have to serialize your model as a JSON string, and send that to your controller to turn into an object.

Here's your actionlink:

@Html.ActionLink("Next", "Lookup", "User", new { JSONModel = Json.Encode(Model.UserLookupViewModel), page = Model.UserLookupViewModel.curPage }, null)

In your controller, you'll need a method to turn your JSON data into a MemoryStream:

private Stream GenerateStreamFromString(string s)
{
  MemoryStream stream = new MemoryStream();
  StreamWriter writer = new StreamWriter(stream);
  writer.Write(s);
  writer.Flush();
  stream.Position = 0;
  return stream;
}

In your ActionResult, you turn the JSON string into an object:

public ActionResult YourAction(string JSONModel, int page)
{
  DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Model.UserLookupViewModel));
  var yourobject =  (UserLookupViewModel)ser.ReadObject(GenerateStreamFromString(JSONModel));
}

While I highly suggest you use a form to accomplish what your attempting to do here for security sake.

 @Html.ActionLink("Next", "Lookup", "User", new 
      { Forenames = Model.UserLookupViewModel.Forenames, 
        Surname = Model.UserLookupViewModel.Surname, 
        DOB = Model.UserLookupViewModel.DOB,  
        PostCode = Model.UserLookupViewModel.PostCode, 
        page = Model.UserLookupViewModel.curPage }, null)

MVC will map the properties appropriately doing this; however, this will use your url to pass the values to the controller. This will display the values for all the world to see.

I highly suggest using a form for security sake especially when dealing with sensitive data such as DOB.

I personally would do something like this:

 @using (Html.BeginForm("Lookup", "User")
 {
     @Html.HiddenFor(x => x.Forenames)
     @Html.HiddenFor(x => x.Surname)
     @Html.HiddenFor(x => x.DOB)
     @Html.HiddenFor(x => x.PostCode)
     @Html.HiddenFor(x => x.curPage)

     <input type="submit" value="Next" />
  }

You can have multiple of these type of forms on the page if needed.

Your controller then accepts a post but functions the same way:

 [HttpPost]
 public ActionResult Lookup(UserLookupViewModel m, int page = 0)
 {
     return this.DoLookup(m, page);
 }

You can't use an ActionLink to pass properties with a Link but you can do the following to get the same behavior.

<form action="/url/to/action" Method="GET">
  <input type="hidden" name="Property" value="hello,world" />
  <button type="submit">Go To User</button>
</form>

If you create a helper to generate these GET forms, you will be able to style them like they are regular link buttons. The only thing I caution against is that ALL forms on the page are susceptible to modification so I wouldn't trust the data. I'd rather just pull the data again when you get to where you are going.

I use the technique above when creating search actions and want to retain a search history and keep the back button working.

Hope this helps,

Khalid :)


P.S.

The reason this works.

@Html.ActionLink("Next", "Lookup", "User", Model.UserLookupViewModel, null)

Is because the parameter list of the ActionLink method is generalized to take an object, so it will take anything. What it will do with that object is pass it to a RouteValueDictionary and then try to create a querystring based on the properties of that object.

If you say that method is working above, you could also just try adding a new property to the viewmodel called Id and it will work like you wanted it to.