简体   繁体   English

ASP.NET MVC 3-调用UpdateModel或TryUpdateModel时如何有条件地验证(IValidatableObject)?

[英]ASP.NET MVC 3 - How can I conditionally validate (IValidatableObject) when calling UpdateModel or TryUpdateModel?

I am using EFCodeFirst CTP5 (although this shouldn't make a difference) and ASP.NET MVC 3. I have created the following entities: 我正在使用EFCodeFirst CTP5(尽管这不会有所作为)和ASP.NET MVC3。我创建了以下实体:

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

Notice that a Company has a Subdomain and a Subdomain has an ICollection<SubdomainActivity> . 请注意, Company有一个SubdomainSubdomainICollection<SubdomainActivity>

I have controllers for Company and Subdomain . 我有CompanySubdomain控制器。 In the SubdomainController when I call UpdateModel() (or TryUpdateModel() ) on an instance of a Subdomain I get the result I want. SubdomainController当我打电话UpdateModel()TryUpdateModel()上的一个实例) Subdomain我得到我想要的结果。 The Subdomain activities are validated that the values sum up to 100. 验证Subdomain活动的值总计为100。

In the CompanyController when I call UpdateModel() on an instance of a Company it validates that the Subdomain.Activities add up to 100 as well, which I don't want. CompanyController当我在Company的实例上调用UpdateModel() ,它会验证Subdomain.Activities加起来为100,这是我不希望的。 The user can't even edit Subdomain.Activites from the Company edit view anyway, so it makes no sense to tell them that there was an error with Subdomain.Activities . 无论如何,用户甚至都无法从Company编辑视图编辑Subdomain.Activites ,因此,告诉他们Subdomain.Activities存在错误是没有意义的。

I would like to be able to add an item to the validationContext.Items IDictionary so that I can conditionally validate based on context or something like that, but I haven't been able to figure out how to do that without writing my own IModelBinder (which I could do I suppose, but seems like overkill). 我希望能够将一个项目添加到validationContext.Items IDictionary中,以便我可以根据上下文或类似条件进行条件验证,但是如果没有编写自己的IModelBinder(我想我可以做到,但似乎有点过分了。 Ultimately I have come up with this workaround in the CompanyController , but I am sure there is a correct way to handle this (this is wrapped in a try catch ) 最终,我在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();

As an interesting side note, if I don't check if the model is valid and throw an error then the companyRepository.Save() works fine. 有趣的是,如果我不检查模型是否有效并抛出错误,则companyRepository.Save()可以正常工作。 In other words EFCodeFirst doesn't seem to call Validate on the Subdomain, but MVC UpdateModel does. 换句话说,EFCodeFirst似乎没有在子域上调用Validate,但是MVC UpdateModel却如此。

Can anyone help me out with a better/correct/recommended way to handle this? 谁能以更好/正确/推荐的方式帮助我解决这个问题?

I found a way to handle this a bit more gracefully. 我找到了一种更优雅地处理此问题的方法。 Instead of implementing IValidatableObject on the Subdomain I just use a [CustomValidation] attribute on the Activities property of the Subdomain. IValidatableObjectSubdomain上实现IValidatableObject ,而是在Subdomain的Activities属性上使用了[CustomValidation]属性。 This is NOT called when validating the Company instance in my question and I still get my specialized validation on the activities. 验证问题中的Company实例时不会调用此方法,但我仍获得有关活动的专门验证。 Hopefully this helps someone somewhere someday. 希望这有一天能对某人有所帮助。

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

what about modifying your Validate() method as below? 如下修改您的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" });
    }
}  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM