JSON Binding Support to Post Action Method with ViewModel in ASP.NET MVC 3

ViewModel object is very good solution for form posting when used within internal application. But, what if your ASP.NET MVC application needs to communicate with outside world? There’s JSON Binding Support in ASP.NET MVC 3.

The best part is, ViewModel object can still be used in this approach.

Controller to process post back:

[HttpPost]
public ActionResult SubmitPostObject(Development.MvcApp.Models.Person objectModel)
{
    return Json(objectModel);
}

The ViewModel:

public class Person
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
}

To test this, I will use Poster, an add-on for Mozilla Firefox.

As you can see, I specify the following Json object to be sent to the Controller:

{ "Firstname": "Alexander", "Lastname": "Witt", "Email": "awitt@gmail.com", "PhoneNumber": "(756) 847-7236" }

For simple demonstration purpose, the Controller only returns Json object pass to it. Here’s the response from Poster:

Obviously, you can also specify your Controller to return any type of result object.

Few important things to note:

  1. This is new feature in ASP.NET MVC 3 (See “JavaScript and AJAX Improvements“).
  2. The JSON object’s strings (‘Firstname’, ‘Lastname’, ‘Email’, and ‘PhoneNumber’) must match ViewModel object’s properties.
  3. ViewModel object’s properties must have “{ get; set; }” method.
  4. Must specify Content Type as “application/json” in the request.
  5. If it’s still not working, check the JSON string to make sure it’s valid one.

Using Domain Model and / or View Model with Post Action in ASP.NET MVC

Although using FormCollection is a  better way to get values from View to Controller than this post, I’d say the better (or best, if you prefer…) practice is to use Domain Model and / or View Model.

Beside the parameter simplicity in the methods, Domain Model and View Model also gives you a strongly typed implementation.

Another advantage of using Domain Model or View Model is whenever you need to change property of the object, there is no need to change the View / Controller. All you need to do is change the model.

Again, here are my Controllers, one for display the page, one for process page post back:

public ActionResult SubmitFormWithDomainOrViewModel()
{
    return View();
}
[HttpPost]
public ActionResult SubmitFormWithDomainOrViewModel(Development.MvcApp.Models.Person person)
{
    return View(person);
}

Notice how simple the post method’s parameter. Also, I do not need to iterate through the object to pass it back to the View. All I did was pass the whole model object to the View.

Here’s my Person (Domain Model) object:

public class Person
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
}

It’s normal to put the model object in Models folder:

And finally, the View:

@model Development.MvcApp.Models.Person

@{
    ViewBag.Title = "Submit Form With Domain or View Model";
}

<h2>Submit Form With Domain or View Model</h2>

@using (Html.BeginForm()) {

    <div>
        @{
            if (Model != null)
            {
                <span>You have submitted:</span><br />
                <span>Firstname:</span> @Model.Firstname<br />
                <span>Lastname:</span> @Model.Lastname<br />
                <span>Email:</span> @Model.Email<br />
                <span>PhoneNumber:</span> @Model.PhoneNumber<br />
            }
        }
    </div>
    <br />

    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Person</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Firstname)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Firstname)
            @Html.ValidationMessageFor(model => model.Firstname)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Lastname)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Lastname)
            @Html.ValidationMessageFor(model => model.Lastname)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Email)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Email)
            @Html.ValidationMessageFor(model => model.Email)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PhoneNumber)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PhoneNumber)
            @Html.ValidationMessageFor(model => model.PhoneNumber)
        </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

When the page is loaded, it looks like:

And when it’s posted:

Create The View

I created the View based on Person model object. To do this, right click on the folder under “Views” where you want to add the view in the Solution Explorer window > Add > View.

To create strongly typed View, you have to check “Create a strongly-typed view” and specified the model you want to based it on.

In “Scaffold template”, you can also specified whether you want the View to create, edit, delete, details, or list the model object.

Update 4.19.2011: In my example above, I used Domain Model, although the screenshot said ViewModel. As pointed out by our reader, Brady, View Model in this case would be: using Person object as well as whatever other objects you want to pass to the view.

So, for example: supposedly I have another object that I want to pass to my View along with my Person object, let’s call this object Car.

public class Car
{
    public string Make { get; set; }
    public string Model { get; set; }
    public string Year { get; set; }
    public string Color { get; set; }
}

My ViewModel would be something like:

public class PersonCarViewModel
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public string Year { get; set; }
    public string Color { get; set; }
}

I can then pass this PersonCarViewModel object to my View just like I did with Person model object earlier. The View will then have access to all properties in this View Model.

Iterate Through System.Web.Mvc.FormCollection

These are some of the ways to iterate through System.Web.Mvc.FormCollection:

FormCollection.AllKeys

public ActionResult DisplayFormCollection(FormCollection formCollection)
{
    foreach (var _key in formCollection.AllKeys)
    {
        var _value = formCollection[_key];
    }

    return View();
}

FormCollection.Keys

