Asp.net模块化开发之Mvc分区扩展框架

对于一个企业级项目开发,模块化是非常重要的。

默认Mvc框架的AreaRegistration对模块化开发已经支持比较好了,还有必要扩展吗?还能扩展吗?

本文中的栗子是使用.net4.0、Mvc4.0及Unity2.0(企业库4.0)的,提供完整源码。

本分区扩展集成了IoC和分区DI(依赖注入)及分区过滤器的支持。

本分区扩展框架(Fang.Mvc)在演示栗子源码中包含完整源码,拿到自己的项目直接引用即可使用了。

感兴趣的同学请继续,用AreaRegistration有不爽的看官请拭目以待...


一、先说一下我用Mvc不爽的地方,看大家是否有同感

1、分区类(继承AreaRegistration)是个"特殊"类型,只能创建一个对象,而且只能简单的"New",不能使用构造函数、属性和方法来初始化对象

好在Mvc是开源的,我们从AreaRegistration的源码中发现是,Mvc是通过AreaRegistration.RegisterAllAreas()初始化所有分区

从上图可以看到Mvc先通过把每个继承AreaRegistration的类型找出来,再通过Activator.CreateInstance创建对象。在我看来类型和对象应该是一对多的关系,分区类也一样。我希望对分区的字段和属性进行不同的初始化以便可以使用同一个类型创建不同的分区。

2、分区的完整路径提前写死了,哪怕是换一下前面的路径都休想

比如有个评论的功能,我希望做成一个分区。新闻的评论地址规则为/News/Comment/,博客的评论地址规则为/Blog/Comment/,使用Mvc默认分区就只能定义为/Comment/了

3、路由初始化需要使用Global.asax

其一、但是多个分区部署同一站点用谁的Global.asax呢?有人说每个Global都定义RegisterAllAreas,用谁的都行。但是对于程序员这个大多都是偏执狂的人群是很难接受的。如果哪个项目下线,正好整个站点都使用的是这个项目的Global,那就都挂了!有风险啊。

其二、那就建一个项目为主项目,其他项目都以分区的形式定义?What?谁是主项目?偏执狂纠结中...

其三、建一个项目为空项目为主项目,只有Global和RegisterAllAreas,还是觉得挺别扭的。

其四、定义一个HttpModule在Init中执行RegisterAllAreas。这个还算靠谱,建议大家使用。本扩展框架也是定义一个HttpModule来初始化一些Mvc的配置达到扩展目的的。

4、Mvc很多种过滤,但默认配置过滤器的方法只有两种,一种是Attribute,一种是GlobalFilters(全局过滤器)

其一、Attribute定义过滤器太细了,要每个Controller或者Action去加,不能漏哦,特别是权限判断

其二、GlobalFilters拦截所有请求,如果使用分区开发的项目,每个分区有自己的过滤器需求,该需求可能与其他分区冲突(影响其他分区的Controller正常执行)。

其三、分区我希望复用,其中的Controller当然也要服用,在不同的部署中有使用不同过滤器或者过滤器参数的需求,Attribute定义的过滤器很难满足要求。

总之我希望有一种过滤器只影响当前部署的分区,不需要提前和分区及Controller绑定(高耦合),部署(运行时)的时候再和指定分区关联(当然要借助IoC容器,这里使用的是微软的Unity框架)。

5、Mvc4.0支持DI,如果没有IoC容器的支持,很鸡肋

其一、Mvc4.0默认的DI基本上没有什么作用,必须扩展。

其二、每个分区有不同的DI(依赖注入)需求,我希望每个分区可以配置成不同的。

二、Mvc分区扩展方法

1、我们继续从源码查找分区初始化的过程

RegisterAllAreas调用CreateContextAndRegister

但是CreateContextAndRegister是一个internal保护的方法,不让我们用啊!好在这个方法没有几行代码,我们直接再写一个类似方法就可以了。

2、Mvc最重要的就是路由规则,这个也要搞清楚

