迁移Model元数据设置项
.NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)
阅读目录:
- 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel)
- 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型)
- 2.迁移ViewModel设置到外部配置文件(扩展Model元数据提供程序)
- 2.1.实现元数据提供程序(简单示例)
1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel)
使用ASP.NETMVC构建普通的中小型站点可以使用简单的Model元数据设置方式来控制ViewModel如何显示在View中,但是复杂的应用场景不会这么简单的就能完成;大型站点的ViewModel的体积非常大,真的大的超乎我们的想象(当然这里面有历史原因),这么大的一个显示实体我们需要在不同的页面中呈现它会非常的棘手;然而小型站点不太会遇见ViewModel在几十个页面中显示的情况出现,一般页面也就是几十个差不多了;
在大型电子商务应用中,UI层的一个ViewModel不仅用来呈现数据还充当着与远程SOA接口通讯的DTO作用,如果为了结构清晰完全可以将ViewModel与DTO分开,但是有时候我们确实需要考虑额外的性能开销(有时候我们只能接受历史遗留的问题,技术债务累积多久就要还多久);
这篇文章将讲解如何利用ASP.NETMVC开发大型站点时ViewModel中设置的元数据设置项随着不同的业务View不同而调用不同的元数据设置项,简单的讲也就是我们不会直接在ViewModel上应用元数据控制特性,而是通过将Model元数据设置项与具体的View绑定的方式来控制它在不同的View中运用不同的元数据控制项,元数据控制特性不会和具体的ViewModel绑定而是和具体的View绑定,因为只有View才是固定呈现什么内容,而ViewModel是用来共用的显示数据项的容器,我将通过本篇文章来讲解如何设计这样的高扩展性的ASP.NETMVC ViewModel使用结构;
1.2.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型)
在考虑使用配置文件将所需要的东西配置起来的时候,我们需要先确定到底需要将什么配置起来;这就需要我们先确定问题域,其实这也就是面向DSL编程的方法;
DSL:简单理解为面向特定领域的语言;该语言主要用来解决特定领域的实现问题,刚开始我们可以会把这个概念定义的过于庞大,希望能通过DSL解决一切领域问题,其实这是错误的;DSL其实是一小部分领域问题的提炼,如:我们这里的将ModelMetadata设置特性从原来定义在ViewModel上的迁移到外部去,这其中的主要问题域就是将ModelMetadata设置项与View绑定,而不是ViewModel;
只有先准确的找到问题域之后我们才能设计DSL来充分的表达这个问题域,通过XML能很好的表达任何特定领域结构的模型,当然你完全可以自己去设计DSL;
目前对ViewModel中设置的元数据控制特性都会作用于使用该ViewModel的所有View,我们要解决的问题是将上图中的ModelMetadata域提取出去与View进行绑定,从而得到一个干净的ViewModel和灵活的面向View的元数据控制功能;当我们成功迁移之后,我们将得到下图中的结构;
最终我们会得出这样的一个满足实际需求的结构;
2.迁移ViewModel设置到外部配置文件(扩展Model元数据提供程序)
要想成功迁移设置项我们必须要搞清楚ASP.NETMVC中Model元数据提供程序的原理,这样我们才能将原来获取元数据的方式改变成我们自己的获取策略;在元数据提供程序对象模型中主要的功能分为两部分(这里我们只介绍获取元数据过程):
我们需要将BuildModelMetadata功能区域换成我们自己的策略;
这样我们就可以将一组强大的元数据提供程序植入到ASP.NETMVC框架的内部;
通过CustomModelMetadataProviderFactory创建用于获取任何一个外部类型的元数据提供程序对象,比如:CustomModelMetadataProviderWithDb(用于数据库的接口),CustomModelMetadataProviderWithConfig(用户配置文件),CustomModelMetadataProviderWithService(远程Service);
迁移ModelMetadate缓存数据(紧要关头可以进行内存优化)
在ASP.NETMVC内部提供了用来获取某个ViewModel的ModelMetadata的提供程序,通过该入口我们将可以把Model元数据缓存在我们自己的容器中,当然绝佳的缓存位置就是当前应用服务器的本地进程,这里是最好的缓存位置,我们缓存元数据主要不是为了改变它的存放位置而是要改变它获取的途径和方式,这样其实会有很多好处,比如:通过工具化管理内存中的缓存数据,对其进行压缩等等,因为你已经可以控制其获取元数据的过程,这在紧要关头可能就是救命稻草,这里只是一点扩展性的介绍,当然要看具体的需求了,不过这确实是一个好的思路;
2.1.实现元数据提供程序(简单示例)
View、ViewModel、ModelMetadata 映射设计:
1 using System.Collections.Generic;
2 using System.Linq;
3 using System.Web.Mvc;
4
5 namespace MvcApplication4.Seed
6 {
7 public enum View
8 {
9 HomePage_Index,
10 HomePage_Edit
11 }
12 public enum ViewModel
13 {
14 Customer
15 }
16 public class ViewMappingModelMetadata
17 {
18 public View View { get; set; }
19 public ViewModel ViewModel { get; set; }
20 public ModelMetadata Metadata { get; set; }
21 }
22
23 public class ViewMappingModelMetadataCollection : Dictionary<View, List<ViewMappingModelMetadata>>
24 {
25 private static ViewMappingModelMetadataCollection coll = new ViewMappingModelMetadataCollection();
26 static ViewMappingModelMetadataCollection()
27 {
28 //在Homepage下的视图———来自外部文件的接口,这里只是示例显示
29 coll.Add(View.HomePage_Index, new List<ViewMappingModelMetadata>());
30 coll[View.HomePage_Index].Add(new ViewMappingModelMetadata()
31 {
32 View = View.HomePage_Index,
33 ViewModel = ViewModel.Customer,
34 Metadata =
35 new ModelMetadata(CustomModelMetadataProviderWithConfig.CurrentProvider, typeof(Models.Customer),
36 () => { return new Models.Customer().CustomerId; }, typeof(string), "CustomerId")
37 {
38 DisplayFormatString = @"HomePage\DisplayName:{0}"
39 }
40 });
41 //在EditCustomer下的视图——来自外部文件的接口,这里只是示例显示
42 coll.Add(View.HomePage_Edit, new List<ViewMappingModelMetadata>());
43 coll[View.HomePage_Edit].Add(new ViewMappingModelMetadata()
44 {
45 View = View.HomePage_Edit,
46 ViewModel = ViewModel.Customer,
47 Metadata = new ModelMetadata(
48 CustomModelMetadataProviderWithConfig.CurrentProvider, typeof(Models.Customer),
49 () => { return new Models.Customer().CustomerId; }, typeof(string), "CustomerId")
50 {
51 DisplayFormatString = @"Edit\DisplayName:{0}"
52 }
53 });
54 }
55 public static ViewMappingModelMetadataCollection Current
56 {
57 get { return coll; }
58 }
59
60 public ModelMetadata GetMetadataByView(View view, ViewModel model)
61 {
62 var metaList = from item in coll[view] where item.ViewModel == model select item.Metadata;
63 return metaList != null && metaList.Count() > 0 ? metaList.LastOrDefault() : null;
64 }
65 }
66 }
这两段是要被放到框架内部去完成的,这里只是为了演示其元数据的设置原理,所以简单这么写;
System.Web.Mvc.ModelMetadataProvider 实现自定义元数据提供程序:
1 using System;
2 using System.Collections.Generic;
3 using System.Web.Mvc;
4
5 namespace MvcApplication4.Seed
6 {
7 public class CustomModelMetadataProviderWithConfig : System.Web.Mvc.ModelMetadataProvider
8 {
9 private static CustomModelMetadataProviderWithConfig provider = new CustomModelMetadataProviderWithConfig();
10 public static CustomModelMetadataProviderWithConfig CurrentProvider
11 {
12 get { return provider; }
13 }
14
15 public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
16 {
17 throw new NotImplementedException();//复杂类型实现,属性的循环获取
18 }
19
20 public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
21 {
22 throw new NotImplementedException();//复杂类型实现,属性的循环获取
23 }
24
25 public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
26 {
27 if (modelAccessor == null) return null;
28 if (System.Web.HttpContext.Current.Session["viewname"] == null) return null;
29 var result = ViewMappingModelMetadataCollection.Current.GetMetadataByView(
30 (View)System.Web.HttpContext.Current.Session["viewname"], (ViewModel)System.Web.HttpContext.Current.Session["viewmodel"]);
31 if (modelAccessor != null)
32 result.Model = modelAccessor().GetType().GetProperty("CustomerId").GetValue(modelAccessor());
33 return result;
34 }
35 }
36 }
Customer模型定义:
1 public class Customer
2 {
3 public string CustomerId { get; set; }
4 }
在模型上我们没有应用任何一个 元数据控制特性,但是我们将在界面上看到效果;
View 视图定义:
1 @model MvcApplication4.Models.Customer
2
3 <table>
4 <tr>
5 <td>
6 <h2>编辑模式.</h2>
7 <h3>@Html.DisplayForModel(Model.CustomerId)</h3>
8 </td>
9 </tr>
10 </table>
11
12 @model MvcApplication4.Models.Customer
13
14 <table>
15 <tr>
16 <td>
17 <h2>显示模式.</h2>
18 <h3>@Html.EditorForModel(Model.CustomerId)</h3>
19 </td>
20 </tr>
21 </table>
22
23 这是两种模型的呈现方式;
我们自动设置的元数据已经起到效果了;
迁移Model元数据设置项的更多相关文章
- .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)
阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...
- ASP.NET MVC Model元数据(五)
ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...
- ASP.NET MVC Model元数据(四)
ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...
- ASP.NET MVC Model元数据(三)
ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...
- ASP.NET MVC Model元数据(一)
ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退 ...
- .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(三)
阅读目录: 7.HtmlHelper.HtmlHelper<T>中的ViewModel的类型推断 8.控制ViewModel中的某个属性的呈现(使用PartialView部分视图细粒度控制 ...
- Model元数据定制与Model模板
元数据这一词对于计算机科学来说不算陌生,对元数据的解释最简单的解释就是描述数据的数据,那么Model元数据当然是描述Model中各种成员的数据了,在ASP.NET MVC中ModelMetadata这 ...
- 【笔记】ASP.NET MVC Model元数据
问题1:什么叫Model元数据? Model元数据,是针对数据类型的一种描述信息.由于复杂类型(或者说类型嵌套的存在,比如CustomerModel中有一个属性为复杂类型Address)的存在,因此M ...
- Model元数据解析
Model 元数据是针对数据类型的一种描述信息,主要用于控制数据类型本身及其成员属性在界面上的呈现方式,同时也为Model 绑定和验证提供必不可少的元数据信息.一个复杂数据类型通过属性的方式定义了一系 ...
随机推荐
- c语言获取符号位整数和浮点
1. 为什么你应该得到的签位 非常多的时间,我们需要推断的数目值正和负,做了相应的逻辑处理.完成这一要求条件推断语句可以很好. 有时会出现以下情况, if (x > 0) { x = x - 1 ...
- C# 使用 Code Snippet 简化 Coding
在开发的项目的时候,你是否经常遇到需要重复编写一些类似的代码,比如是否经常会使用 for.foreach ? 在编写这两个循环语句的时候,你是一个字符一个字符敲还是使用 Visual Studio 提 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除)
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除) ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) ...
- Mysql编写定时任务事件
原文:Mysql编写定时任务事件 场景: 例如:某系统,用户每天只能拥有一次的抽奖机会,抽过后当天就不可再抽,但是过了24:00点后用户就重新拥有一次抽奖机会.像这种需要数据库定时对某个字段进行更新操 ...
- TRIZ系列-创新原理-28-替代机械系统原理
替代机械系统原理的详细描写叙述例如以下:1)用光.声.热.嗅觉系统替代机械系统:2)用电.磁或电磁场来与物体交互作用:3)用移动场替代精巧场,用随时间变化的场替代固定场,用结构化的场替代随机场:4)使 ...
- LeetCode——Spiral Matrix
Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral or ...
- Cassandra C++/NodeJs开发环境
工作的需要,开始更多地倾向于去中心化的结构,目前看来Cassandra算是去中心化DB中性能/管理最热门的选择,崇尚其P2P的理念. 自身原因对JAVA不擅长(周围写C的好少),还是更热衷于C++/J ...
- 在打包程序中自动安装SQL Server数据库 .
原文:在打包程序中自动安装SQL Server数据库 . 1.创建安装项目“Setup1”安装项目 在“文件”菜单上指向“添加项目”,然后选择“新建项目”. 在“添加新项目”对话框中,选择“项目类型” ...
- JS时间戳比较大小:对于一组时间戳(开始时间~结束时间)和另一组时间戳进行比较,用于判断被比较时间戳组是否在要求范围内
/* *JS时间戳比较大小:对于一组时间戳(开始时间~结束时间)和另一组时间戳进行比较,用于判断被比较时间戳组是否在要求范围内 *@param date1 date2(形如:'2015-01-01'类 ...
- Net Framework中的提供的常用委托类型
.Net Framework中的提供的常用委托类型 .Net Framework中提供有一些常用的预定义委托:Action.Func.Predicate.用到委托的时候建议尽量使用这些委托类型,而 ...