如何使 ModelState 键/模型属性名称匹配?

发布于 2024-11-08 02:29:26 字数 4349 浏览 0 评论 0原文

我有一个 MVC3 应用程序,我正在使用 EF4.1 Code First 和 POCO 类。

我的问题涉及摆脱 POCO 类中的硬编码“PropertyNames”,并使用 ModelState 中的正确值对其进行预先修复,以便验证消息正确显示。

我的 POCO 类中有一个如下所示的方法。 您会注意到,我还使用“DataAnnotations.Validator”代码来重新使用数据注释验证。

public class TaxCode : ModelBusinessObjectBase
{
    //...

    [Required]
    [DataType(DataType.Date)]
    [DisplayName("Effective Date")]        
    public DateTime EffectiveDate
    {
        get { return _effectiveDate; }
        set { _effectiveDate = value; }
    }    

    [Required]
    [DataType(DataType.Date)]
    [DisplayName("Expiry Date")]        
    public DateTime ExpiryDate
    {
        get { return _expiryDate; }
        set { _expiryDate = value; }
    }    

    //...

    public override IEnumerable<ValidationResult> GetValidationResults()
    {
        //---- data annotation validation ----
        ValidationContext validationContext = new ValidationContext(this, null, null);
        IList<ValidationResult> dataAnnotationValidationResults = new List<ValidationResult>();
        bool isValid = Validator.TryValidateObject(this, validationContext, dataAnnotationValidationResults, true);


        foreach (ValidationResult dataAnnotationValidationResult in dataAnnotationValidationResults)
            yield return new ValidationResult(dataAnnotationValidationResult.ErrorMessage, dataAnnotationValidationResult.MemberNames);

        //---- custom business rule validation ----
        // expiry date must be greater than effective date
        if (ExpiryDate <= EffectiveDate)
        {   
            yield return new ValidationResult("Expiry Date must be after Effective Date", new [] {"EffectiveDate", "ExpiryDate"});
        }

        yield break;
    }

在我的服务层中,我最终将调用这样的内容:

    public bool TryValidate(TaxCode domainObject)
    {
        if (!domainObject.IsValid) 
        {   
            _validationDictionary.AddValidationResults(domainObject.GetValidationResults());
            isValid = false;
        }
        return isValid;
    }

使用“ModelStateWrapper”,代码执行以下操作:

    public virtual void AddValidationResults(IEnumerable<ValidationResult> validationResults)
    {

        foreach (ValidationResult validationResult in validationResults)
        {
            _modelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
        }
    }

我的视图模型是这样的:

public class TaxCodeViewModel : IPersistantBusinessObjectViewModel<TaxCode>
{
    public TaxCodeViewModel()
    {
    }

    public TaxCodeViewModel(TaxCode domainObj)
    {
        this.BusinessObject = domainObj;
    }
}

我的视图看起来有点像这样:

   <%@ Control Language="C#" AutoEventWireup="true"               Inherits="System.Web.Mvc.ViewUserControl<TaxCodeViewModel>" %>

   //...

    <% using (Html.BeginForm()) {%>

        <%:Html.ValidationSummary(false, "Unable to save. Please correct the errors and try again.")%>


        //...

        <div class="editor-label">
            <%:Html.LabelFor(model => model.BusinessObject.EffectiveDate)%>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(model => model.BusinessObject.EffectiveDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.EffectiveDate)%>
        </div>
        <br />  
        <div class="editor-label">
            <%: Html.LabelFor(model => model.BusinessObject.ExpiryDate)%>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(model => model.BusinessObject.ExpiryDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.ExpiryDate)%>
        </div>
        <br />  
        //...

我的问题是:

  1. 我该如何做避免硬编码的属性名称字符串“到期日期”?

  2. 由于 ViewModel,预计 ModelState 键为“BusinessObject.ExpiryDate”。我如何使我的属性匹配?如何添加前缀或删除自动添加的前缀?

  3. 请注意,我当前使用validationResult.MemberNames.First())。 就我而言,我只希望验证摘要中包含一条消息,但我希望突出显示两个属性。即只有一条关于“.validation-summary-errors”的消息,但两个字段都针对 DOM 中的“.input-validation-error”和“.field-validation-error”元素突出显示。

谢谢你,

I have an MVC3 application, I'm using EF4.1 Code First and POCO Classes.

My question involves getting rid of hard-coded "PropertyNames" in my POCO Class and also pre-fixing it with the proper values in ModelState so that the validation message appear properly.

I have in my POCO class a method that looks like this.
You will notice that I am also using the "DataAnnotations.Validator" code to re-use the Data Annotations validation.

public class TaxCode : ModelBusinessObjectBase
{
    //...

    [Required]
    [DataType(DataType.Date)]
    [DisplayName("Effective Date")]        
    public DateTime EffectiveDate
    {
        get { return _effectiveDate; }
        set { _effectiveDate = value; }
    }    