这个简单,随便建一个分区就可以看得很清楚

原来Mvc是通过RegisterArea调用AreaRegistrationContext的MapRoute方法来设置路由规则的;而AreaRegistrationContext对象创建就更简单,直接New出来的(参考前面CreateContextAndRegister的源码截图)!

现在基本上都搞清楚了,可以动手进行扩展了。

3、首先对分区扩展类(Area),我们来增加一些功能

我这里定义了一个类型Fang.Mvc.Area继承AreaRegistration。这个是可以按个人爱好加一些功能的,最好是一些常用功能,每个分区项目的个性化功能可以通过再次继承这个类型来扩展

3.1 扩展分区基本属性

通过Name属性实现分区名的配置(注意:同一个站点下分区名不能重复)。

通过Path属性分区路径前缀,就是分区的路由规则前都加一个这个路径。其一、大家知道,如果路由规则冲突化,Mvc无法找到正常的路由规则,这个很要命,增加一个部署是配置的路径就很有必要了。其二、我的需求比较奇特,我希望同一个站点下可以部署多个相同的分区,就像前面说的我们要给/News/和/Blog/都部署Comment分区,访问路径不一样,访问的数据库或者数据表也可以不一样,对已数据源不一样就靠DI了,后面再继续说。

通过NameSpaces属性配置当前分区查找Controller的范围。如果没有配置就按Mvc默认处理,按当前分区类的命名空间。

4、定义一个路由规则注册类(AreaRoute)来达到把Area的配置应用到路由注册

AreaRoute通过调用AreaRegistrationContext的对应方法注册

AreaRoute调用Area的CheckName、CheckUrl和CheckNameSpaces来实现Area的配置

把分区的路由规则保存到Area的_routes列表中备用(这里不详述作用,不在本文探讨范围内)

5、现在开始搞定分区过滤器

5.1 在Area类增加属性Filters配置分区过滤器

5.2 定义AreaFilterProvider类型来调用Area的Filters

AreaFilterProvider继承Mvc框架的IFilterProvider接口

在分区初始化时把AreaFilterProvider添加到Mvc的FilterProviders.Providers中,任务完成。

6、该轮到期盼已久DI容器了

6.1 首先定义Fang.Mvc.Container类来封装一下Unity容器

这个使用其他容器工具也是可以的,甚至封装一个工厂,支持多种容器也未不可。

至于有人说Unity有"bug",不适合做DI。我使用Unity容器有几年了,还没完全搞明白Unity,我认为Unity容器还是挺博大精深的,足够我用了。至于"bug"也算不上bug,最多是坑,多踩踩就平了。至于Unity(及企业库)有多挺博大精深,不在本文探讨范围,敢兴趣的可以自己研究,找高手探讨。

找我交流也行(但是我还在学习中,认识可能还肤浅或者有错误,最好不要误导了大家)。

6.2 增加属性DependencyContainer配置DI(依赖注入)容器的名字

6.3 定义AreaDependencyResolver类来实现分区配置和DI配置的结合

AreaDependencyResolver继承Mvc框架的IDependencyResolver接口

接下来就简单了,按Http上线文信息获取分区配置,调用容器工厂,调用容器实现GetService方法即可。

7、万事俱备了,借HttpModule的东风吹起来

定义类AreaMergeModule继承asp.net的IHttpModule,在Init方法中一通调用初始化以上扩展的功能的初始化。

调用容器工厂获取Mvc容器,在容器中获取所有的Area对象并逐个初始化,再初始化AreaDependencyResolver。

三、重头戏开场,炒"栗子"

1、一个站点配置两个分区,分别调用不同的数据源

源码路径:\Test\MvcApplication1

1.1 先看分区及容器配置

配置文件:\Test\MvcApplication1\ConfigFiles\unity.config

以上使用分区类MvcApplication1.RouteConfig定义两个分区(A和B),每个分区的名字和路径等都配置不一样。

