Pergunta

I have an issue that is probably just due to my lack of experience with ASP.NET MVC, but it's one I have been trying to resolve for a bit now.

I have a Code First database set up that doesn't differ very much from the first tutorial on asp.net (http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4). Basically the problem that I'm having is upon trying to create a new record in the database via the "Create" page, the ID is set to 0, which makes the ModelState invalid.

Relevant code: Model:

public class Evt
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string GeoDescription { get; set; }
    public decimal Longitude { get; set; }
    public decimal Latitude { get; set; }
    public DateTime Date { get; set; }
}

Controller:

[HttpPost]
public ActionResult Create(Evt evt)
{
    if (ModelState.IsValid) // This is returning false because ID is 0
    {
        db.Evts.Add(evt);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(evt);
}

I can add the View code as well upon request, but it's basically just the auto-generated code from the Model.

If anyone has any ideas, I'd greatly appreciate it!

Thanks,

Jeff

Edit: I do not reference the ID in my "Create" view at all, and adding it as a hidden form value did not solve my problem either.

Update: I have been able to circumvent the error by adding

if (!ModelState.IsValid && evt.ID == 0) ModelState.Clear();

above the if statement in Create, but this removes all client-side validation and is obviously not ideal. It does show that the record is properly inserted with an incremented ID once it hits the server though.

Foi útil?

Solução 3

If anyone comes across this in the future, this may not be the answer you'd like to hear, but it's what I ended up doing.

I switched to using an explicit Entity Framework (Database First) instead of using Code First. This re-generated my model and subsequently fixed my problem. I'm not exactly sure why it fixed it, but as I said in the problem description, I think it may have been a minor setting or line of code that I accidentally changed originally.

My suggestion to those who have this issue and don't want to abandon Code First: try refactoring your Model or deleting it altogether and creating a new one with the same properties.

Sorry I couldn't be more help.

Outras dicas

It looks like you're using your EF Entity classes as ViewModels. This is not recommended because there is not a 1:1 mapping between ViewModels (that encapsulate the data content of a humand-readable input form) and entities (which represent normalized business objects), it's just coincidental that you can get away with using simple EF classes as ViewModels, but if you do, eventually you'll run into problems like these.

There are a few possible solutions, the best is to use a dedicated ViewModel for your page. The second is to modify your entity class to change int ID to int? ID, so the Model-binder will not require that the item be specified, the third option is to clear the Model-state dicitonary of any errors relating to the ID member prior to calling ModelState.IsValid.

Note that if you do continue to use your entity classes as viewmodels you will be suspectible to Mass Assignment attacks (as your code currently is). This is why dedicated per-view ViewModels are the best.

As Dai says, the recommended approach is to not use your entities directly in your view. There are a lot of reasons for this, but you're getting a taste of them right now.

However, if you aren't going to do that, you have several options. You can clear the model state, as Dai says, but I do not like this approach. It's hacky and ugly and really is just poor practice.

You can also add a [Bind(Exclude="ID")] to your parameter. In this case:

public ActionResult Create([Bind(Exclude="ID")] Evt evt)

I'm not real fond of that either, but at least it's not as ugly as removing the item from the ModelState in your controller.

You could also add a hidden field. You say you did this and it didn't solve the problem, but it should have worked. So perhaps you were doing something wrong, such as using the wrong naming convention. I suggest using HiddenFor and make sure it's within the braces of your BeginForm(){}

@Html.HiddenFor(x => x.ID)

I just come across this problem, not sure is same to you

I am using same page for New and Edit, so I have something like:

@Html.HiddenFor(model => model.Code_Id)

but this is useful for edit only, so I add something like:

if (ViewBag.Action != "New")
{
    @Html.HiddenFor(model => model.Code_Id)
}

and ModelState.IsValid is now true

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top