views:

65

answers:

3

I have a farily complex model needing to be validated, the problem is that this model is used on two different places, one where you register your customer and one where you simply add addresses. Some fields on the address are simply not visible on the register customer form. So when i check if ModelState.IsValid i get false of course since eg. the name is not entered on the billing address, but it is on the customer. That is why i want to before validation occurs, copy a couple of fields to the model, and then validate. I am somewhat lost though and i need help.

My action looks something like this:

public ActionResult Register(WebCustomer customer) 
{
     customer.CopyProperties();
     if(TryUpdateModel(customer)) 
     {
       ...
     }
     ...

But it always returns false, and ModelState.IsValid continues to be false.

+2  A: 

I think that the best approach in this situation, is to write CustomModelBinder, and apply it to your action parameter

public ActionResult Register([ModelBinder(typeof(WebCustomerRegisterBinder))]WebCustomer customer)  
{
  if(TryUpdateModel(customer))  
  { 
    ... 
  } 
  ...
}

This CustomModelBinder should take care of copying fields, and because its applied to action parameter it will be used only in this action.

tpeczek
but how would i retrieve all the values posted from the form then?
Mikael
TryUpdateModel() will try to put values from form into your customer object (the only thing that might go wrong here, is TryUpdateModel setting missing fields to null and in result failing model validation), just give it a try.
tpeczek
That is what happened yea, since all that CopyProperties does is use properties like Name and copy it to the addresses property for Name, and if Name is null you can figure out the rest :)
Mikael
Ok, so I'm redifing my answer into something more suitable for this situation.
tpeczek
+1  A: 

Binder is working on form values. So, your ModelState's always throw an error. you have to check your properties in your entity or second option's write your own model binder. eg.

public class Customer
{
    public bool IsValid()
    {
        //TODO: check properties.
    }
}

public ActionResult Register(WebCustomer customer) 
{
    customer.CopyProperties();
    TryUpdateModel(customer);
    if (customer.IsValid())
    {
        ...
    }
    ...
cem
+1  A: 

I solved it a bit diffferently, not sure if it is the best way but:

First i made an extension method for the ModelStateDictionary

public static void ResetErrors(this ModelStateDictionary modelState)
{
     foreach (var error in modelState.Values.Select(m => m.Errors))
 {
    error.Clear();
 }
}

then i did the following in my action:

ModelState.ResetErrors();
customer.CopyProperties();
ValidateModel(customer);
Mikael