另外还额外定义了两个依赖注入的容器。名字分别为两个分区配置的依赖注入的容器名。

以上还可以看出分区类和分区的Controller没有依赖关系,事实上只要路由规则没有特殊路由及其他要求,可以使用定义好的默认分区类Area。而且分区定义是按命名空间,事实上原有复杂系统可以在不修改原项目的情况下按逻辑(命名空间)拆分为多个分区,以后看情况再逐个分区拆分为独立项目,优化项目结构。

如果有同学说你上面的配置看不懂,不好意思要补课了,找度娘,搜索"Unity2.0容器配置"(小心有一个叫Unity3d的东西是做游戏的,和这个没关系)。

1.2 再看HttpModule配置

配置文件:\Test\MvcApplication1\Web.config

system.web的httpModules在经典模式下起作用,system.webServer的modules在集成模式下起作用,如果不确定两个都配上就Ok了。

1.3 分区路由配置(与Mvc默认路由配置及分区配置对比)

配置文件:\Normaltest\MvcApplication4\App_Start\RouteConfig.cs

配置文件:\Test\MvcApplication1\App_Start\RouteConfig.cs

以上三种路由配置中,可以看出新改良的分区扩展居然比Mvc默认分区配置和静态路由配置更相似

首先使用该扩展配置路由没有新的学习成本

其次原非分区项目要改成分区项目建一个分区类(扩展后的),把路由规则直接复制过来,意味迁移成本非常低。

1.4 再看一下Controller怎么用DI

代码文件:\Test\MvcApplication1\Controllers\HomeController.cs

HomeController执行依赖一个数据源(Config),但是HomeController并没有定义和调用获取数据源的方法,只是把数据源(Config属性)声明为Dependency的。

1.5 最后看测试效果

例子有点简单,完全说明问题,两个不同路径(分区路径)的Url都访问到HomeController而且数据源(Config属性)自动初始化成功,而且这两个地址调用了不同的数据源。

2、分区过滤器的栗子

源码路径:\Test\Site

2.1 先看分区及容器配置

配置文件:\Test\Site\ConfigFiles\unity.config

这次配置更复杂了一点,定了三个分区,使用两个分区类。配置了一个过滤器,而且有两个分区(不同分区类)引用了该过滤。(依赖注入配置同前一个例子,没必要说了)

2.2 其他配置和上一个例子相似,直接看三个分区效果

对此不想多说了,一切都在以上的热乎乎的栗子里,我的目的已经达到了。你的目的达到了吗?

四、高潮来了,奉送源码

下载栗子(分区扩展框架)源码

瞬间高潮就结束了,是不是有些遗憾啊。本框架是从搜房内部框架中拆分出来的一部分。随着.net开源社区的快速发展,搜房作为广泛使用.net的大型互联网公司之一,正在逐步以新的姿态拥抱开源。

我们鼓励(甚者奖励)搜房的程序员参与开源项目或者把内部通用系统脱敏整理后在网上开源。

时间: 2024-12-23 05:28:00

Asp.net模块化开发之Mvc分区扩展框架的相关文章

Asp.net模块化开发之“部分版本部分模块更新(上线)”

项目开发从来就不是一个简单的问题.更难的问题是维护其他人开发的项目,并且要修改bug.如果原系统有重大问题还需要重构. 怎么重构系统不是本文探讨的问题,但是重构后如何上线部署和本文关系密切.这个大家可能刚兴趣. 言归正传,现在演示一下如果做到部分版本和部分模块更新. Asp.net模块化开发系列目录 1. Asp.net模块化开发之Mvc分区扩展框架(送源码) 2. Asp.net模块化开发之“开启分模块开发简单愉快之旅” 3. Asp.net模块化开发之“逻辑(项目)复用” 3.1. 不同角色

JS中的模块化开发之Sea.JS

模块化开发的好处: 1:减少冲突 2:提高性能 用sea.js为例:sea.js模块库下载地址:http://seajs.org/docs/#downloads 例子:获取非行间样式的模块化开发: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="

