ASP.NET MVC的Model元数据与Model模板:模板的获取与执行策略

当我们调用HtmlHelper或者HtmlHelper<TModel>的模板方法对整个Model或者Model的某个数据成员以某种模式(显示模式或者编辑模式)进行呈现的时候,通过预先创建的代表Model元数据的ModelMetadata对象都可以找到相应的模板。如果模板对应着某个自定义的分部View,那么只需要执行该View即可;对于默认模板,则直接可以得到相应的HTML。本篇文章着重讨论模板的获取和执行机制,不过在这之前,顺便来讨论一下DataTypeAttribute和模板的关系。

一、 DataTypeAttribute和模板有何关系?

通过《初识Model元数据》针对Model元数据定义的介绍,我们知道通过DataTypeAttribute特性对目标元素设置的数据类型最终会反映在表示Model元数据的ModelMetadata对象的DataTypeName属性上。此外,对于某些设置的数据类型,比如Date、Time、Duration和Currency等,还会随之创建一个DisplayFormatAttribute应用到ModelMetadata上。那么ModelMetadata的DataTypeName属性对目标元素的最终呈现具有怎样的影响呢?

实际上在模板匹配的过程中会将ModelMetadata的DataTypeName属性当作模板名称来看待,所以下面两种形式的Model类型定义可以看成是等效的。通过UIHintAttribute特性设置的模板名称和通过DataTypeAttribute特性设置的数据类型的唯一不同之处在于前者具有更高的优先级。换句话说,如果将UIHintAttribute和DataTypeAttribute同时应用到同一个数据成员分别将模板名称和数据类型设置为ABC和123,自定义模板123只有在模板ABC不存在的情况下才会被使用。

   1: public class Model   2: {   3:     [DataType(DataType.Html)]   4:     public string Foo { get; set; }   5:   6:     [DataType(DataType.MultilineText)]   7:     public string Bar { get; set; }   8:   9:     [DataType(DataType.Url)]  10:     public string Baz { get; set; }  11: }  12:  13: public class Model  14: {  15:     [UIHint("Html")]  16:     public string Foo { get; set; }  17:  18:     [UIHint("MultilineText")]  19:     public string Bar { get; set; }  20:  21:     [UIHint("Url")]  22:     public string Baz { get; set; }  23: }

实例演示:证明DataTypeName与模板名称的等效性

为了证明通过DataTypeAttribute特性设置数据类型在针对目标元素进行可视化呈现过程中被视为模板名称,我们来做一个简单的实例演示。在这个实例中我们定义了如下一个表示三角形的数据类型Triangle,其属性A、B和C是一个Point对象,表示三个角所在的坐标。

   1: public class Triangle   2: {   3:     [DataType("PointInfo")]   4:      public Point A { get; set; }   5:   6:     [DataType("PointInfo")]   7:      public Point B { get; set; }   8:   9:     [DataType("PointInfo")]  10:     public Point C { get; set; }  11: }  12:  13: [TypeConverter(typeof(PointTypeConverter))]  14: public class Point  15: {  16:     public double X { get; set; }  17:     public double Y { get; set; }  18:     public Point(double x, double y)  19:     {  20:         this.X = x;  21:         this.Y = y;  22:     }  23:  24:     public static Point Parse(string point)  25:     {  26:         string[] split = point.Split(',');  27:         if (split.Length != 2)  28:         {  29:             throw new FormatException("Invalid point expression.");  30:         }  31:         double x;  32:         double y;  33:         if (!double.TryParse(split[0], out x) ||!double.TryParse(split[1], out y))  34:         {  35:             throw new FormatException("Invalid point expression.");  36:         }  37:         return new Point(x, y);  38:     }  39: }  40:  41: public class PointTypeConverter : TypeConverter  42: {  43:      public override bool CanConvertFrom(ITypeDescriptorContext context,Type sourceType)  44:     {  45:         return sourceType == typeof(string);  46:     }  47:  48:      public override object ConvertFrom(ITypeDescriptorContext context,CultureInfo culture, object value)  49:     {  50:         if (value is string)  51:         {  52:             return Point.Parse(value as string);  53:         }  54:         return base.ConvertFrom(context, culture, value);  55:     }  56: }

对于类型Triangle和Point的定义,有两点值得注意:其一,Triangle的三个A、B和C属性上应用了DataTypeAttribute特性并将自定义数据类型设置为PointInfo(不是Point);其二,Point类型上应用了TypeConverterAttribute特性并将TypeConverter类型设置为PointTypeConverter,后者支持源自字符串的类型转换。通过前面对复杂类型(Complex Type)的介绍,这样会将Triangle的三个属性从复杂类型成员转换成简单类型成员。根据前提介绍的关于Object模板对数据成员的便利规则,Triangle的这三个属性才能被最终呈现出来。

