English 中文(简体)
数据说明“ 不需要” 属性
原标题:DataAnnotations "NotRequired" attribute

我有一个模型 有点复杂。

我有我的 UserViewModel , 它有几个属性, 其中两个是 homePhone workPhone 。 两种类型都是 PhoneViewModel 。 在 PhoneViewModel 中, 我有 DroadCode , 所有字符。 我要将 drocod> drodCode 改为强制性, 但 AryaCode nution> nution

这非常有效。 我的问题是在 UserViewModel 中是强制性的,而 HomePhone 不是强制性的。

PhoneViewModel 中,我能否在 HomeWork 属性中设置任何属性,从而在 PhoneViewModel 属性中解开 Require 属性?

我试过了

[ValidateInput(false)]

但它只针对班级和方法。

守则:

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

    public PhoneViewModel HomePhone { get; set; }

    [Required]    
    public PhoneViewModel WorkPhone { get; set; }
}

public class PhoneViewModel
{
    public string CountryCode { get; set; }

    public string AreaCode { get; set; }

    [Required]
    public string Number { get; set; }
}
最佳回答

[2012年5月24日对5/24/2012号作出修正,使这个想法更加清晰]

我不确定这是正确的做法,但我认为你可以扩大这一概念的范围,并创造一种更通用/可重复使用的方法。

在 ASP.NET MVC 中,验证发生在约束阶段。当您在服务器上张贴表格时, DefaultModelBinder 就是根据请求信息创建示范实例并将验证错误添加到 ModelDigitary

在您的情况下,只要约束与 < code> homePhone 发生,验证就会起火,而 我认为 我们无法通过创建 海关验证属性或类似的 来做很多事情。

我所想的不是为 HomePhone 属性创建示范实例,因为当我们控制约束时,当我们控制验证时,当我们没有以 (区域代码、国家代码和编号或空白) (区域代码、国家代码和编号或空白) 客户模式绑定 。

海关模式绑定器 中,我们正在检查属性是否为 < code> homePhone ,以及窗体是否含有任何属性的值,如果不是的话,我们不约束属性,验证不会发生 homePhone 。简单地说, homePhone 的价值在 UserViewModel 中将是无效的。

  public class CustomModelBinder : DefaultModelBinder
  {
      protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
      {
        if (propertyDescriptor.Name == "HomePhone")
        {
          var form = controllerContext.HttpContext.Request.Form;

          var countryCode = form["HomePhone.CountryCode"];
          var areaCode = form["HomePhone.AreaCode"];
          var number = form["HomePhone.Number"];

          if (string.IsNullOrEmpty(countryCode) && string.IsNullOrEmpty(areaCode) && string.IsNullOrEmpty(number))
            return;
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
      }
  }

最后,您必须注册全球.asax.cs 的自定义模型粘合器。

  ModelBinders.Binders.Add(typeof(UserViewModel), new CustomModelBinder());

所以现在你们有一个动作 将用户ViewModel作为参数,

 [HttpPost]
 public Action Post(UserViewModel userViewModel)
 {

 }

我们的自定义模型绑定器开始运行, 窗体不显示 < compt> 区域代码、 countrycode 和 < homePhone / number 的任何值, 也不会出现任何验证错误, 而 < code> userViewModel. homePhone 是无效的 。 如果窗体上显示这些属性的任何值, 那么这些特性的验证将按预期发生 : < code> HomePhone

问题回答

我用过这个神奇的核子 做动态说明: < a href="https://github.com/jwaliszko/Expressive Antatations" rel="没有跟随 noreferrer" > 表达式说明

它允许你做以前不可能做的事

[AssertThat("ReturnDate >= Today()")]
public DateTime? ReturnDate { get; set; }

或 偶 或

public bool GoAbroad { get; set; }
[RequiredIf("GoAbroad == true")]
public string PassportNumber { get; set; }

Update: Compile annotations in a unit test to ensure no errors exist

@diego提到, 这可能会吓人地在字符串中写出代码, 但以下是我用来测试United Test的所有验证,

namespace UnitTest
{
    public static class ExpressiveAnnotationTestHelpers
    {
        public static IEnumerable<ExpressiveAttribute> CompileExpressiveAttributes(this Type type)
        {
            var properties = type.GetProperties()
                .Where(p => Attribute.IsDefined(p, typeof(ExpressiveAttribute)));
            var attributes = new List<ExpressiveAttribute>();
            foreach (var prop in properties)
            {
                var attribs = prop.GetCustomAttributes<ExpressiveAttribute>().ToList();
                attribs.ForEach(x => x.Compile(prop.DeclaringType));
                attributes.AddRange(attribs);
            }
            return attributes;
        }
    }
    [TestClass]
    public class ExpressiveAnnotationTests
    {
        [TestMethod]
        public void CompileAnnotationsTest()
        {
            // ... or for all assemblies within current domain:
            var compiled = Assembly.Load("NamespaceOfEntitiesWithExpressiveAnnotations").GetTypes()
                .SelectMany(t => t.CompileExpressiveAttributes()).ToList();

            Console.WriteLine($"Total entities using Expressive Annotations: {compiled.Count}");

            foreach (var compileItem in compiled)
            {
                Console.WriteLine($"Expression: {compileItem.Expression}");
            }

            Assert.IsTrue(compiled.Count > 0);
        }


    }
}

我不会使用模型Binder; 我会使用自定义的验证属性 :

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

    public HomePhoneViewModel HomePhone { get; set; }

    public WorkPhoneViewModel WorkPhone { get; set; }
}

public class HomePhoneViewModel : PhoneViewModel 
{
}

public class WorkPhoneViewModel : PhoneViewModel 
{
}

public class PhoneViewModel 
{
    public string CountryCode { get; set; }

    public string AreaCode { get; set; }

    [CustomRequiredPhone]
    public string Number { get; set; }
}

然后:

[AttributeUsage(AttributeTargets.Property]
public class CustomRequiredPhone : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ValidationResult validationResult = null;

        // Check if Model is WorkphoneViewModel, if so, activate validation
        if (validationContext.ObjectInstance.GetType() == typeof(WorkPhoneViewModel)
         && string.IsNullOrWhiteSpace((string)value) == true)
        {
            this.ErrorMessage = "Phone is required";
            validationResult = new ValidationResult(this.ErrorMessage);
        }
        else
        {
            validationResult = ValidationResult.Success;
        }

        return validationResult;
    }
}

如果不清楚,我将作一个解释,但我认为这是相当不言自明的。

只需观察一下: 如果绑定不仅仅是简单的存档, 以下代码会串连一个问题。 我有一个案例, 您在物体中嵌套了 东西, 它会跳过它, 并让一些被绑定的物体没有被绑绑住 。

可能的解决办法是

protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
     {
         if (!propertyDescriptor.Attributes.OfType<RequiredAttribute>().Any())
         {
             var form = controllerContext.HttpContext.Request.Form;

             if (form.AllKeys.Where(k => k.StartsWith(string.Format(propertyDescriptor.Name, "."))).Count() > 0)
             {
                 if (form.AllKeys.Where(k => k.StartsWith(string.Format(propertyDescriptor.Name, "."))).All(
                         k => string.IsNullOrWhiteSpace(form[k])))
                     return;
             }
         }

         base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
     }

感谢""http://www.altafkhatri.com" rel="no follow" >Altaf Khatri





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签