21

Is there an alternative for [Bind(Exclude = "Id")] (Related Question) ?

Could I write a model binder?

Community
  • 1
  • 1
Rookian
  • 19,841
  • 28
  • 110
  • 180

5 Answers5

36

Yes there is: it's called view models. View models are classes which are specifically tailored to the specific needs of a given view.

So instead of:

public ActionResult Index([Bind(Exclude = "Id")] SomeDomainModel model)

use:

public ActionResult Index(SomeViewModel viewModel)

where the view model contains only the properties which need to be bound. Then you could map between the view model and the model. This mapping could be simplified with AutoMapper.

As best practice I would recommend you to always use view models to and from a view.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 2
    +1 This is the best description ever that I've seen about ViewModel vs Business model. I've never thought about it from a security point of view. But's is **the** reason to use a view model, at least for http. – jgauffin Jan 08 '11 at 08:14
  • so I need seperate view models for update and create scenarios, do I? – Rookian Jan 08 '11 at 16:28
  • 1
    @Rookian, yes it is a good practice to have separate view models. – Darin Dimitrov Jan 08 '11 at 17:00
  • 9
    @Darin: so when you have a big, complex graph of domain objects with many properties (and relationships, validation rules, etc.) that needs to be presented on a form, do you redefine all of the relevant properties in your view models, manually copy all the properties between them, etc.? It seems like this would result in lots of duplication, hard dependencies and redundant code, so I've been avoiding it like the plague - even though it seems like the "correct" approach, in practice I don't see how you would get around all the awkward duplication and repetition..?? – mindplay.dk Jul 27 '11 at 18:19
  • 1
    @mindplay.dk, I put all that's needed in the view model. If my initial domain model has some complex graph of properties I might flatten it. But once again I include only what I need to show/edit in the view. If it is just for persisting some data into hidden fields (ViewState sorta emulation) then I don't include those properties in the view model. I include only the id that will allow me to fetch this information back from wherever it is stored. And as far as the manual copying is concerned, no, I don't do anything manually, I use AutoMapper which does this for me. – Darin Dimitrov Jul 27 '11 at 18:43
  • 2
    @Darin: but you are duplicating all those properties from your domain-model that are required in the view, correct? What about validation annotations, do you duplicate all of those, or do you only have the validation annotations on the view-models? (thanks for sharing!) – mindplay.dk Jul 28 '11 at 15:37
  • 2
    @mindplay.dk, I duplicate only what I need on my view. As far as validation is concerned, I perform validation on the view models. I use FluentValidation.NET for this. Don't bother with DataAnnotations. – Darin Dimitrov Jul 28 '11 at 15:39
  • In my case, I was "forced" to use ViewModel because my classes were NHibernate classes so when it tries to serialize a lazy property, it fails... – Kat Lim Ruiz Aug 05 '14 at 20:46
  • @DarinDimitrov what is the syntax to use both together on single viewmodel? – Ehsan Sajjad Feb 20 '18 at 09:48
22

You can exclude properties directly with an attribute using;

[BindNever]
PaulB
  • 962
  • 7
  • 15
15

A very simple solution that I figured out.

public ActionResult Edit(Person person)
{
    ModelState.Remove("Id"); // This will remove the key 

    if (ModelState.IsValid)
       {
           //Save Changes;
       }
    }
}
Desmond
  • 1,308
  • 1
  • 19
  • 27
10

As an addition to the existing answers, C# 6 makes it possible to exclude the property in a safer way:

public ActionResult Edit(Person person)
{
    ModelState.Remove(nameof(Person.Id));

    if (ModelState.IsValid)
       {
           //Save Changes;
       }
    }
}

or

public ActionResult Index([Bind(Exclude = nameof(SomeDomainModel.Id))] SomeDomainModel model)
Memet Olsen
  • 4,578
  • 5
  • 40
  • 50
  • I like this answer, but I still believe you should use [ViewModels](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) and [POCO's](http://stackoverflow.com/questions/250001/poco-definition) in regards to the Design Pattern and [SoC](http://stackoverflow.com/questions/98734/what-is-separation-of-concerns). – Chef_Code Jan 09 '17 at 22:21
  • how would you do this if you wanted to exclude two of them? – John Lord Oct 15 '20 at 19:09
3

As Desmond stated, I find remove very easy to use, also I've made a simple extension which can come in handy for multiple props to be ignored...

    /// <summary>
    /// Excludes the list of model properties from model validation.
    /// </summary>
    /// <param name="ModelState">The model state dictionary which holds the state of model data being interpreted.</param>
    /// <param name="modelProperties">A string array of delimited string property names of the model to be excluded from the model state validation.</param>
    public static void Remove(this ModelStateDictionary ModelState, params string[] modelProperties)
    {
        foreach (var prop in modelProperties)
            ModelState.Remove(prop);
    }

You can use it like this in your action method:

    ModelState.Remove(nameof(obj.ID), nameof(obj.Prop2), nameof(obj.Prop3), nameof(obj.Etc));
IOrlandoni
  • 1,790
  • 13
  • 30
Vedran Mandić
  • 1,084
  • 11
  • 21