public ActionResult DisplayFormCollection(FormCollection formCollection)
{
    foreach (var _key in formCollection.Keys)
    {
        var _value = formCollection[_key.ToString()];
    }

    return View();
}

FormCollection.ToValueProvider()

public ActionResult DisplayFormCollection(FormCollection formCollection)
{
    var _valueProvider = formCollection.ToValueProvider();

    foreach (var _key in _valueProvider.Keys)
    {
        var _value = _valueProvider[_key];
    }

    return View();
}

FormCollection[]

public ActionResult DisplayFormCollection(FormCollection formCollection)
{
    foreach (var _key in formCollection)
    {
        var _value = formCollection[_key];
    }

    return View();
}

MSDN resource: System.Web.Mvc.FormCollection

Get Form’s Post Values in ASP.NET MVC with FormCollection

In addition to this post, you can also get the form’s post values with System.Web.Mvc.FormCollection in ASP.NET MVC 2 or MVC 3.

Here are my controllers, one for display the page, one for process page post back:

public ActionResult SubmitFormWithFormCollection()
{
    return View();
}
[HttpPost]
public ActionResult SubmitFormWithFormCollection(FormCollection formCollection)
{
    foreach (string _formData in formCollection)
    {
        ViewData[_formData] = formCollection[_formData];
    }

    return View();
}

Here’s my code in Razor view engine:

@{
    ViewBag.Title = "Submit Form With FormCollection";
}

<h2>Submit Form with FormCollection</h2>

@using (Html.BeginForm())
{
    <div>
        You have submitted:<br />
        Firstname: @ViewData["firstname"]<br />
        Lastname: @ViewData["lastname"]<br />
        Email: @ViewData["email"]<br />
    </div>
    <br />

    <label for="firstname">Firstname:</label>
    <input type="text" name="firstname" />
    <br />
    <label for="lastname">Lastname:</label>
    <input type="text" name="lastname" />
    <br />
    <label for="email">Email:</label>
    <input type="text" name="email" />
    <br />
    <br />

    <input type="submit" name="submit" />
}

When the view is loaded, it looks like:

And when it posted:

FormCollection (System.Web.Mvc.FormCollection) class contains key / value pairs from all the fields in the form submitted.

The FormCollection’s key is the ‘name’ attribute of the HTML control field in the form while the value is the user’s input to that field. So, to get value of the ‘firstname’ field, I can do:

[HttpPost]
public ActionResult SubmitFormWithFormCollection(FormCollection formCollection)
{
    ViewData["firstname"] = formCollection["fistname"];

    return View();
}

There are many ways to iterate through System.Web.Mvc.FormCollection. See this post for detail.

Submit Form with Parameters in ASP.NET MVC

When you have a form, you can use controller’s parameters to get form’s data and process it.

Here are my controllers, one for display the page, one for process page post back:

public ActionResult SubmitFormWithParameters()
{
    return View();
}
[HttpPost]
public ActionResult SubmitFormWithParameters(string firstname, string lastname, string email)
{
    ViewData["firstname"] = firstname;
    ViewData["lastname"] = lastname;
    ViewData["email"] = email;

    return View();
}

Here’s my code in Razor view engine:

@{
    ViewBag.Title = "Submit Form With Parameters";
}

<h2>Submit Form With Parameters</h2>

@using (Html.BeginForm())
{
    <div>
        You have submitted:<br />
        Firstname: @ViewData["firstname"]<br />
        Lastname: @ViewData["lastname"]<br />
        Email: @ViewData["email"]<br />
    </div>
    <br />

    <label for="firstname">Firstname:</label>
    <input type="text" name="firstname" />
    <br />
    <label for="lastname">Lastname:</label>
    <input type="text" name="lastname" />
    <br />
    <label for="email">Email:</label>
    <input type="text" name="email" />
    <br />
    <br />

    <input type="submit" name="submit" />
}

So, when the view is loaded, it looks like:

And when it posted:

So, what happen is when you fill out the form and submit it, the controller automatically picks up the post value of the fields you have specified from the form that is submitted. One thing to keep in mind in order to map the fields correctly with your parameters is that your parameters for the controller must match the name of the form’s fields.

Also, this example is simplified. Obviously, using ViewData is not recommended in full blown application and this example is not ideal when you have a lot of fields in the form.

ASP.NET MVC 2 And MVC 3 Relative Path

Sometime, you just need to work with MVC 2 and have no choice although MVC 3 is out there. Here’s another MVC 2 tip on how to use relative path.

This is especially useful (and important) when deploy to IIS. What I’d seen is, the CSS / images / javascript / jquery would work in local machine, but not in IIS. Most likely it’s because the path to CSS / images / javascript / jquery files in your Site.Master / *.aspx / *.ascs / *.cshtml.

  1. For master page, add the following page directive in Site.Master:
    <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
    
  2. For *.aspx pages, make sure you have the following page directive (you might / might not have MasterPageFile attribute):
    <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
    
  3. The relative path format (for master page and *.aspx) should look like:
    <link href="<%=  Url.Content("~/Content/Site.css")%>" media="all" rel="stylesheet" type="text/css" />
    
  4. The relative path format (*.cshtml) should look like (note that *.cshtml doesn’t need any page directive defined):
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    

