I am trying to do a bit of a custom error handler. We have 4 tabs (using JQuery tabs), they are all build from one large model. Say for simplicity the model looks like:
myModel.HomeInfo
myModel.PhoneNumbers
myModel.Addresses
myModel.PersonalDetails
Each part is an object that have various bits of information. They all have attributes on them and validate messages.
At the top of the page (above the tabs) I want to display some top level errors, by that I mean the errors for attributes on the "myModel" object. This works when I do the:
foreach (ModelState state in viewData.ModelState.Values)
When I do:
@Html.ValidationSummary(false)
on my view I get all errors from each of the four objects and all their children, (more than 10). But when I go through the errors my self, (code above), I only get 2 errors, (the errors for "myModel" only, not its child properties).
I tried to use ILSPY to see what the validation summary is doing and replicate it. Believe I had the code pretty much line for line, but it still only got the two errors.
I do not know what magic is going on when I use the @Html.ValidationSummary().
What I want to know is how I can get all the errors for the whole object my self to be able to display some of the errors on each tab.
for clarification here is my basic model:
public class MemberProfileModel
{
[CompanyTabValid]
public CompanyInformationModel CompanyInformation { get; set; }
[ContactTabValid]
public ContactInformationModel ContactInformation { get; set; }
[InvoiceTabValid]
public InvoiceInformationModel InvoiceInformation { get; set; }
[TabProductIdentificationMarkValid]
public ProductIdentificationMarkModel ProductIdentificationMark { get; set; }
}
public class CompanyTabValid : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
var model = value as CompanyInformationModel;
if(model == null) throw new ArgumentNullException("value");
var failed = new ValidationResult("Company information incomplete.");
return model.IsValid ? ValidationResult.Success : failed;
}
}
public class ContactInformationModel : BaseModel
{
public ContactInformationModel()
{
PrimarySiteAddress = new AddressInformation();
PrimarySiteContact = new ContactInformation();
RegisteredOfficeAddress = new AddressInformation();
RegisteredOfficeContact = new ContactInformation();
}
public override void Validate()
{
IsValid = PrimarySiteAddress.IsValid &&
PrimarySiteContact.IsValid &&
RegisteredOfficeAddress.IsValid &&
RegisteredOfficeContact.IsValid;
}
public AddressInformation PrimarySiteAddress { get; set; }
public ContactInformation PrimarySiteContact { get; set; }
public AddressInformation RegisteredOfficeAddress { get; set; }
public ContactInformation RegisteredOfficeContact { get; set; }
}
public class AddressInformation : BaseModel
{
public int Id { get; set; }
public Guid MemberId { get; set; }
/// <summary>
/// This property is only here to make EF happy, do not use
/// </summary>
public int LocationTypeValue { get; set; }
public LocationType LocationType { get { return (LocationType) LocationTypeValue; } set { LocationTypeValue = (int) value; } }
[Required(AllowEmptyStrings = false, ErrorMessage = "Address Line 1 required.")]
[Display(Name = "Address Line 1 *")]
public string AddressLine1 { get; set; }
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
[Display(Name = "Address Line 3")]
public string AddressLine3 { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Town required.")]
[Display(Name = "Town *")]
public string Town { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "County required.")]
[Display(Name = "County *")]
public string County { get; set; }
[Display(Name = "Country *")]
public string Country { get; set; }
[RequiredOneOfTwo("InterationalPostCode", ErrorMessage="PostCode or international PostCode are required.")]
[Display(Name = "Post Code *")]
public string PostCode { get; set; }
[RequiredOneOfTwo("PostCode", ErrorMessage = "International PostCode or PostCode are required.")]
[Display(Name = "International Post Code *")]
public string InterationalPostCode { get; set; }
public override void Validate()
{
if (string.IsNullOrEmpty(AddressLine1))
{
this.IsValid = false;
return;
}
else if (string.IsNullOrEmpty(Town))
{
this.IsValid = false;
return;
}
else if (string.IsNullOrEmpty(County))
{
this.IsValid = false;
return;
}
else if (string.IsNullOrEmpty(Country))
{
this.IsValid = false;
return;
}
else if (string.IsNullOrEmpty(PostCode) && string.IsNullOrEmpty(InterationalPostCode))
{
this.IsValid = false;
return;
}
this.IsValid = true;
return;
}
}
I have shown an example of a validation attribute (some of ours are custom, some are normal), the top level MemberProfileModel = myModel in this example, and ContactInformationModel is one of its children which in turn has its own objects such as AddressInformation.
Thanks