.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编程的方法;app

DSL:简单理解为面向特定领域的语言;该语言主要用来解决特定领域的实现问题,刚开始咱们能够会把这个概念定义的过于庞大,但愿能经过DSL解决一切领域问题,其实这是错误的;DSL实际上是一小部分领域问题的提炼,如:咱们这里的将ModelMetadata设置特性从原来定义在ViewModel上的迁移到外部去,这其中的主要问题域就是将ModelMetadata设置项与View绑定,而不是ViewModel;框架

只有先准确的找到问题域以后咱们才能设计DSL来充分的表达这个问题域,经过XML能很好的表达任何特定领域结构的模型,固然你彻底能够本身去设计DSL;ide

目前对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 这是两种模型的呈现方式; 

咱们自动设置的元数据已经起到效果了;

 

相关文章
相关标签/搜索