全面解析ASP.NET MVC模块化架构方案

什么叫架构?揭开架构神秘的面纱,无非就是:分层+模块化。任意复杂的架构,你也会发现架构师也就做了这两件事。

本文将会全面的介绍我们团队在模块化设计方面取得的经验。之所以加了“全面”二字,是因为本文的内容将会涉及到:数据库、路由、C#、JavaScript、CSS、HTML等一个完整模块所需要的内容。

在阅读本文之前后,你也可以转到我们的开源项目:https://github.com/leotsai/mvcsolution。这个开源项目完整的总结了我们团队在ASP.NET MVC领域的分层架构思想,同时也定义了很多标准。

本文的目的则主要是介绍架构思想之模块化。

当前项目架构以及模块化架构图

一个模块的运行通常要依托于一个完整的系统。在本文的例子中,模块化依托于我们的开源项目MvcSolution这个架构。下面先看看这个架构的工程引用关系图:

上面这个架构是系统原本的架构,而在这个原本的架构之上,我们怎么添加模块的呢?请看下图:

从上图可以看出,我们增加的模块是引用了系统原来的多个工程的,这虽然会增加模块与当前系统的耦合度,但是却让模块的开发变得简单很多。而对于我们团队来讲,因为所有项目都是基于MvcSolution这个架构,所以每一个模块都可以很快的融入每一个系统。

下面在看看添加了模块之后的项目文件结构:

由于我们这个模块不算大,所以就把所有C#文件都放到一个工程里面了,分层只在心中。这也有利于我们将这个模块搬运到其他项目中。

1. 模块的入口

我们模块的入口非常简单,没有反射,也没有动态初始化,就是一个再普通不过的System.Web.MvcAreaRegistration。 在Global.ascx.cs文件中,通过AreaRegistration.RegisterAllAreas();把所有引用的Area全部注册。

在这个AreaRegistration类中,主要完成了路由的注册以及IOC的注册,如下图:

这样,这个模块的公开URL地址就已经生成了,如:http://www.example.com/donating。你可以在程序其他地方添加这个链接,那么用户就可以访问这个模块了。

2. 模块化之数据访问

