6

I follow this tutorial: http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-6

When talking about form validation author says that Bind anntoations is used to:

 Lists fields to exclude or include when binding parameter or form values to model properties

It is little bit gibberish to me - I don't get it. What does it actually mean? Maybe the problem is the word scaffold which has to meanings in dictionary that don't have any connection to IT.

What is the result of: [Bind(Exclude = "AlbumId")] and what is the sense of typing: [ScaffoldColumn(false)] - the column is not hidden by default, why to say it again.


namespace MvcMusicStore.Models
{
    [Bind(Exclude = "AlbumId")]
    public class Album
    {
        [ScaffoldColumn(false)]
        public int      AlbumId    { get; set; }
        [DisplayName("Genre")]
        public int      GenreId    { get; set; }
        [DisplayName("Artist")]
        public int      ArtistId   { get; set; }
        [Required(ErrorMessage = "An Album Title is required")]
        [StringLength(160)]
        public string   Title      { get; set; }
        [Required(ErrorMessage = "Price is required")]
        [Range(0.01, 100.00,
            ErrorMessage = "Price must be between 0.01 and 100.00")]
        public decimal Price       { get; set; }
        [DisplayName("Album Art URL")]
        [StringLength(1024)]
        public string AlbumArtUrl { get; set; }
        public virtual Genre  Genre    { get; set; }
        public virtual Artist Artist   { get; set; }
    }
}
Yoda
  • 17,363
  • 67
  • 204
  • 344

1 Answers1

19

Scaffold

For what it's worth I've been building apps on top of ASP.NET MVC for over two years now and not once have I ever used the ScaffoldColumn attribute. However, to actually answer your question the attribute is used to tell the framework if the field should be visible.

As an example, if you used @Html.EditorForModel() (this method does some magic under the hood and builds out form inputs for your model properties) then your view will not contain inputs for the columns marked false in the ScaffoldColumn attribute. It's essentially a shortcut to tell the framework not to allow the field to be edited when it builds out the view. Again, I never use EditorForModel because I build out my forms by hand for each input because I want more granular control.

Bind

The Bind attribute is used to tell the framework if you want to allow the property to be bound to when sending data to the server (this is more of a security feature).

Consider this action:

[HttpPost]
public ActionResult DontSendMeTooMuchData(Employee employee) {
    db.Employees.Update(employee);
}

Suppose the Employee object looks like this:

public class Employee {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string SocialSecurityNumber { get; set; }
}

Now suppose I send an HTTP POST request that sends up data:

FirstName=Justin
&LastName=Helgerson
&SocialSecurityNumber=YouShouldntLetMeUpdateThis

You've just updated my social security number! Bad news bears. How do you stop it?

[Bind(Exclude = "SocialSecurityNumber")]
public class Employee {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string SocialSecurityNumber { get; set; }
}

Now when the DontSendMeTooMuchData method is executed and ASP.NET MVC does the model binding to give you an Employee object from the HTTP request, the SocialSecurityNumber property will never be populated from the request data.

Again, this is an attribute that I never use in my applications. There is another way to solve this problem that has other benefits. For fear of this answer becoming too long, the way to solve the problem is to use different models for your view and your database. I never let my database objects hit my view. Instead I build a class specifically for use in the view which only contains the properties I want the user to provide.

Justin Helgerson
  • 24,900
  • 17
  • 97
  • 124
  • so what if your view model includes an IEnumerable of a class that you want to exclude certain fields? Do you define a new model for each regular model, with those classes excluded, and do an `IEnumerable`? – Allen Wang Jan 17 '18 at 15:13
  • Also, could you explain some of the other benefits you allude to? – Allen Wang Jan 17 '18 at 15:20
  • 1
    @AllenWang If I understand you correctly, that's how I would do it. My simple rule is: if my data model (i.e. an object from a database or some API) is read-only then I'm okay with that same object hitting my view. If you ever want to allow the user to provide data then I always create a separate model class specifically for that scenario. Using the `Bind` attribute doesn't give you compile time safety. What if you forget to add the attribute for a certain property that should be read-only? Then you have that exposure. By using a separate model you get the compile time safety. – Justin Helgerson Jan 17 '18 at 16:41
  • @AllenWang Regarding the other benefits... I think it boils down to separation of concerns. Here's a simple example that I had today. I have a `Description` property in my database. In the view for the customer I only want to display the first 128 characters to prevent the page from becoming too long. By having a separate view model I can create a read-only `DescriptionDisplay` property that handles this. There's no need for that property to exist at the data layer since it only serves a purpose in my view. Hopefully that example helps. – Justin Helgerson Jan 17 '18 at 16:47
  • That example helps, but then it seems that you end up having to write a lot of extra classes and conversion code between the classes. Do you recommend using Automapper? – Allen Wang Jan 17 '18 at 21:15
  • I used to use AutoMapper, but I found it easier to just do the mapping on my own (e.g. in a constructor or load method). This pattern has worked well for me, but maybe you need to tweak it a little to best meet your needs. – Justin Helgerson Jan 18 '18 at 15:20
  • It is worth noting that excluding properties is called blacklisting. It is usually better to include properties instead (whitelisting) because it makes it easier to explicitly allow the required properties. However, using view models is of course the best way to solve this, like Justin mentions. – Slippers Mar 18 '20 at 06:51