Nick
Nick

Reputation: 5892

Using the Bind attribute on a ViewModel class in ASP.NET MVC

Why might a developer use the Bind attribute on a ViewModel object in an ASP.NET MVC project and can this have a detrimental effect an application?

[Bind(Include = "Id,Name")]
[MetadataType(typeof (MyViewModelValidation))]
public class MyViewModel
{
    public string CustomerProductUserName { get; set; }

    [Display(Name = "Name")]
    public string Name { get; set; }

}

public class MyViewModelValidation
{
    [HiddenInput(DisplayValue = false)]
    public int Id { get; set; }

    [Required]
    public string Name{ get; set; }
}

Upvotes: 17

Views: 32509

Answers (4)

juFo
juFo

Reputation: 18587

In addition, if you want to prevent refactoring issues when renaming properties from your model you could do something like:

public async Task<ActionResult> Create([Bind(Include = nameof(Foo.Bar1)+","+nameof(Foo.Bar2)+","+nameof(Foo.Bar3))] Foo fooObj)

If you now e.g. rename "Bar1" your Include Bindings will still work.

Upvotes: 5

Chandra Malla
Chandra Malla

Reputation: 2449

The purpose of using bind attribute is to prevent attacker from assigning property value while posting of request or control what properties you want to bind.

Let us suppose, you have a class called Member and a create method that saves member. But you do not want user to send a value for MemberType property.

Class Member  
{  
    public int MemberId { get; set; }  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
    public string MemberType { get; set; }  
}  

[HttpPost]  
Public ActionResult Create(Member member)  
{  
    Save(member);  
}

Let's say for now, you are only offering Regular member type which is the default value. You might think that you can prevent the user to send a value for MemberType property by not allowing input for MemberType Property. But when a user posts the member object, an attacker may intercept the request and send the MemberType value in request, as MemberId=1&FirstName=Chandra&LastName=Malla&MemberType=Premium and save the member as a Premium member. To prevent this, you can decorate Member class with Bind attribute.

[Bind(Include="MemberId,FirstName,LastName")]  
Class Member  
{
    ...

or

[Bind(Exclude="MemberType")]  
Class Member  
{  
    ...

Now if Member object is posted, MemberType property value will not be posted.

If you are using ViewModel, you might not necessarily have to use bind attribute because you can omit MemberType properties in your ViewModel.

Class Member  
{  
    public int MemberId { get; set; }  
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
    public string MemberType { get; set; } 
}  

Class MemberViewModel  
{       
    public int MemberId { get; set; }   
    public string FirstName { get; set; }  
    public string LastName { get; set; }  
}  

[HttpPost]  
Public ActionResult Create(MemberViewModel memberviewmodel)  
{  
    Save(memberviewmodel);  
}

If you do not nicely design your model and/or ViewModel and do not use bind attribute to avoid posting of property you do not want, that might have detrimental effect.

Upvotes: 15

ataravati
ataravati

Reputation: 9155

First of all, you don't need to create a MetadataType class for a ViewModel. You can use data annotation attributes directly in your ViewModel. MetadataType classes are used for Models automatically generated by EF or other ORMs, so that you can use data annotation attributes without touching the auto-generated code.

The Bind attribute does not have to be used either - unless you want to use Include or Exclude properties of the Bind attribute, to include or exclude properties in your Model in or from binding, respectively.

For example, in the code in your question, only the Id and Name properties will be bound when submitting your Model from your View. Even if you have an input in your View for CustomerProductUserName, when you submit your form, the property will always be null. This can be useful in cases like where you don't want an auto-generated ID field to be included in binding.

Properties excluded from binding are also excluded from validation, because validation is done as part of model binding. Also, you may use the Bind attribute for security reasons; for instance, when you want to make sure nothing but the properties in your model are being posted to the controller.

Upvotes: 21

Abbas Amiri
Abbas Amiri

Reputation: 3214

You can use the Bind attribute to control how a model binder converts a request into an object. The most common way that you use the Bind attribute is when you exclude an Id property from binding. For example, the Persons database table includes a column named Id that is an Identity column. Because the value of an Identity column is generated by the database automatically, you don’t want to bind a form field to this property.

On the other hand, imagine that a property of a model is especially sensitive, which a malicious user could simply append it in a URL when submitting a form. If this were done, the model binder would happily discover and use the data value in the binding process. By Bind attribute you can protect your application from this kind of attack.

Using the Bind attribute could make problem(s) when you, for example, are going to update an entity and the ID is important for you.

Upvotes: 4

Related Questions