带有验证的自包含组件

时间:2012-08-09 18:04:24

标签: asp.net-mvc-3 validation model-binding

我有一个名为 Foo 的模型,它有一个名为 MyProp 的属性 Bar 。 当我将此模型发布到控制器时,我希望模型绑定器验证 MyProp ,因为它具有Required属性,就像对字符串一样。我需要它在Bar类中自包含或作为单独的类。我曾尝试在 Bar 类上使用IValidatableObject,但似乎无法检查 Foo 类是否具有必需属性 MyProp ?所以现在我没有选择,需要一些帮助。以下是我的问题的一些示例代码。

public class Foo {
    [Required]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }
    public string Name { get; set; }
}

3 个答案:

答案 0 :(得分:2)

这是我的问题的一个解决方案,我可以使用内置的必需属性,仍然可以获得自定义行为。这只是概念代码的一些证据。

模特:

public class Page : IPageModel {
    [Display(Name = "Page", Prompt = "Specify page name...")]
    [Required(ErrorMessage = "You must specify a page name")]
    public PageReference PageReference { get; set; }
}

模型活页夹:

public class PageModelBinder : DefaultModelBinder {
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) {
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(bindingContext.ModelType)) {
            var attributes = property.Attributes;
            if (attributes.Count == 0) continue;
            foreach (var attribute in attributes) {
                if (attribute.GetType().BaseType == typeof(ValidationAttribute) && property.PropertyType == typeof(PageReference)) {
                    var pageReference = bindingContext.ModelType.GetProperty(property.Name).GetValue(bindingContext.Model, null) as PageReference;
                    Type attrType = attribute.GetType();
                    if (attrType == typeof (RequiredAttribute) && string.IsNullOrEmpty(pageReference.Name)) {
                        bindingContext.ModelState.AddModelError(property.Name,
                            ((RequiredAttribute) attribute).ErrorMessage);
                    }
                }
            }
        }
        base.OnModelUpdated(controllerContext, bindingContext);
    }
}

模型绑定提供者:

public class InheritanceAwareModelBinderProvider : Dictionary<Type, IModelBinder>, IModelBinderProvider {
    public IModelBinder GetBinder(Type modelType) {
        var binders = from binder in this
                      where binder.Key.IsAssignableFrom(modelType)
                      select binder.Value;

        return binders.FirstOrDefault();
    }
}

并持续global.asax注册:

var binderProvider = new InheritanceAwareModelBinderProvider {
    {
        typeof (IPageModel), new PageModelBinder() }
    };
ModelBinderProviders.BinderProviders.Add(binderProvider);

结果:http://cl.ly/IjCS

那你怎么看待这个解决方案呢?

答案 1 :(得分:0)

问题是没有名为MyProp的html字段,并且MVC不会对此属性进行任何验证。

实现目标的一种方法是摆脱Bar并在Bar's中创建Foo属性。您可以使用 AutoMapper 将管道代码最小化。

另一种解决方案是编写一个自定义验证属性,该属性根据null值进行验证,并使用它而不是Required属性。

答案 2 :(得分:0)

解决方案1 ​​

尝试自定义[Required]

,而不是使用ValidationAttribute
public class Foo {
    [RequiredBar]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }
    public string Name { get; set; }
}

public class RequiredBar : ValidationAttribute {

    public override bool IsValid(object value)
    {
        Bar bar = (Bar)value;

        // validate. For example
        if (bar == null)
        {
            return false;
        }

        return bar.Name != null;
    }
}

解决方案二:

只需将Required放在Bar的相应必需属性上,例如

public class Foo {
    //[RequiredBar]
    public Bar MyProp { get; set; }
}

public class Bar {
    [ScaffoldColumn(false)]
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }
}