监控开发之用python扩展dstat插件自定义实时监控

dstat是一个python开源的实时监控工具,一般是用来做系统性能监控的.咱们这里只是提他的自定义插件开发,用来打造自己的dstat. 有朋友可能还没清楚是啥意思, 咱们查看系统的状体状态有人喜欢用vmstat,也有人喜欢用dstat.相比来说dstat的功能模块更全一点是,这里还只是说查看系统性能方面的 !   如果想一边查看,系统的各方面性能指标,还想看你应用的一些个负载相关,比如某个程序的负载,mongodb的锁lock百分比,mysql连接数...   懂了吧 ! 下面是dstat的插

ASP.NET Core开发之HttpContext

ASP.NET Core中的HttpContext开发,在ASP.NET开发中我们总是会经常用到HttpContext. 那么在ASP.NET Core中要如何使用HttpContext呢,下面就来具体学习ASP.NET Core HttpContext. 注入HttpContextAccessor ASP.NET Core中提供了一个IHttpContextAccessor接口,HttpContextAccessor 默认实现了它简化了访问HttpContext. 它必须在程序启动时在ISer

【转】ASP.NET Core开发之HttpContext

ASP.NET Core中的HttpContext开发,在ASP.NET开发中我们总是会经常用到HttpContext. 那么在ASP.NET Core中要如何使用HttpContext呢,下面就来具体学习ASP.NET Core HttpContext. 注入HttpContextAccessor ASP.NET Core中提供了一个IHttpContextAccessor接口,HttpContextAccessor 默认实现了它简化了访问HttpContext. 它必须在程序启动时在ISer

Android开发之MVC设计模式

Android的MVC设计模式即为模型(Model)-视图(View)-控制器(Controller) 1.模型对象存储着应用的数据和业务逻辑 2.视图对象知道如何在屏幕上绘制自己以及如何响应用户的输入,如用户的触摸等. 3.控制对象包含了应用的逻辑单元,是视图与模型对象的联系纽带 在Android中,控制器通常是 Activity . Fragment 或 Service 的子类 由于应用功能的不断扩展,程序往往会变得过于复杂而让人难以理解 而使用MVC模式还可以让类的复用更加容易.相比功能多

iOS开发之MVC

好久没有写文章了,上一篇对于初学者可能比较有用的文章吧-- 我的入行语言是Java.JSP,比较强调MVC模式,所以对MVC还是比较了解的.因此后来转入iOS开发,在模式上就没有那么纠结,但是对于很多初入编程领域的人来说可能会比较困惑,下面用一个简单的列表例子来说一下iOS开发当中的MVC模式. 首先,新建一个工程,在工程中新建两个UIViewController的子类,如图: 我将用这两个类来示例非MVC(MainViewController)和MVC(SecondViewController

Web开发之MVC框架

什么是MVC框架? 在这里我简要的说明一下,想要详细的了解MVC的小伙伴们可以上百度百科,或者找来相应的书籍,仔细研究和理解一下,但是要说明的的一点是,完全理解MVC并不是一件容易的事. MVC的全称为Model View Controller,是模型-视图-控制器的缩写,一种软件框架模式,通俗点讲,就是将应用程序的输入.处理和输出进行解耦,使M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式. 简单来说一下MVC框架的三个核心部件的内容,即Model.View和Controller.

前端模块化开发之seaJs

了解后端语言的童鞋一定听过模块化开发的概念,比如java.python等后端语言都有自己的模块化特性,然而和后端语言相比,javascript还尚未实现模块化的功能,虽然之后的更高版本可能引入模块化开发的概念,但是现阶段我们可以通过第三方控件来实现. 今天我就来给大家介绍下可以帮助我们实现前端模块化的工具——seaJs.如果对seaJs已经有实际使用经验的小伙伴可以直接忽略这篇文章. 如果有小伙伴了解requireJs,那么学习seaJs会相当的容易,因为requireJs也是前端模块化的构建工