【问题标题】:how to get ALL errors from viewdata.modelstate如何从 viewdata.modelstate 获取所有错误
【发布时间】:2012-08-19 04:00:42
【问题描述】:

我正在尝试做一些自定义错误处理程序。我们有 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 是它的孩子之一,它又拥有自己的对象,例如地址信息。

谢谢

【问题讨论】:

  • @emragins 我见过这个和其他几个。当我调试它时,modelstate 字典只有两个键。我没有看到验证摘要将返回的其他 8 个以上对象/键
  • 那么不确定。使用 Chris McKenzie 的代码,我能够毫无问题地得到所有错误(来自父母和众多孩子)。也许这是一个 mvc3-mvc4 的东西??

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


【解决方案1】:

我发现了为什么这对我不起作用。像往常一样,是我傻了。因为模型有多个层/级别,即model.someobject.someotherobject.someproperty,当我调用 tryValidateModel 时,它会验证顶层而不是内层。

解决方案是确保它们都被调用:

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

所以我的解决方案是创建一个方法来在每个对象级别调用 try validate 或创建一个反射方法来为我做这件事。

【讨论】:

    【解决方案2】:

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

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

    并且不要忘记将您所需的和/或其他验证添加到您的视图模型访问方法中:

    [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>
    

    【讨论】:

    • 我已经更新了我的问题,以显示我已经对我的模型做了什么。我试图在 GET 而不是 post 上获取这些错误(validationsummary 似乎很乐意这样做,但明确地迭代错误不会返回它们)。由于各种原因,我不想定义每个验证消息属性,一个是冗长的,两个我希望它们在 UL LI 中,所以有效的会导致空 LI
    • @Jon 我不知道 ModelState 在 GET 中有错误?那么对您的问题的更好解释是,“我怎样才能获得我的模型的所有潜在错误消息?”或者,也许您的问题是试图显示它们?我现在很困惑你想要完成什么。
    • @emragins 抱歉,是的。我在 GET 之前验证了我的模型(用户可以保存错误数据以便以后修复它)。我需要能够以编程方式获取该模型的所有错误。谢谢
    【解决方案3】:

    我从这里得到这个: 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-25
      • 2010-11-24
      • 2015-08-09
      • 2016-10-18
      • 2020-11-19
      • 2016-12-07
      • 1970-01-01
      • 2015-12-19
      相关资源
      最近更新 更多