如何从viewdata.modelstate获取所有错误

时间:2012-08-23 15:20:26

标签: asp.net-mvc validation asp.net-mvc-4

我正在尝试做一些自定义错误处理程序。我们有4个选项卡(使用JQuery选项卡),它们都是从一个大型模型构建的。简单地说,模型看起来像:

myModel.HomeInfo
myModel.PhoneNumbers
myModel.Addresses
myModel.PersonalDetails

每个部分都是具有各种信息的对象。它们都具有属性并验证消息。

在页面顶部(选项卡上方)我想显示一些顶级错误,我的意思是“myModel”对象上的属性错误。这可以在我执行以下操作时使用:

foreach (ModelState state in viewData.ModelState.Values)

当我这样做时:

@Html.ValidationSummary(false)

在我的观点中,我从四个对象及其所有孩子中获得了所有错误(超过10个)。但是当我经历错误时我自己(上面的代码),我只得到2个错误,(仅“myModel”的错误,而不是它的子属性)。

我尝试使用ILSPY来查看验证摘要正在执行的操作并进行复制。相信我的代码几乎与行相符,但它仍然只有两个错误。

我不知道使用@ Html.ValidationSummary()时会发生什么魔法。

我想知道的是我如何能够获得整个对象的所有错误,以便能够在每个标签上显示一些错误。

澄清这里是我的基本模型:

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;
    }
}

我已经展示了一个验证属性的示例(我们的一些是自定义的,一些是正常的),本例中的顶级MemberProfileModel = myModel,而ContactInformationModel是其子节点之一,而子节点又有自己的对象,如AddressInformation。

由于

3 个答案:

答案 0 :(得分:1)

我发现为什么这不适合我。像往常一样,我是愚蠢的。因为模型有多个图层/级别,即I.e。 model.someobject.someotherobject.someproperty,当我调用tryValidateModel时,它将验证顶层但不验证内层。

解决这个问题的方法是确保他们都被称为:

            TryValidateModel(mp);
            TryValidateModel(mp.ContactInformation.PrimarySiteAddress);
            TryValidateModel(mp.ContactInformation.RegisteredOfficeAddress);

所以我的解决方案是创建一个方法来调用每个对象级别的try validate,或者为我创建一个refelctive方法。

答案 1 :(得分:0)

在页面的发布事件中,在控制器中添加以下内容:

[HttpPost]
public ActionResult Create(TestViewModel testViewModel)
{
// If not Valid
if (!ModelState.IsValid)
{
   return this.View(testViewModel)
}
...
}

不要忘记将您的必需和/或其他验证添加到您的viewmodel访问方法:

[Required(ErrorMessageResourceType = typeof(Resources.MyProject), ErrorMessageResourceName = "validation_Test")]
public virtual string HomeInfo { get; set; }

在你看来:

<div class="editor-row">
        <div class="editor-label">
            @Html.LabelFor(model => model.HomeInfo)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HomeInfo)
            @Html.ValidationMessageFor(model => model.HomeInfo)
        </div>
</div>

答案 2 :(得分:0)

我从这里得到了这个: http://www.unknownerror.org/opensource/aspnet/Mvc/q/stackoverflow/1352948/how-to-get-all-errors-from-asp-net-mvc-modelstate

public static List<string> GetErrorListFromModelState
                                              (ModelStateDictionary modelState)
{
      var query = from state in modelState.Values
                  from error in state.Errors
                  select error.ErrorMessage;

      var errorList = query.ToList();
      return errorList;
}