[英]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
有一个Subdomain
而Subdomain
有ICollection<SubdomainActivity>
。
I have controllers for Company
and Subdomain
. 我有
Company
和Subdomain
控制器。 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. 我
IValidatableObject
在Subdomain
上实现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.