ASP.NET MVC - Alternative for [Bind(Exclude = "Id")]
Asked Answered
S

5

21

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

Could I write a model binder?

Secularism answered 7/1, 2011 at 22:50 Comment(0)
I
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.

Inimitable answered 8/1, 2011 at 8:4 Comment(9)
+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.Turncoat
so I need seperate view models for update and create scenarios, do I?Secularism
@Rookian, yes it is a good practice to have separate view models.Inimitable
@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..??Tredecillion
@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.Inimitable
@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!)Tredecillion
@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.Inimitable
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...Descendible
@DarinDimitrov what is the syntax to use both together on single viewmodel?Secluded
I
22

You can exclude properties directly with an attribute using;

[BindNever]
Interpret answered 24/1, 2018 at 10:53 Comment(0)
K
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;
       }
    }
}
Keilakeily answered 1/11, 2012 at 1:48 Comment(0)
C
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)
Coprolite answered 10/2, 2016 at 14:22 Comment(2)
I like this answer, but I still believe you should use ViewModels and POCO's in regards to the Design Pattern and SoC.Leverage
how would you do this if you wanted to exclude two of them?Praise
B
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));
Bogard answered 12/6, 2014 at 0:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.