模块内的数据访问如何跟现有系统的数据访问共存,这个问题是所有模块化架构师最难处理的问题,相比其他文件(C#、JS、CSS、HTML),数据访问最难处理好,因为下面这个目标很难达到:

目标:模块内可以很轻易的访问现有数据库的所有内容,但是却最好不对现有数据库进行任何更改,只有这样,当该模块移除之后,才不会留下任何无用的代码;

在我们的实践当中,基本上可以达到这个目标。下面我就详细介绍我们是如何进行数据访问设计的,基于EF CodeFirst。

原有系统使用着一个非常复杂且庞大的数据库,我们希望新增加的模块不做任何更改。原有数据库大概长这个样子的:

我们增加的模块化工程的文件结构如下图:

我们是增加了一个新的数据库DonatingDataContext,当然,这个数据库继承自原有系统的数据库。这样,新增加的模块就可以完全访问原有数据库了。请看模块数据库代码:

 

上方代码请注意 base.OnModelCreating(modelBuilder); 这句话非常重要,干什么的就不用解释了。

在增加新模块才用到的表的时候,难免需要跟原有系统的表建立外键关系。正常的做法,我们是通过EntityTypeConfiguration<T>来添加,如下图:

但是在模块化设计中,由于不能修改原有系统中表的定义,所以用EntityTypeConfiguration<T>是无法完成外键关系定义的。这时,只能用DataAnnotations的方式:

public Guid CreatorUserId { get; set; }

[ForeignKey("CreatorUserId")]
public virtual User CreatorUser { get; set; }

这样,在新数据库中,就可以随意的访问原有数据库了。如下所示:

1 public DonatePost GetPost(Guid postId)
2 {
3 using (var db = new DonatingDataContext())
4 {
5 return db.DonatePosts.Get(postId);
6 }
7 }

而在发布到产品服务器的时候,只需要在产品数据库上执行新模块的SQL脚本即可(可以通过EF生成新库,再用ManagementStudio生成脚本)。

3. 模块化之静态文件(JS、CSS、HTML)

从本文最开始的文件结构图中可以看到,我们把几乎所有静态文件都放到了一个叫“Plugins/Donating”的文件夹中了,这将非常有利于我们搬运这个模块到其他项目中。

请注意上面段落中的“几乎”二字,这说明还有小部分文件不在这里。这部分特殊的文件都是JS,有两部分,一部分在“_js-plugins/donating”,另一部分在“_grunt/gruntfile.js”中。用过grunt的都知道,这是JS未压缩为混淆的源文件了,你也可以参考我们的开源项目MvcSolution 了解更多这两部分JS的设计思想。简单的将,这两部分JS在发布网站的时候,是要被删除的,不需要拷贝到服务器的。

下面,请看静态文件结构图:

上图说明了很多东西,除了js文件夹是由grunt生成的话,其他的都一目了然,不再赘述。

对于CSHTML文件,在我们的例子中,是引用的原有项目的一个Layout,包括一些基本的CSS和JS,都有引用原有项目。这固然增加了耦合度,但我们的项目都是基于同一个架构,各个层级的代码都在标准之内,所以还是可以很容易的搬运模块的。

好了,本文关于ASP.NET MVC模块化的介绍就完了,不知道你是否看的云里雾里的。没有关系,当你决定开始尝试一下模块化设计的时候,相信本文中的一些实践还是能给你一些启发的。

最后

希望大家针对本文中的观点和实践畅所欲言,说说你的看法。

MVC模块化架构的更多相关文章

  1. 全面解析ASP.NET MVC模块化架构方案

    什么叫架构?揭开架构神秘的面纱,无非就是:分层+模块化.任意复杂的架构,你也会发现架构师也就做了这两件事. 本文将会全面的介绍我们团队在模块化设计方面取得的经验.之所以加了“全面”二字,是因为本文的内 ...

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

    项目开发从来就不是一个简单的问题.更难的问题是维护其他人开发的项目,并且要修改bug.如果原系统有重大问题还需要重构. 怎么重构系统不是本文探讨的问题,但是重构后如何上线部署和本文关系密切.这个大家可 ...

  3. Asp.net Mvc模块化开发系列(目录)

    模块化开发是非常重要的,模块化开发是个系统性问题,为此我觉得有必须要写一个系列的文章才能基本说的清楚 那又为什么要写一个目录呢? 其一.是对我昨天承诺写一个系列新的文章的回应 其二.是先写出一个大纲, ...

  4. net Mvc模块化开发

    Asp.net Mvc模块化开发之“部分版本部分模块更新(上线)” 项目开发从来就不是一个简单的问题.更难的问题是维护其他人开发的项目,并且要修改bug.如果原系统有重大问题还需要重构. 怎么重构系统 ...

  5. Angular JS从入门基础 mvc三层架构 常用指令

    Angular JS从入门基础  mvc模型 常用指令 ★ 最近一直在复习AngularJS,它是一款优秀的前端JS框架,已经被用于Google的多款产品当中.AngularJS有着诸多特性,最为核心 ...

  6. ABP vnext模块化架构的最佳实践的实现

    在上一篇文章<手把手教你用Abp vnext构建API接口服务>中,我们用ABP vnext实现了WebAPI接口服务,但是并非ABP模块化架构的最佳实践.我本身也在学习ABP,我认为AB ...

  7. MVC实用架构设计(三)——EF-Code First(5):二级缓存

    前言 今天我们来谈谈EF的缓存问题. 缓存对于一个系统来说至关重要,但是是EF到版本6了仍然没有见到有支持查询结果缓存机制的迹象.EF4开始会把查询语句编译成存储过程缓存在Sql Server中,据说 ...

  8. MVC实用架构设计(三)——EF-Code First(4):数据查询

    前言 首先对大家表示抱歉,这个系列已经将近一个月没有更新了,相信大家等本篇更新都等得快失望了.实在没办法,由于本人水平有限,写篇博客基本上要大半天的时间,最近实在是抽不出这么长段的空闲时间来写.另外也 ...

  9. MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少代码相似度较高,比如负责实体映射的 EntityConfiguration,负责仓储操作的I ...

随机推荐

  1. 【Demo 0015】位置服务及地图

    本章学习要点:       1.  掌握位置相关类(CLLocationManager,MKUserLocation) 基本用法;        2.  掌握地图视图(MKMapView)基本用法; ...

  2. Android - 隐藏最顶端的通知条(Top Notification Bar)

    隐藏最顶端的通知条(Top Notification Bar/ActionBar) 本文地址: http://blog.csdn.net/caroline_wendy Android中, 视频播放等功 ...

  3. Indy的评价

    已经抛弃了indy,实在是不好,tcp在android下退出报错.我现在改用系统自带的httpclient.推荐RTC RTC带有一个tcp组件,不过处理方式跟indy不同,测试过,在android下 ...

  4. gradle学习系列之eclipse中简单构建android项目

    看不到图片能够去訪问这个网址看看:http://pan.baidu.com/s/1o6FrFkA 一.什么是Gradle 官网www.gradle.org上介绍Gradle是升级版(evolved)的 ...

  5. spring中bean的设计模式

    默认的是单例的. 如果不想单例需要如下配置: <bean id="user" class="..." singleton="false" ...

  6. oschina图形和图像工具开源软件

    图形和图像工具开源软件 http://www.oschina.net/project/tag/181/imagetools?sort=view&lang=21&os=0

  7. Android开发者必须深入学习的10个应用开源项目

    Android 开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项 目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的 ...

  8. 一种单片机支持WiFi的应用——SimpleWiFi在单片机中的应用

    一种单片机支持WiFi的应用——SimpleWiFi在单片机中的应用 先上图: 现在的智能控制都是基于微控制器,随着智能的手持终端的普及,基于智能终端的控制就会越来越普遍. WIFI便是其中的一种.W ...

  9. MySQL多表查询之外键、表连接、子查询、索引

    MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...

  10. Kaggle—Digit Recognizer竞赛

    Digit Recognizer 手写体数字识别  MNIST数据集 本赛 train 42000样例 test 28000样例,原始MNIST是 train 60000 test 10000 我分别 ...