Using BindAttribute In ASP.NET MVC To Exclude Bindable Data
If you've used MVC you'll know how much time is saved thanks to model binding. That's where a form post is matched to a strongly typed object. This can save you time initially but it can also provide a way for a malicious user to exploit vulnerabilities in your code if you're not careful. You can optionally override what values to bind and what not to bind automatically. In my opinion it's better to code what not to allow in this case.
To demonstrate this imagine you had an application that added new employees to your company. You could enter their department, given name, surname and salary. Here's what the Employee class might look like:
C#
public class Employee
{
public string Department { get; set; }
public string GivenName { get; set; }
public string Surname { get; set; }
public double Salary { get; set; }
}
VB.NET
Public Class Employee
Private privateDepartment As String
Public Property Department() As String
Get
Return privateDepartment
End Get
Set(ByVal value As String)
privateDepartment = value
End Set
End Property
Private privateGivenName As String
Public Property GivenName() As String
Get
Return privateGivenName
End Get
Set(ByVal value As String)
privateGivenName = value
End Set
End Property
Private privateSurname As String
Public Property Surname() As String
Get
Return privateSurname
End Get
Set(ByVal value As String)
privateSurname = value
End Set
End Property
Private privateSalary As Double
Public Property Salary() As Double
Get
Return privateSalary
End Get
Set(ByVal value As Double)
privateSalary = value
End Set
End Property
End Class
Salary is one value that you don't want any user to be able to adjust through this system. You could create your form so it hides the salary input field like this:
However if you did use model binding without setting any exclusions, a user could create a totally separate form and add the salary field to the form post. By doing this the user would be able to set their own salary!
One way to stop this is to add exclusions to your action and explicitly state what can and can't be binded. Here's one example of how to do that:
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateWithAttributeBinding([Bind(Exclude = "Salary")] Employee emp)
{
var employee = new Employee();
if (!TryUpdateModel(employee))
{
// an error occured
return View("Create");
}
else
{
// add to database
return RedirectToAction("Create");
}
}
VB.NET
<AcceptVerbs(HttpVerbs.Post)> _
Public Function CreateWithAttributeBinding(<Bind(Exclude := "Salary")> ByVal emp As Employee) As ActionResult
Dim employee = New Employee()
If (Not TryUpdateModel(employee)) Then
' an error occured
Return View("Create")
Else
' add to database
Return RedirectToAction("Create")
End If
End Function
Notice in the code above there's this line:
C#
([Bind(Exclude = "Salary")] Employee emp
VB.NET
((Bind(Exclude = "Salary")) Employee emp
By adding this line of code I'm explicitly saying that Salary cannot be set from the form post. Even if the user posts data from their fake form, the salary amount will be ignored.
That's one way to override exclusions. Another way which is a little cleaner is by using an interface to define what fields are to be excluded. I'll create an interface called IEmployeeBinding and have Employee inherit from that:
C#
public interface IEmployeeBinding
{
string Department { get; set; }
string GivenName { get; set; }
string Surname { get; set; }
}
public class Employee : IEmployeeBinding
{
public string Department { get; set; }
public string GivenName { get; set; }
public string Surname { get; set; }
public double Salary { get; set; }
}
VB.NET
Public Interface IEmployeeBinding
Property Department() As String
Property GivenName() As String
Property Surname() As String
End Interface
Public Class Employee
Implements IEmployeeBinding
Private privateDepartment As String
Public Property Department() As String Implements IEmployeeBinding.Department
Get
Return privateDepartment
End Get
Set(ByVal value As String)
privateDepartment = value
End Set
End Property
Private privateGivenName As String
Public Property GivenName() As String Implements IEmployeeBinding.GivenName
Get
Return privateGivenName
End Get
Set(ByVal value As String)
privateGivenName = value
End Set
End Property
Private privateSurname As String
Public Property Surname() As String Implements IEmployeeBinding.Surname
Get
Return privateSurname
End Get
Set(ByVal value As String)
privateSurname = value
End Set
End Property
Private privateSalary As Double
Public Property Salary() As Double
Get
Return privateSalary
End Get
Set(ByVal value As Double)
privateSalary = value
End Set
End Property
End Class
Nothing too complex about the code above. Where the magic happens is in the controller. You can take advantage of TryUpdateModel and update the model instance using values from the current values:
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateWithInterfaceBinding()
{
var employee = new Employee();
if (!TryUpdateModel<IEmployeeBinding>(employee))
{
// an error occured
return View("Create");
}
else
{
// add to database
return RedirectToAction("Create");
}
}
VB.NET
<AcceptVerbs(HttpVerbs.Post)> _
Public Function CreateWithInterfaceBinding() As ActionResult
Dim employee = New Employee()
If (Not TryUpdateModel(Of IEmployeeBinding)(employee)) Then
' an error occured
Return View("Create")
Else
' add to database
Return RedirectToAction("Create")
End If
End Function
The line below does the work for us:
C#
if (!TryUpdateModel<IEmployeeBinding>(employee))
VB.NET
If (Not TryUpdateModel(Of IEmployeeBinding)(employee)) Then
The code will create a new instance of an employee and bind the values according to what properties have been specified by the interface. Pretty neat huh?!
You should always add exclusions to your actions whenever you accept user input that can change state. This way you'll become a more defensive programmer.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @
malcolmsheridan