Convert ASP.NET MVC 2 Project to ASP.NET MVC 3 (Visual Studio)

  1. Remove the following references:
    System.Web.Mvc (v 2.0)
  2. Add the following references:
    System.Web.Mvc (v 3.0)
    System.Web.Helpers
    System.Web.WebPages
  3. Here’s my final references:

    If you don’t have any of the above references, you might want to add them.
  4. Add / modify the root Web.config file for the following sections:
    <configuration>
        <appSettings>
            <add key="ClientValidationEnabled" value="true"/>
            <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
        </appSettings>
    </configuration>
    
    <configuration>
        <system.web>
            <compilation debug="true" targetFramework="4.0">
                <assemblies>
                    <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                    <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
                </assemblies>
            </compilation>
        </system.web>
    </configuration>
    
    <system.web>
        <pages>
            <namespaces>
                <add namespace="System.Web.Helpers" />
                <add namespace="System.Web.Mvc" />
                <add namespace="System.Web.Mvc.Ajax" />
                <add namespace="System.Web.Mvc.Html" />
                <add namespace="System.Web.Routing" />
                <add namespace="System.Web.WebPages"/>
            </namespaces>
        </pages>
    </system.web>
    
  5. Add / modify the view Web.config file for the following sections:
    <configuration>
        <configSections>
            <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
                <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
                <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
            </sectionGroup>
        </configSections>
    </configuration>
    
    <configuration>
        <system.web.webPages.razor>
            <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            <pages pageBaseType="System.Web.Mvc.WebViewPage">
                <namespaces>
                    <add namespace="System.Web.Mvc" />
                    <add namespace="System.Web.Mvc.Ajax" />
                    <add namespace="System.Web.Mvc.Html" />
                    <add namespace="System.Web.Routing" />
                </namespaces>
            </pages>
        </system.web.webPages.razor>
    </configuration>
    

ASP.NET MVC with Optional Query String (without Modifying Map Route Table)

In MVC, you can have optional query string that looks like this:

http://localhost:51778/Home/UrlWithQueryString?firstname=John&lastname=Doe

The ‘firstname’ and ‘lastname’ are optional query string.

See the screenshots below:

But also works without one of the query strings:

Here’s my controller code:

public ActionResult UrlWithQueryString(string firstname, string lastname)
{
    ViewData["Firstname"] = firstname;
    ViewData["Lastname"] = lastname;

    return View();
}

And here’s the view (both in ASPX and Razor view engine):

ASPX View Engine

<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    <h2>UrlWithQueryString</h2>
    <%= Html.Encode(ViewData["Firstname"]) %>
    <%= Html.Encode(ViewData["Lastname"]) %>
</asp:Content>

Razor View Engine

@{
    ViewBag.Title = "UrlWithQueryString";
}

<h2>UrlWithQueryString</h2>

@ViewData["Firstname"] @ViewData["Lastname"]

Check If IEnumerable<> or List<> Type is Empty / Null

There are three ways to check whether IEnumerable<> or List<> type is empty / null or not.

== null

List<string> EquipmentList = new List<string>();

if (EquipmentList != null)
{
    // True, the list is not empty
}
else
{
    // False, the list is empty
}

.Any()

List<string> EquipmentList = new List<string>();

if (EquipmentList.Any())
{
    // True, the list is not empty
}
else
{
    // False, the list is empty
}

.Count()

List<string> EquipmentList = new List<string>();

if (EquipmentList.Count() != 0)
{
    // True, the list is not empty
}
else
{
    // False, the list is empty
}

I am using List<> type here, but this can also be applied to IEnumerable<> type.

In any case, you always want to combine “== null” and, either “.Any()” or “.Count()”, with OR (“||”) operator.

In addition, you want to put “== null” before the other condition. The reason for this is, “if” condition goes from left to right. So, if the list object is null, it will not go to second check, which will result in “Object reference not set to an instance of an object” exception if the list object is null.

List<string> EquipmentList = new List<string>();

if (EquipmentList != null || EquipmentList.Count() != 0)
{
    // True, the list is not empty
}
else
{
    // False, the list is empty
}

MVC Music Store for ASP.NET MVC 2 (ASPX View Engine)

The ASP.NET MVC website is currently on MVC 3, so the sample applications, specifically MVC Music Store, have also been updated to MVC 3 with Razor view engine.

If you want to download the “ASPX” view engine version of the sample applications, you can do so in CodePlex website. All previous versions are also available.

Here’s the link to MVC Music Store, ASPX view engine version: MVC Music Store v0.8. The cool thing is, you can also download the step by step tutorial for this version in the PDF format.