现在我们创建一个Model类型为Point的强类型分部View作为模板,并将其命名为PointInfo(和前面通过DataTypeAttribute特性指定的自定义数据类型一致)。我们只为Point定义关于显示模式的模板,所以我们将该分部View文件放在Views\Shared\DisplayTemplates中。如下面的代码片断所示,我们将一个Point对象显示为(X,Y)的形式。

   1: @model MvcApp.Models.Point   2: (@Model.X, @Model.Y)

现在我们创建一个默认的HomeCtroller。如下面的代码片断所示,在默认的Index操作方法中我们创建了一个Triangle对象将其呈现在默认的View中。

   1: public class HomeController : Controller   2: {   3:     public ActionResult Index()   4:     {   5:         Triangle triangle = new Triangle   6:         {   7:             A = new Point(1,2),   8:             B = new Point(2,3),   9:             C = new Point(3,4)  10:         };  11:         return View(triangle);  12:     }  13: }

下面是对应的View的定义,这是一个Model类型为Triangle的强类型View,我们仅仅调用了HtmlHelper<TModel>的DisplayModel方法将作为Model的Triangle对象以显示模式呈现出来。

   1: @model MvcApp.Models.Triangle   2: @Html.DisplayForModel()

运行该Web应用会在浏览器中得到如下图所示的呈现效果,我们可以看到作为我们创建的Triangle对象的A、B和C属性表示的三个角的坐标是完全按照我们定义的PointInfo模板的方式进行呈现的。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索模板
, 数据类型
, 类型
, model
, point
, public
formatexception
,以便于您获取更多的相关知识。

时间: 2024-10-03 23:47:09

ASP.NET MVC的Model元数据与Model模板:模板的获取与执行策略的相关文章

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子.[本文已经同步到<How ASP.NET MVC Works?>中] 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等

ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上

ASP.NET MVC默认采用基于标准特性的Model验证机制,但是只有应用在Model类型及其属性上的ValidationAttribute才有效.如果我们能够将ValidationAttribute特性直接应用到参数上,我们不但可以实现简单类型(比如int.double等)数据的Model验证,还能够实现"一个Model类型,多种验证规则",本篇文章将为你提供相关的解决方案(源代码从这里下载). 一.ValidationAttribute本身是可以应用到参数上的 如果你够细心应该会

ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidator

对于ASP.NET MVC基于标注特性的Model验证,很多人只知道应用在数据类型及其属性上用于定义验证规则和错误消息的ValidationAttribute.通过<ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidator>的介绍,我们知道了最终用于进行Model验证的是一个叫做ModelValidator的组件.ValidationAttribute对应的ModelValidator为DataAnnotationsModelValidat

ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidatorProvider

DataAnnotationsModelValidator最终是通过它对应的ModelValidatorProvider,即DataAnnotationsModelValidatorProvider创建的.通过前面的介绍我们知道它是AssociatedValidatorProvider的子类,后者在用于获取ModelValidator的GetValidators方法中已经根据指定的Model元数据所有特性创建出来,DataAnnotationsModelValidator只需要从中筛选出继承自V

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子. 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等.对于ASP.NET MVC来说,我们可以通过HtmlHelper/H

ASP.NET MVC的Model元数据与Model模板:预定义模板

通过ModelMetadata表示的Model元数据的一个主要的作用在于为定义在HtmlHelper和HtmlHelper<TModel>中的模板方法(这些模板方法包括Display/DisplayFor.Editor/EditorFor.DisplayForModel/EditForModel.Lable/LabelFor和DisplayText/DisplayTextFor等)提供用于最终生成HTML的元数据信息.在调用这些方法的时候,如果我们指定了一个具体的通过分部View定义的模板,或

ASP.NET MVC基于标注特性的Model验证:ValidationAttribute

通过前面的介绍我们知道ModelValidatorProviders的静态只读Providers维护着一个全局的ModelValidatorProvider列表,最终用于Model验证的ModelValidator都是通过这些ModelValidatorProvider来提供的.对于该列表默认包含的三种ModelValidatorProvider来说,DataAnnotationsModelValidatorProvider无疑是最重要的,ASP.NET MVC默认提供的基于数据标注特性的声明式

浅谈ASP.NET MVC 3中如何使用Model

昨天博客发了新文章,讲一下我对如何使用MVC中的Model的看法,不是什么大技术,当是一个技术讨论^^ 原文地址:http://www.youguanbumen.net/Article.aspx?id=79 原文: 前两天写了个文章ASP.NET MVC 3 -- Model远程验证,主要记录了一下ASP.NET MVC 3中新增的RemoteAttribute类的使用,得益于这个类,我们可以在模型中为属性配置客户端远程校验的业务,文章中给了出一个简单的实体类MyUser_Add,举了一个最常见

ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则

对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象,在不同的使用场景中可能具有不同的验证规则.举个简单的例子,对于一个表示应聘者的数据对象来说,针对应聘的岗位不同,肯定对应聘者的年龄.性别.专业技能等方面有不同的要求.但是ASP.NET MVC的Model验证确是Model驱动的,因为验证规则以验证特性的形式应用到Model类型及其属性上.这样的验证方式实际上限制了Model类型在基于不同验证规则的使用场景中的重用.通过上一篇文章<将V