当前位置: 首页 > news >正文

.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;

wKioL1Lcu8iwXQu9AAKOmvUhr9o430.jpg

目前对ViewModel中设置的元数据控制特性都会作用于使用该ViewModel的所有View,我们要解决的问题是将上图中的ModelMetadata域提取出去与View进行绑定,从而得到一个干净的ViewModel和灵活的面向View的元数据控制功能;当我们成功迁移之后,我们将得到下图中的结构;

wKiom1LcvATA23U_AALqvBadUhY734.jpg

最终我们会得出这样的一个满足实际需求的结构;

2.迁移ViewModel设置到外部配置文件(扩展Model元数据提供程序)

要想成功迁移设置项我们必须要搞清楚ASP.NETMVC中Model元数据提供程序的原理,这样我们才能将原来获取元数据的方式改变成我们自己的获取策略;在元数据提供程序对象模型中主要的功能分为两部分(这里我们只介绍获取元数据过程):

wKiom1LcvCXhnVA6AAE0vo5OTB8326.jpg

我们需要将BuildModelMetadata功能区域换成我们自己的策略;

wKioL1LcvBWiNp8wAAI79GDi5Hw775.jpg

这样我们就可以将一组强大的元数据提供程序植入到ASP.NETMVC框架的内部;

通过CustomModelMetadataProviderFactory创建用于获取任何一个外部类型的元数据提供程序对象,比如:CustomModelMetadataProviderWithDb(用于数据库的接口),CustomModelMetadataProviderWithConfig(用户配置文件),CustomModelMetadataProviderWithService(远程Service);

迁移ModelMetadate缓存数据(紧要关头可以进行内存优化)

在ASP.NETMVC内部提供了用来获取某个ViewModel的ModelMetadata的提供程序,通过该入口我们将可以把Model元数据缓存在我们自己的容器中,当然绝佳的缓存位置就是当前应用服务器的本地进程,这里是最好的缓存位置,我们缓存元数据主要不是为了改变它的存放位置而是要改变它获取的途径和方式,这样其实会有很多好处,比如:通过工具化管理内存中的缓存数据,对其进行压缩等等,因为你已经可以控制其获取元数据的过程,这在紧要关头可能就是救命稻草,这里只是一点扩展性的介绍,当然要看具体的需求了,不过这确实是一个好的思路;

2.1.实现元数据提供程序(简单示例)

View、ViewModel、ModelMetadata 映射设计:

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace MvcApplication4.Seed
{
    public enum View
    {
        HomePage_Index,
        HomePage_Edit
    }
    public enum ViewModel
    {
        Customer
    }
    public class ViewMappingModelMetadata
    {
        public View View { get; set; }
        public ViewModel ViewModel { get; set; }
        public ModelMetadata Metadata { get; set; }
    }
    public class ViewMappingModelMetadataCollection : Dictionary<View, List<ViewMappingModelMetadata>>
    {
        private static ViewMappingModelMetadataCollection coll = new ViewMappingModelMetadataCollection();
        static ViewMappingModelMetadataCollection()
        {
            //在Homepage下的视图———来自外部文件的接口,这里只是示例显示
            coll.Add(View.HomePage_Index, new List<ViewMappingModelMetadata>());
            coll[View.HomePage_Index].Add(new ViewMappingModelMetadata()
            {
                View = View.HomePage_Index,
                ViewModel = ViewModel.Customer,
                Metadata =
                    new ModelMetadata(CustomModelMetadataProviderWithConfig.CurrentProvider, typeof(Models.Customer),
                    () => { return new Models.Customer().CustomerId; }, typeof(string), "CustomerId")
                    {
                        DisplayFormatString = @"HomePage\DisplayName:{0}"
                    }
            });
            //在EditCustomer下的视图——来自外部文件的接口,这里只是示例显示
            coll.Add(View.HomePage_Edit, new List<ViewMappingModelMetadata>());
            coll[View.HomePage_Edit].Add(new ViewMappingModelMetadata()
            {
                View = View.HomePage_Edit,
                ViewModel = ViewModel.Customer,
                Metadata = new ModelMetadata(
                    CustomModelMetadataProviderWithConfig.CurrentProvider, typeof(Models.Customer),
                    () => { return new Models.Customer().CustomerId; }, typeof(string), "CustomerId")
                    {
                        DisplayFormatString = @"Edit\DisplayName:{0}"
                    }
            });
        }
        public static ViewMappingModelMetadataCollection Current
        {
            get { return coll; }
        }
        public ModelMetadata GetMetadataByView(View view, ViewModel model)
        {
            var metaList = from item in coll[view] where item.ViewModel == model select item.Metadata;
            return metaList != null && metaList.Count() > 0 ? metaList.LastOrDefault() : null;
        }
    }
}

