January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Programmatic Model Binding Using UpdateModel()

 ASP.NET MVC offers model binding to capture form field values entered in a view. In many cases model binding to complex types serves the purpose. When the model type to fill from the values is known at development time, you can specify a parameter of that type. However, this is not always the case. That is where programmatic model binding comes handy. Programmatic model binding allows you to perform model binding at runtime based on some condition or processing logic.

Consider the following page.

The page captures details about workers doing certain job. The EmployeeID, FirstName and LastName fields are quite straightforward. The tricky thing is - depending on the selection in the Worker Type dropdown list you need to bind the values with two different types. When the Worker Type is Employee you want to bind the values to Employee object and when the Worker Type is Contract you want to bind values with ContractWorker object.

In this case the target type is dependent on the selection in the dropdown list. Obviously, you can't decide at development time as to which type is to be model bound. Let's see how programmatic model bind can be used in such a situation.

First of all, create a new ASP.NET MVC project and add two model classes - Employee and ContractWorker. These classes are shown below:

public class Employee
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class ContractWorker
{
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

In this example, both the classes area almost identical but that's not necessary. In addition to the properties to be model bound they can contain a different set of properties as per your requirement.

Index view

Now add a new controller (HomeController) and Index view. Then key-in the following markup in the Index view.

<h1>Enter Worker Details</h1>

<form action="/home/process" method="post">
    <table cellpadding="10" border="1">
        <tr>
            <td>Employee ID :</td>
            <td><input type="text" name="employeeid" /></td>
        </tr>
        <tr>
            <td>First Name :</td>
            <td><input type="text" name="firstname" /></td>
        </tr>
        <tr>
            <td>Last Name :</td>
            <td><input type="text" name="lastname" /></td>
        </tr>
        <tr>
            <td>Worker Type :</td>
            <td>
                <select name="workerType">
                    <option value="E">Employee</option>
                    <option value="C">Contract Worker</option>
                </select>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
</form>

The Index view consists of a <form> that submits to Process action as indicated in the action attribute. Although the above markup uses plain HTML tags, you could have also used HTML helpers.

UpdateModel() method

Now add the Process() action inside the HomeController as shown below:

[HttpPost]
public ActionResult Process(string workerType)
{

    if(workerType=="E")
    {
        Employee emp = new Employee();
        this.UpdateModel(emp);
        //do something with emp
    }

    if (workerType == "C")
    {
        ContractWorker worker = new ContractWorker();
        this.UpdateModel(worker);
        //do something with worker
    }

    return View("Index");
}

The Process() action takes a string parameter - workerType. Note that workerType is name of the dropdownlist on the Index view. This way you get the selection of Worker Type in the action. Then two if blocks check the workerType value. If it is E a new object of Employee is created. This object will be initially empty. To fill various properties of emp object you need to perform model binding. To accomplish this task UpdateModel() method of the Controller base class is called. The UpdateModel() method accepts an object and tries to model bind it with from the Request.QueryString or Request.Form collections.

Similarly, the other if block fills the ContractWorker object.

Once filled, you can use emp and worker objects as per your application's need.

TryUpdateModel() method

Although our application works as expected there is a catch. Run the application and enter a string in EmployeeID textbox. The call to UpdateModel() will throw an exception:

 

Your code throws  this exception because UpdateModel() can't convert string to integer. You can add try-catch to your code to deal with this kind of exception but there is an alternative - TryUpdateModel() method.

The TryUpdateModel() method is quite similar to UpdateModel() but it silently returns true or false instead of throwing an exception. That means TryUpdateModel() will return true if everything goes well, otherwise it will return false. So, your job is to simply check this return value instead of adding try-catch. The following code shows how this can be done.

[HttpPost]
public ActionResult Process(string workerType)
{
    bool flag = false;

    if(workerType=="E")
    {
        Employee emp = new Employee();
        flag = this.TryUpdateModel(emp);
        if (flag)
        {
            //do something with emp
        }
    }

    if (workerType == "C")
    {
        ContractWorker worker = new ContractWorker();
        flag = this.TryUpdateModel(worker);
        if (flag)
        {
            //do something with worker
        }
    }

    return View("Index");
}
}

As you can see, the return value of TryUpdateModel() is stored in flag variable. If this flag is true only then application specific processing is invoked.

If you try to run the application again and enter some string value in EmplyeeID textbox, this time you won't get any exception. The flag will be silently set to false.

That's it for now! Keep coding!!


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 21 November 2016


Tags : ASP.NET ASP.NET Core MVC C#