开发者

MVC3 validation attribute breaks model

开发者 https://www.devze.com 2023-04-10 00:48 出处:网络
I\'m working with MVC3.I have a model object that I created with fluidNhibernate.It contains some value types, and some reference types of other objects also created through fluid.Lazy loading is enab

I'm working with MVC3. I have a model object that I created with fluidNhibernate. It contains some value types, and some reference types of other objects also created through fluid. Lazy loading is enabled. In order for the reference types to show up as dropdown boxes on my view I have code like this:

@Html.DropDownListFor(m => m.TheObject.objId, new SelectList(Model.TheObjects, "ObjId", "ItemToDislpay"))

The controller assigns a List<TheObject> to Model.TheObjects before passing the model to the view.

The edit action in my controller:

    public ViewResult Edit(int id)
        {
            myModelType myModel = //get my model object by id here.
            myModel.TheObjects = //assign List<SomeObject> here
            myModel.TheObjects2 = //assign List<SomeObject2> here

            return View(myModel);
        }

        [HttpPost]
        public ActionResult Edit(MyModelType myModel)
        {
            if(ModelState.IsValid)
            {
                ....
            }
            else
            {
                //We end up here even though the validation should have succeeded
                // myModel.TheObjects is null, but I don't know why
                return View(myModel);开发者_StackOverflow
            }
        }

Example of attribute:

[Required(ErrorMessage = "Please enter Username")]
public virtual string UserName { get; set; }

Everything is working fine, until I add validation attributes to model properties. It doesn't matter to which parameter I assign the attribute to. As long as I have at least one validation attribute ModelState.IsValid returns false and all the Lists that I assigned in the non-post action are null in myModel. I tried disabling client side validation but that didn't help. What could be causing this?

I thought that the lists are supposed to be passed back, but I guess not. Still why is the validation failing if the required string exists?

It seems like the FirstName validation is failing on the server side ModelState.IsValid is saying that First Name is missing, while the model object clearly has the First Name field filled in. Here's how my view is processing FirstName:

    <div class="editor-field">
        @Html.EditorFor(model => model.FirstName)
        @Html.ValidationMessageFor(model => model.FirstName)
    </div>

Here's how I submit:

<input type="submit" value="Save" />

client side validation correctly catches the empty FirstName field, and stops the submit, but if I fill in the FirstName then the server side code gives me problems described above.


Your question is still a little vague, but this may help with your problem.

Add this attribute to your model:

[MetadataType(typeof(MyModelTypeMeta))]
public partial class MyModelType
{
    ...
}

and add the MyModelTypeMeta class like shown below, adding a field to match each string property, and telling the model binder to the let the empty string values stay empty instead of changing them to null, which usually causes string properties to fail binding (because you don't have them defined as nullable in your model)

public class MyModelTypeMeta
{
    [DisplayFormat(ConvertEmptyStringToNull=false)]
    public string myProperty;
}


Looking at what you have added, I am betting the problem is with the empty List<someObject> is null when it should at least be an empty list. (and the same goes for the List<someObject2> property)

In your constructor for MyModelType, you should initialize those to empty lists so that the binder does not see them as null. something like:

public MyModelType()
{
    myModel.TheObjects = new List<SomeObject>();
    myModel.TheObjects2 = new List<SomeObject2>();
    ...
}


Ok, I figured out the problem. Thanks to Neil N with helping me along with troubleshooting ideas. First of all, the lists need to be reassigned in the postback action if the validation fails, as they don't get kept from the view and we will need them again when the model is sent back to the view.

Now, the heart of the problem is this. One of the fields in my model is a property that's of the same type as the model. Specifically, each user has a manager property which is also of type user. It is a reference type that's lazy loaded by nhibernate. When I decorated the FirstName property as required for the user, this applies to the user's manager as well. The manager object only has the UserId field set, since that is what we were binding to the dropdownlist in the view. By looking at ModelState.Values I found the error message saying that first name is required in under value index 9. The critical troubleshooting step was to now look at the ModelState.Keys collection and find the item with the same index 9, which had a value of Manager.FirstName. So, it's the manager object that had a null FirstName, not the immediate User object that was being edited.

I guess the question now is how I should resolve this problem. Should I do my bindings differently? Do I do something on the nHibernate side? Should I do custom validation? Should I somehow specify the Manager object only to check if a valid userId is selected for the Manager? I would love to hear some suggestions. Thanks you very much for everyone's help.

0

精彩评论

暂无评论...
验证码 换一张
取 消