views:

1139

answers:

6

This is happening when I try to create the entity using a Create style action in Asp.Net MVC 2.

The POCO has the following properties:

public int Id {get;set;}

[Required]
public string Message {get; set}

On the creation of the entity, the Id is set automatically, so there is no need for it on the Create action.

The ModelState says that "The Id field is required", but I haven't set that to be so. Is there something automatic going on here?

EDIT - Reason Revealed

The reason for the issue is answered by Brad Wilson via Paul Speranza in one of the comments below where he says (cheers Paul):

You're providing a value for ID, you just didn't know you were. It's in the route data of the default route ("{controller}/{action}/{id}"), and its default value is the empty string, which isn't valid for an int. Use the [Bind] attribute on your action parameter to exclude ID. My default route was: new { controller = "Customer", action = "Edit", id = " " } // Parameter defaults

EDIT - Update Model technique

I actually changed the way I did this again by using TryUpdateModel and the exclude parameter array asscoiated with that.

    [HttpPost]
    public ActionResult Add(Venue collection)
    {
        Venue venue = new Venue();
        if (TryUpdateModel(venue, null, null, new[] { "Id" }))
        {
            _service.Add(venue);
            return RedirectToAction("Index", "Manage");
        }
        return View(collection);
    }
A: 
[Bind(Exclude = "Id")]
public class Hebe
{
      public int Id {get;set;}

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

By the way above it doesnt bind the Id Property for your model on create

Barbaros Alp
What about on Updates?
burnt_hand
on updates, you need to take the record and use the UpdateModel to update the record. So you have the id from the db record
Barbaros Alp
Have a look at RM's answer to show what I mean
burnt_hand
+8  A: 

You can add the attribute:

 [Bind(Exclude = "Id")] 

on the parameter in method rather than the class, that way on create you can exclude it and on edit it will still be mandatory:

public ActionResult Create([Bind(Exclude = "Id")] User u)
{
    // will exclude for create
}

public ActionResult Edit(User u)
{
    // will require for edit
}
RM
Nice. I think this will do the trick. I had seen it somewhere but couldn't find it again. Where did you find it?
burnt_hand
@burnt_hand - Its in a book I have (Professional MVC 1.0 off the top of my head). But also you can google "asp.net mvc bind exclude" and there are some example usages.
RM
A: 

I just created a new MVC2 project, and added a simple POCO as well as a Controller and a View. From what I understand, you're using model binding to create the object, that is

using System.ComponentModel.DataAnnotations;
public class SimpleObject
{
    public int Id {get;set;}
    [Required]
    public string Message { get; set; }
}

in the Controller we have

[HttpPost]
public ActionResult Create(SimpleObject created)
{
    /// do something
}

and in the View, there is no editor for the ID field?

This should not end up in any error messages. Instead, the Id is supposed to be set to default(int) which is 0. This works for me. What version of MVC2 are you using (the RC I assume)?

Don't get me wrong: It is important to prevent the Id from being bound by the model binders since that would allow an attacker to tamper with the Id of the object. Nonetheless, the default model binder should not show the behaviour you describe.

mnemosyn
+1  A: 

I have the same problem, using RC2 with a POCO. If you name a property Id but do not put an validation attributes on it but IsValid says it is required. If I name a property anything but Id this does not happen. Why should I have to Exclude Id?

Thanks

Paul Speranza
And I just got this anser from Brad Wilson : You're providing a value for ID, you just didn't know you were. It's in the route data of the default route ("{controller}/{action}/{id}"), and its default value is the empty string, which isn't valid for an int. Use the [Bind] attribute on your action parameter to exclude ID. My default route was: new { controller = "Customer", action = "Edit", id = " " } // Parameter defaults
Paul Speranza
Argh! Kidding me... Makes sense, but I would have never of found that
burnt_hand
A: 

I had the same issue, except i had three integer fields on my model. I managed to get around it by setting all my integer properties that were erroneously required to nullable ints.

kmehta
+1  A: 

Great question and answers, saved my ... behind. I need to add something, though:

Instead of

[Bind(Exclude = "Id")]

I think it's better to use

[Bind(Include = "Prop1, Prop2, Prop3, etc")]

.. where Prop1, Prop2 and Prop3 are THE ONLY properties that you want to be bound at the action level.

Since this is white-listing as opposed to black-listing. White-listing is better, safer. This way you also solve the risk of over posting and under posting too. See Brad Wilson's post.

Andrei Rinea
Agreed. You can easily get haX0rd if you aren't using View Models.
burnt_hand
Yep. For example I have a CreateUser action on my Account controller. One of the properties of the User model is UserType which is an enum containing User, ..., Admin. If he'd be posting a hidden field called UserType and it's value "Admin" and I **wouldn't** use this form of Bind attribute I'd have WAY TOO MANY Admins on my site =))
Andrei Rinea