专栏首页大内老A让我们的ASP.NET MVC应用可以单独维护验证消息

让我们的ASP.NET MVC应用可以单独维护验证消息

在项目开发中,我们会使用到很多的描述性文字,比如验证消息、错误消息和确认消息等,让这些文本消息具有可维护性具有重要的意义。虽然我们可以将它们存储于资源文件中,并且ASP.NET的ValidationAttribute也对这种方式提供了原生的支持。但是资源文件的每个条目仅仅是简单的键-值对,只能存储消息的文本值而已,在我们的项目开发中使用的是专门的一个维护消息的组件。在这篇文章中将会通过扩展现有的ValidationAttribute特性让ASP.NET MVC应用可以使用我们的消息组件来获取验证消息。[源代码从这里下载]

一、ExtendedValidationAttribute

我们通过如下一个MessageManager来模拟我们独立的消息组件。简单起见,我们通过一个静态字典来维护所有的消息,Key和Value分别代表消息的Id和文本值。从如下的代码可以看出,消息文本可以支持{0}、{1}、…形式表示站位符。GetMessage方法根据指定的消息ID和替换站位符的对象数组格式化一个完成得消息文本。

   1: public class MessageManager
   2: {
   3:     static Dictionary<string, string> messages = new Dictionary<string, string>();
   4:     static MessageManager()
   5:     {
   6:         messages.Add("RequiredField", "The \"{0}\" is mandatory!");
   7:         messages.Add("GreaterThan", "The \"{0}\" must be greater than \"{1}\"!");
   8:         messages.Add("LessThan", "The \"{0}\" must be less than \"{1}\"!");
   9:     }
  10:     public string GetMessage(string messageId, params object[] args)
  11:     {
  12:         return string.Format(CultureInfo.CurrentCulture, messages[messageId], args);
  13:     }
  14:     public static MessageManager Current = new MessageManager();
  15: }

通过直接继承ValidationAttribute的方式,我们定义了如下一个ExtendedValidationAttribute。我们仅仅定义了一个将消息ID和替换站位符的对象数组作为参数的构造函数,而该构造函数直接调用基类包含Func<string>参数的构造函数。至于用于获取验证消息Func<string>对象,则使用调用MessageManager的GetMessage方法来构建。

   1: public class ExtendedValidationAttribute : ValidationAttribute 
   2: { 
   3:     public ExtendedValidationAttribute(string messageId, params object[] args):
   4:         base(()=>MessageManager.Current.GetMessage(messageId,args))
   5:     {           
   6:     }
   7: }

二、扩展的RequiredAttribute和RangeAttribute

