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.

Use BindProperty Attribute for Model Binding to Properties

Model binding allows you map request parameters to actions. This means action methods will have one or more parameters and those parameters will receive their values from the model binding framework. Model binding can be performed to simple types as well as complex types. In ASP.NET Core 2.0 you can perform model binding to properties in addition to action parameters. This article explains how.

Consider the following <form> from an ASP.NET Core view :

<form asp-action="Process" 
asp-controller="Home" method="post">
    <input name="Name" />
    <input name="Age" />
    <button type="submit">Submit</button>
</form>

Above form is POSTed to the Process() action of HomeController. It contains two textboxes - Name and Age - for entering the respective values. In order to grab the values entered by the user using model binding you can write the Process() action like this :

public IActionResult Process(string name, int age)
{
  ViewBag.Name = name;
  ViewBag.Age = age;

  return View();
}

Here you used model binding with simple types (string and int).

If you want you can wrap the Name and Age into a class :

public class Person
{
    public string Name { get; set; }
    public string Age { get; set; }
}

And then modify Process() action to use the Person type :

public IActionResult Process(Person p)
{
  ViewBag.Name = p.Name;
  ViewBag.Age = p.Age;

  return View();
}

If you output the Name and Age ViewBag properties on the Process view you will get the textbox values as expected.

So far so good. Now imagine that your HomeController takes this form :

public class HomeController : Controller
{
    public string Name { get; set; }
    public string Age { get; set; }

    public IActionResult Index()
    {
        return View();
    }


    public IActionResult Process()
    {
        ...
        ...
        return View();
    }
}

In this case the HomeController has two properties - Name and Age. And the Process() no longer takes any parameter. You wish to fill these properties through model binding.

If you run the application in its current form and observe the Name and Age properties after the form submission you will see this :

As you can see both the properties are null. This means model binding hasn't filled them by default.

Now change the HomeController as shown below :

public class HomeController : Controller
{
    [BindProperty]
    public string Name { get; set; }

    [BindProperty]
    public string Age { get; set; }

    ...
    ...
}

As you can see, the Name and Age properties are now decorated with [BindProperty] attribute. The [BindProperty] is an instruction to the model binding framework to bind the underlying property with the matching request parameter. If you run the application this time you will see this :

This time model binding did its job and filled the controller properties with the textbox values.

Once model binding to properties is in place, you can change Process() like this :

public IActionResult Process()
{
    ViewBag.Name = this.Name;
    ViewBag.Age = this.Age;

    return View();
}

Process() no longer takes any parameters and you directly use the Name and Age properties.

You can also use [BindProperty] with complex types. Consider the following code :

public class HomeController : Controller
{
    [BindProperty]
    public Person PersonData { get; set; }
    ...
    ...
}

The PersonData property is of type Person (the class you created earlier) and is decorated with [BindProperty] attribute. In this case Name and Age properties of Person will be filled with the textbox values.

And now your Process() will look like this :

public IActionResult Process()
{
    ViewBag.Name = this.PersonData.Name;
    ViewBag.Age = this.PersonData.Age;

    return View();
}

Properties of BindPropertyAttribute class

There are a couple of properties of [BindProperty] attribute that are useful in certain cases - Name and SupportsGet.

By default the model binding logic maps the form field names and the property names. If their is no match found the property doesn't get assigned any value. For example, a textbox named Name should have a property named Name for model binding to work as expected. If the property name is different than the form field name you can use the Name property of [BindProperty]. Here is an example :

[BindProperty(Name ="Name123")]

The above usage ensures that a textbox named Name123 is bound with the Name property of HomeController.

By default model binding works for POST requests. If you are using GET for submitting a form, you can use the SupportsGet property. Here is how you can use it :

[BindProperty(SupportsGet = true)]

[BindProperty] in Razor Pages

In the above example you used [BindProperty] with ASP.NET Core MVC application. You can also use [BindProperty] with Razor Pages. Let's see how.

Suppose you have two Razor pages - Index.cshtml and Process.cshtml. The <form> housed in the Index.cshtml looks like this :

<form asp-page="Process" method="post">
    <input name="Name" />
    <input name="Age" />
    <button type="submit">Submit</button>
</form>

Notice the use of asp-page attribute to post the values to Process.cshtml.

The code-behind of Process.cshtml will house the ProcessModel class. This class is shown below :

public class ProcessModel : PageModel
{
    [BindProperty]
    public string Name { get; set; }

    [BindProperty]
    public string Age { get; set; }

    public IActionResult OnPost()
    {
        ViewData["Name"] = this.Name;
        ViewData["Age"] = this.Age;

        return Page();
    }
}

The ProcessModel class has two properties Name and Age that are model bound using [BindProperty] attribute. The OnPost() method then uses the Name and Age properties to fill the ViewData dictionary.

If you want to use Person complex type the ProcessModel will look like this :

public class ProcessModel : PageModel
{
    [BindProperty]
    public Person PersonData { get; set; }

    public IActionResult OnPost()
    {
        ViewData["Name"] = this.PersonData.Name;
        ViewData["Age"] = this.PersonData.Age;

        return Page();
    }
}

Here you used PersonData property and decorated it with [BindProperty]. The OnPost() method now uses PersonData to fill the ViewData dictionary.

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 : 04 December 2017


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