wKiom1LcvGOyaIhUAAMWffXtoP8729.jpg

这两段是要被放到框架内部去完成的,这里只是为了演示其元数据的设置原理,所以简单这么写;

System.Web.Mvc.ModelMetadataProvider 实现自定义元数据提供程序:

using System;
using System.Collections.Generic;
using System.Web.Mvc;
namespace MvcApplication4.Seed
{
    public class CustomModelMetadataProviderWithConfig : System.Web.Mvc.ModelMetadataProvider
    {
        private static CustomModelMetadataProviderWithConfig provider = new CustomModelMetadataProviderWithConfig();
        public static CustomModelMetadataProviderWithConfig CurrentProvider
        {
            get { return provider; }
        }
        public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
        {
            throw new NotImplementedException();//复杂类型实现,属性的循环获取
        }
        public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
        {
            throw new NotImplementedException();//复杂类型实现,属性的循环获取
        }
        public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
        {
            if (modelAccessor == null) return null;
            if (System.Web.HttpContext.Current.Session["viewname"] == null) return null;
            var result = ViewMappingModelMetadataCollection.Current.GetMetadataByView(
                    (View)System.Web.HttpContext.Current.Session["viewname"], (ViewModel)System.Web.HttpContext.Current.Session["viewmodel"]);
            if (modelAccessor != null)
                result.Model = modelAccessor().GetType().GetProperty("CustomerId").GetValue(modelAccessor());
            return result;
        }
    }
}

Customer模型定义:

public class Customer
{
    public string CustomerId { get; set; }
}

在模型上我们没有应用任何一个 元数据控制特性,但是我们将在界面上看到效果;

View 视图定义:

@model  MvcApplication4.Models.Customer
<table>
    <tr>
        <td>
            <h2>编辑模式.</h2>
            <h3>@Html.DisplayForModel(Model.CustomerId)</h3>
        </td>
    </tr>
</table>
@model  MvcApplication4.Models.Customer
<table>
    <tr>
        <td>
            <h2>显示模式.</h2>
            <h3>@Html.EditorForModel(Model.CustomerId)</h3>
        </td>
    </tr>
</table>

这是两种模型的呈现方式;

wKioL1LcvIDwwb2EAACcV13jnlc872.jpg

wKiom1LcvLODkgW3AACQDh8jEJI862.jpg

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

作者:王清培

出处:http://wangqingpei557.blog.51cto.com/

本文版权归作者和51CTO共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。


相关文章:

  • VirtualBox和VMware安装Mac OS 10.11——虚拟机安装黑苹果
  • DOS建立带点的文件夹
  • 算法之智能搜索(上)
  • 一种基于云存储架构的开放电子病历平台
  • ES6核心特性
  • greenDAO讲义(一):使用篇
  • vue中完美解决html2canvas图片跨域问题
  • Eclipse+kafka集群 实例源码
  • 高并发处理思路与手段(六):服务降级与服务熔断
  • 2014第6周日杂记
  • 26. Remove Duplicates from Sorted Array C++ 删除排序数组中的重复项
  • Usage of API documented as @since 1.8+”报错的解决办法
  • Mysql容器启动失败-解决方案
  • Linux的epoll模型
  • java B2B2C电子商务平台分析之七-Spring Cloud Config
  • [LeetCode] Wiggle Sort
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • es6(二):字符串的扩展
  • FastReport在线报表设计器工作原理
  • gcc介绍及安装
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • IDEA 插件开发入门教程
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • java2019面试题北京
  • magento 货币换算
  • PAT A1017 优先队列
  • 观察者模式实现非直接耦合
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端_面试
  • 实现简单的正则表达式引擎
  • 推荐一个React的管理后台框架
  • 微信小程序开发问题汇总
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • # 数论-逆元
  • #{} 和 ${}区别
  • #13 yum、编译安装与sed命令的使用
  • #HarmonyOS:Web组件的使用
  • #include
  • (solr系列:一)使用tomcat部署solr服务
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (力扣)循环队列的实现与详解(C语言)
  • (十八)SpringBoot之发送QQ邮件
  • (十三)Maven插件解析运行机制
  • (转) Android中ViewStub组件使用
  • (转)程序员疫苗:代码注入
  • **PHP分步表单提交思路(分页表单提交)
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET关于 跳过SSL中遇到的问题
  • .NET开发不可不知、不可不用的辅助类(一)
  • :O)修改linux硬件时间