接下来我们来演示如何定义具体的ValidationAttribute,我们以用于验证必需字段/属性和值范围的RequiredAttribute和RangeAttribute为例。下面是我们自定义的RequiredAttribute和RangeAttribute,这里使用了一个比较讨巧的方式:直接调用System.ComponentModel.DataAnnotations.RequiredAttribute和System.ComponentModel.DataAnnotations.RangeAttribute的IsValid方法来实施验证。

   1: [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
   2: public class RequiredAttribute : ExtendedValidationAttribute
   3: {
   4:     public bool AllowEmptyStrings { get; set; }
   5:     public RequiredAttribute(string messageId, params object[] args) :
   6:         base(messageId,args)
   7:     {}
   8:     public override bool IsValid(object value)
   9:     {
  10:         return new System.ComponentModel.DataAnnotations.RequiredAttribute {AllowEmptyStrings = this.AllowEmptyStrings }.IsValid(value);
  11:     }
  12: }
  13:  
  14: [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
  15: public class RangeAttribute : ExtendedValidationAttribute
  16: {
  17:     private System.ComponentModel.DataAnnotations.RangeAttribute innerRangeAttribute;
  18:  
  19:     public RangeAttribute(double minimum, double maximum, string messageId, params object[] args) :
  20:         base(messageId, args)
  21:     {
  22:         innerRangeAttribute = new System.ComponentModel.DataAnnotations.RangeAttribute(minimum, maximum);
  23:     }
  24:  
  25:     public RangeAttribute(int minimum, int maximum, string messageId, params object[] args):  
  26:         base(messageId, args)
  27:     {
  28:         innerRangeAttribute = new System.ComponentModel.DataAnnotations.RangeAttribute(minimum, maximum);
  29:     }
  30:  
  31:     public RangeAttribute(Type type, string minimum, string maximum,string messageId, params object[] args) :
  32:         base(messageId, args)
  33:     {
  34:         innerRangeAttribute = new System.ComponentModel.DataAnnotations.RangeAttribute(type, minimum, maximum);
  35:     }
  36:  
  37:     public override bool IsValid(object value)
  38:     {
  39:         return innerRangeAttribute.IsValid(value);
  40:     }
  41: }

三、实例演示

接下来我们来演示上面定义的两个验证特性在ASP.NET MVC项目中的应用。我们先定义如下一个实体类型Person,RequiredAttribute和RangeAttribute分别应用在表示名字、年龄和体重的Name、Age和Weight三个属性上。具体的验证规则是:名称是必需的,年龄必须大于18周岁而体重不得终于160斤。表示验证消息的ID和站位符对象数组作了相应的设置。

   1: public class Person
   2: {
   3:     [Required("RequiredField","Name")]
   4:     public string Name { get; set; }
   5:     [Range(18,int.MaxValue,"GreaterThan","Age",18)]
   6:     public int Age { get; set; }
   7:     [Range(int.MinValue, 160, "LessThan", "Weight", 160)]
   8:     public double Weight { get; set; }
   9: }

在创建的ASP.NET MVC项目中添加下一个HomeController。

   1: public class HomeController : Controller
   2: {        
   3:     public ActionResult Index()
   4:     {
   5:         return View(new Person { Name = "Zhan San", Age = 24, Weight = 120 });
   6:     }
   7:  
   8:     [HttpPost]
   9:     public ActionResult Index(Person person)
  10:     {
  11:         if (this.ModelState.IsValid)
  12:         {
  13:             throw new NotImplementedException();
  14:         }
  15:         return View();
  16:     }
  17: }

Index.cshtml的内容如下所示,这是一个以Person对象作为Model的View。具体来说,这个View用于对Person对象三个属性的修改。

   1: @model Artech.Web.Mvc.Extensions.Person
   2:  
   3: @{
   4:     ViewBag.Title = "Index";
   5: }
   6:  
   7: <h2>Index</h2>
   8: @using (Html.BeginForm())
   9: {
  10: @Html.EditorForModel()
  11: <input type="submit" value="Save" />
  12: }

运行我们的程序,如果输入的内容不符合定义在Person类型上的验证规则,相应的验证消息会被现实,而这些消息都是通过MessageManager来获取的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 让IoC动态解析自定义配置(提供基于Unity的实现)

    在《通过自定义配置实现插件式设计》中,通过在运行时对配置的动态解析实现了真正的“插件式”设计,其本质就是让配置自行提供对配置类型实例的创建。在这篇文章中,我们将...

    蒋金楠
  • .NET的资源并不限于.resx文件,你可以采用任意存储形式[上篇]

    为了构建一个轻量级的资源管理框架以满足简单的本地化(Localization)的需求,我试图直接对现有的Resource编程模型进行扩展。虽然最终没能满足我们的...

    蒋金楠
  • 通过扩展改善ASP.NET MVC的验证机制[实现篇]

    在《使用篇》中我们谈到扩展的验证编程方式,并且演示了本解决方案的三大特性:消息提供机制的分离、多语言的支持和多验证规则的支持,我们现在来看看这样的验证解决方案最...

    蒋金楠
  • 策略模式——运筹帷幄

    三国情景再现: 诸葛亮在刘备去东吴招亲之前,特授予伴郎赵云三个锦囊,说是按天机拆开解决棘手问题。

    100000860378
  • Python 关于xpath查找XML元素的一点总结

    xpath = ".//xmlns:return//xmlns:copeWith"

    授客
  • Java基础-day11-接口;多态案例练习

    Java基础-day11-接口&多态案例练习 题目要求1(多态): 定义家类 方法:饲养动物 动物类: 属性:年龄、姓名 方法:吃饭、睡觉 猫类、狗类、猪类均为...

    奋斗蒙
  • 第76节:Java中的基础知识

    设置环境,安装操作系统,安装备份,就是镜像,jdk配置环境,eclipse下载解压即可使用,下载tomcat

    达达前端
  • [读书笔记]C#学习笔记四: C#2.0泛型 可控类型 匿名方法和迭代器

    一枝花算不算浪漫
  • 如何去除代码中的多次if而引发的一连串面试问题

    小白:不是,真正的工厂模式有两种:工厂方法和抽象工厂。工厂方法使用继承,首先定义一个抽象父类工厂,然后定义子类工厂,把工厂要创建的对象委托给子工厂类,子工厂类实...

    JavaQ
  • Spring是如何保证同一事务获取同一个Connection的?使用Spring的事务同步机制解决:数据库刚插入的记录却查询不到的问题【享学Spring】

    关于Spring的事务,它是Spring Framework中极其重要的一块。前面用了大量的篇幅从应用层面、原理层面进行了比较全方位的一个讲解。但是因为它过于重...

    YourBatman

扫码关注云+社区

领取腾讯云代金券