    [Required]
    [DataType(DataType.Date)]
    [DisplayName("Expiry Date")]        
    public DateTime ExpiryDate
    {
        get { return _expiryDate; }
        set { _expiryDate = value; }
    }    

    //...

    public override IEnumerable<ValidationResult> GetValidationResults()
    {
        //---- data annotation validation ----
        ValidationContext validationContext = new ValidationContext(this, null, null);
        IList<ValidationResult> dataAnnotationValidationResults = new List<ValidationResult>();
        bool isValid = Validator.TryValidateObject(this, validationContext, dataAnnotationValidationResults, true);


        foreach (ValidationResult dataAnnotationValidationResult in dataAnnotationValidationResults)
            yield return new ValidationResult(dataAnnotationValidationResult.ErrorMessage, dataAnnotationValidationResult.MemberNames);

        //---- custom business rule validation ----
        // expiry date must be greater than effective date
        if (ExpiryDate <= EffectiveDate)
        {   
            yield return new ValidationResult("Expiry Date must be after Effective Date", new [] {"EffectiveDate", "ExpiryDate"});
        }

        yield break;
    }

In my service layer, I will eventually call something like this:

    public bool TryValidate(TaxCode domainObject)
    {
        if (!domainObject.IsValid) 
        {   
            _validationDictionary.AddValidationResults(domainObject.GetValidationResults());
            isValid = false;
        }
        return isValid;
    }

And using a "ModelStateWrapper", the code does this:

    public virtual void AddValidationResults(IEnumerable<ValidationResult> validationResults)
    {

        foreach (ValidationResult validationResult in validationResults)
        {
            _modelState.AddModelError(validationResult.MemberNames.First(), validationResult.ErrorMessage);
        }
    }

My view model is this:

public class TaxCodeViewModel : IPersistantBusinessObjectViewModel<TaxCode>
{
    public TaxCodeViewModel()
    {
    }

    public TaxCodeViewModel(TaxCode domainObj)
    {
        this.BusinessObject = domainObj;
    }
}

And my View looks a bit like this:

   <%@ Control Language="C#" AutoEventWireup="true"               Inherits="System.Web.Mvc.ViewUserControl<TaxCodeViewModel>" %>

   //...

    <% using (Html.BeginForm()) {%>

        <%:Html.ValidationSummary(false, "Unable to save. Please correct the errors and try again.")%>


        //...

        <div class="editor-label">
            <%:Html.LabelFor(model => model.BusinessObject.EffectiveDate)%>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(model => model.BusinessObject.EffectiveDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.EffectiveDate)%>
        </div>
        <br />  
        <div class="editor-label">
            <%: Html.LabelFor(model => model.BusinessObject.ExpiryDate)%>
        </div>
        <div class="editor-field">
            <%: Html.EditorFor(model => model.BusinessObject.ExpiryDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.ExpiryDate)%>
        </div>
        <br />  
        //...

My Question are:

  1. How do I avoid the hardcoded property name strings "Expiry Date"?

  2. Because of the ViewModel, expects the ModelState key to be "BusinessObject.ExpiryDate". How do I, get my properties to match? How do I add a prefix or remove the automatically added prefix?

  3. Notice I currently use validationResult.MemberNames.First()).
    In my case, I only want one message in the validation summary, but I would like to have BOTH properties highlighted. i.e. only one message for ".validation-summary-errors" but both fields highlighted for ".input-validation-error" and ".field-validation-error" elements in the DOM.

Thank you,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风流物 2024-11-15 02:29:27

属性中的硬编码属性名称不错,除了函数等。我建议您实现从 CompareAttribute ,这样上面的大部分代码都会消失,你的硬编码依赖问题将得到解决。

为了突出显示问题,您可以使用 java 脚本,或实现一些实用函数来检查模型在某些字段上是否有错误并返回一些 css 类名。类似休耕的东西。

 <div class="editor-field <%: Html.HasValidationMessage(model => model.BusinessObject.ExpiryDate)%>">
            <%: Html.EditorFor(model => model.BusinessObject.ExpiryDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.ExpiryDate)%>
 </div>

Hard coding property name in attributes is not bad, except functions,etc.I suggest you to implement new class inherited from CompareAttribute , so most of above code will gone and your hard coding depency problem will be solved.

For highlighting problem you can use java script, or implement some utily function to check if model has error on some field and returning some css class name. Something like fallowing.

 <div class="editor-field <%: Html.HasValidationMessage(model => model.BusinessObject.ExpiryDate)%>">
            <%: Html.EditorFor(model => model.BusinessObject.ExpiryDate)%>
            <%: Html.ValidationMessageFor(model => model.BusinessObject.ExpiryDate)%>
 </div>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文