【问题标题】:ASP.NET MVC 3 - How can I conditionally validate (IValidatableObject) when calling UpdateModel or TryUpdateModel?ASP.NET MVC 3 - 如何在调用 UpdateModel 或 TryUpdateModel 时有条件地验证 (IValidatableObject)?
【发布时间】:2011-01-28 22:07:19
【问题描述】:

我正在使用 EFCodeFirst CTP5(尽管这应该没什么区别)和 ASP.NET MVC 3。我创建了以下实体:

public class Company
{
    public int CompanyID { get; set; }    
    public int SubdomainID { get; set; }
    public virtual Subdomain Subdomain { get; set; }    
}

public class Subdomain : IValidatableObject
{
    public int SubdomainID { get; set; }    
    public virtual ICollection<SubdomainActivity> Activities { get; set; }    
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        int activitySum = Activities.Sum(x => x.Value);
        if (activitySum != 100)
        {
            yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
        }
    }    
}
public class SubdomainActivity
{        
    public int ActivityID { get; set; }    
    public int Value { get; set; }
}

请注意,Company 具有 SubdomainSubdomain 具有 ICollection&lt;SubdomainActivity&gt;

我有 CompanySubdomain 的控制器。在SubdomainController 中,当我在Subdomain 的实例上调用UpdateModel()(或TryUpdateModel())时,我得到了我想要的结果。验证 Subdomain 活动的值总和为 100。

CompanyController 中,当我在Company 的实例上调用UpdateModel() 时,它验证Subdomain.Activities 加起来也为100,这是我不想要的。无论如何,用户甚至不能从Company 编辑视图编辑Subdomain.Activites,因此告诉他们Subdomain.Activities 有错误是没有意义的。

我希望能够将一个项目添加到 validationContext.Items IDictionary 以便我可以根据上下文或类似的东西有条件地验证,但我无法弄清楚如何在不写我的情况下做到这一点自己的 IModelBinder (我想我可以这样做,但似乎有点矫枉过正)。最终我在CompanyController 中提出了这个解决方法,但我确信有一个正确的方法来处理这个问题(这包含在try catch 中)

var d = this.companyRepository.GetById(id);
bool good = TryUpdateModel(d);
if (!good)
{
    if (ModelState.ContainsKey("Subdomain.Activities"))       
        ModelState.Remove("Subdomain.Activities");        
    if (!ModelState.IsValid)
        throw new InvalidOperationException(string.Format("The model of type '{0}' could not be updated.", typeof(Company).FullName));
}
this.companyRepository.Save();

作为一个有趣的附注,如果我不检查模型是否有效并抛出错误,那么 companyRepository.Save() 工作正常。换句话说,EFCodeFirst 似乎没有在子域上调用 Validate,但 MVC UpdateModel 会。

谁能帮助我以更好/正确/推荐的方式来处理这个问题?

【问题讨论】:

  • 如果我可以跳过对公司子域属性的验证,我认为这也可以。不过不知道该怎么做。
  • 没有dontvalidateattribute什么的吗?查看 system.componentobject.dataannotations 或命名空间的名称(抱歉,我没有更多帮助,在移动设备上)。
  • 我认为从 ModelState 错误中删除它很好。关于您关于 EF CTP5 未验证的问题 - 这可能是此 CTP 中的错误。它应该使用 IValidatableObject 并对其进行验证。也许这个问题可以帮助stackoverflow.com/questions/4233920/…
  • @Alxandr - 是的,我已经搜索了那个命名空间但没有成功。我尝试添加一个 CustomValidationAttribute 希望它会覆盖另一个,但它没有帮助。仍然运行子域验证。您还可以将 [ValidateInput(false)] 添加到模型中,但不能添加属性。
  • @mare - 可以期望对象图验证多远?在这种情况下,它在技术上验证子域的活动。甚至与公司无关。我更喜欢我所看到的 EFCodeFirst,而不是 TryUpdateModel 和 UpdateModel。如果我有办法在 validationContext 中设置标志,我会很高兴。必须删除模型错误是一件痛苦的事情。另外,不确定其他问题与我的关系如何。

标签: c# asp.net-mvc asp.net-mvc-3 entity-framework


【解决方案1】:

我找到了一种更优雅地处理这个问题的方法。我没有在Subdomain 上实现IValidatableObject,而是在子域的Activities 属性上使用[CustomValidation] 属性。在我的问题中验证 Company 实例时不会调用此方法,并且我仍然会获得对活动的专门验证。希望有一天这对某个地方的人有所帮助。

public class Subdomain
{
    public int SubdomainID { get; set; }

    [CustomValidation(typeof(Subdomain), "ValidateActivities")]
    public virtual ICollection<SubdomainActivity> Activities { get; set; }
    public static ValidationResult ValidateActivities(ICollection<SubdomainActivity> activities)
    {
        if (activities.Count > 0)
        {
            int activitySum = activities.Sum(x => x.Value);
            if (activitySum != 100)
            {
                return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
            }
        }
        return ValidationResult.Success;
    }
}

【讨论】:

    【解决方案2】:
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        int activitySum = Activities.Sum(x => x.Value);
        if (activitySum != 100)
        {
            yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
        }
    }  
    

    如下修改你的 Validate() 方法怎么样?

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        int activitySum = Activities.Sum(x => x.Value);
        if (Activities.Count != 0 && activitySum != 100)
        {
            yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
        }
    }  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      相关资源
      最近更新 更多