Mvc - How to pass parameters in Html.BeginForm action url

In my previous post Authentication and Dynamic content in MVC using Model Binding I described how you can bind your model to input controls and then binding will transport the values back and forth between client and server. In this post I will extend this concept and show how to pass some additional parameters with FORM's post action along with the data that will be passed with model binding.

One of the common activities in an application is to perform search. For that we get input from user in text box ,some drop down or some other form of control. Then that information is passed back to server to perform search on some repository and return results to the user. In the sample project, I am trying to add a search box on my product listing page.

mvc search box

Model Binding With Text Box

To take advantage of model binding, I have bound my view to a ViewModel class in my application. One of the objects in this view model is QueryParameters which contains a property named Keywords. So in my FORM rendering, I have bound the text box to this property. Based on this approach the code looks like as below.

Razor View Code
@model ByteBlocks.ShoppingMall.Models.ProductListViewModel
    ViewBag.Title = "Products";

Controller Code
public ViewResult Search(ProductListViewModel model)
   return View();

This works like a champ. If I was not interested in filtering the search based on any other existing criteria, this will fly. But if you look at the image above, you will notice that on left side there is a navigation bar that has product categories. So if a user is interested in searching for some item in certain category, then I will have to let my Search action know about that as well. This means FORM's post action will need to carry more data. There are few approaches you could take.

  • We can take advantage of model binding by adding a new property, Category, to QueryParameter and then add a hidden field to form which will bind to this property.
  • Second approach would be to take advantage of Html.BeginForm method's overload and pass additional parameters to FORM's post data. Since I already have route that knows about product category, I can get the value of this route parameter using ViewContext and pass it back and forth. I like this approach because now I don't have to extend my view model object for something that may or may not be required. In this particular case product category was going to be part of the view model so it was perfect to take advantage of model binding. But there will be cases where you could take advantage of FORM's post data package itself and pass the data to server.

Based on the second approach the code changes as below.

Razor View Code
@using (Html.BeginForm("Search", "Product", new { category = ViewContext.RouteData.Values["category"] })) { @Html.EditorFor(m => m.QueryParameters.Keywords); <input type="submit" value="Search" /> }
Rendered Html
<div id="Div2">
<form action="/Product/Search?category=Apparel" method="post">
 <input class="text-box single-line" type="text" value="" />        
 <input type="submit" value="Search" />
Controller Code
public ViewResult Search(string category, ProductListViewModel model)
  return View();

Notice how rendered HTML has appended category as query string parameter to form's action URL. And Mvc framework passes that as parameter with same name in controller's action method.

View content of ViewContext

You can view content of ViewContext object in your page at any time by setting a break point in Razor view itself. Then in debugger's immediate window you can type ViewContext and go from there. Following snippet shows how I looked at contents of ViewContext object in my application.

Count = 4
    [0]: "Controller"
    [1]: "action"
    [2]: "category"
    [3]: "page"

In subsequent posts I will discuss some more tips and tricks related to Mvc4 using VS11.




23.9 °C / 75.0 °F

weather conditions Clouds

Monthly Posts

Blog Tags