Asp.net mvc 如何支持模型属性的条件验证

Asp.net mvc 如何支持模型属性的条件验证,asp.net-mvc,controller,models,data-annotations,Asp.net Mvc,Controller,Models,Data Annotations,我目前正在构建一个表单,它需要支持两个不同的版本。每个版本可能使用不同的表单字段子集。我必须这样做以支持两个不同的客户端,但我不希望两个客户端的控制器操作完全不同 因此,我试图想出一种方法,使用具有验证属性的强类型模型,但其中一些属性是有条件的 我能想到的一些方法与steve sanderson的方法类似 在这里,我将根据表单的激活版本清除过滤器中的模型错误 我想到的另一种方法是使用类似于 class FormModel { public Form1 Form1Model {get; set;

我目前正在构建一个表单,它需要支持两个不同的版本。每个版本可能使用不同的表单字段子集。我必须这样做以支持两个不同的客户端,但我不希望两个客户端的控制器操作完全不同

因此,我试图想出一种方法,使用具有验证属性的强类型模型,但其中一些属性是有条件的

我能想到的一些方法与steve sanderson的方法类似

在这里,我将根据表单的激活版本清除过滤器中的模型错误

我想到的另一种方法是使用类似于

class FormModel
{

public Form1 Form1Model {get; set;}
public Form2 FormModel {get; set;}
}
然后找到一些方法,根据版本验证适当的属性。模型上也会有适用于两者的通用属性,这些属性将始终得到验证


有人对此有什么好的建议吗?

我在使用ModelBinder删除ModelState中不需要的错误方面取得了相当的成功

下面是一个
地址
模型活页夹的示例。在UI中,我有一个针对美国各州的
,但当国家不是“美国”而支持
文本框时,这一点是隐藏的

modelbinder查看国家并删除不需要的值

至于如何使用验证属性,我认为除非你有非常简单的规则,否则你会很快把自己弄得一团糟

提示:您可以拥有任意数量的ModelBinder,以保留整个模型的各个部分。例如,我的模型中有2个
Address
对象,每个对象都自动应用此行为

注册:

ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
public class AddressModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        base.OnModelUpdated(controllerContext, bindingContext);

        // get the address to validate
        var address = (Address)bindingContext.Model;

        // remove statecd for non-us
        if (address.IsUSA)
        {
            address.StateOrProvince = string.IsNullOrEmpty(address.StateCd) ? null : CountryCache.GetStateName(address.StateCd);
            bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateOrProvince");
        }
        else
        {
            address.StateCd = null;
            bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateCd");
        }


        // validate US zipcode
        if (address.CountryCode == "US")
        {
            if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).Match(address.ZipOrPostal ?? "").Success == false)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".ZipOrPostal", "The value " + address.ZipOrPostal + " is not a valid zipcode");
            }
        }

        // all other modelbinding attributes such as [Required] will be processed as normal
    }
}
ModelBinder:

ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
public class AddressModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        base.OnModelUpdated(controllerContext, bindingContext);

        // get the address to validate
        var address = (Address)bindingContext.Model;

        // remove statecd for non-us
        if (address.IsUSA)
        {
            address.StateOrProvince = string.IsNullOrEmpty(address.StateCd) ? null : CountryCache.GetStateName(address.StateCd);
            bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateOrProvince");
        }
        else
        {
            address.StateCd = null;
            bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateCd");
        }


        // validate US zipcode
        if (address.CountryCode == "US")
        {
            if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).Match(address.ZipOrPostal ?? "").Success == false)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".ZipOrPostal", "The value " + address.ZipOrPostal + " is not a valid zipcode");
            }
        }

        // all other modelbinding attributes such as [Required] will be processed as normal
    }
}

我喜欢这个主意,西蒙。我要试一试。@jeff一开始我不喜欢它,所以我很高兴你已经喜欢了。对于我正在进行的简单任务,工作得相当好