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

本文将会全面的介绍我们团队在模块化设计方面取得的经验。之所以加了“全面”二字,是因为本文的内容将会涉及到:数据库、路由、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,当然,这个数据库继承自原有系统的数据库。这样,新增加的模块就可以完全访问原有数据库了。请看模块数据库代码:

 namespace Lin.Plugins.Donating.Data
{
public class DonatingDataContext : LinDataContext
{
public DbSet<DonateComment> DonateComments { get; set; }
public DbSet<DonatePost> DonatePosts { get; set; }
public DbSet<DonateWant> DonateWants { get; set; } public DonatingDataContext()
{
Database.SetInitializer<DonatingDataContext>(null);
} protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var mappings = typeof(DonatingDataContext).Assembly.GetInheritedTypes(typeof(EntityTypeConfiguration<>));
foreach (var mapping in mappings)
{
dynamic instance = Activator.CreateInstance(mapping);
modelBuilder.Configurations.Add(instance);
}
}
}
}

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

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

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

public Guid CreatorUserId { get; set; }

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

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

 public DonatePost GetPost(Guid postId)
{
using (var db = new DonatingDataContext())
{
return db.DonatePosts.Get(postId);
}
}

而在发布到产品服务器的时候,只需要在产品数据库上执行新模块的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模块化的介绍就完了,不知道你是否看的云里雾里的。没有关系,当你决定开始尝试一下模块化设计的时候,相信本文中的一些实践还是能给你一些启发的。

最后

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

全面解析ASP.NET MVC模块化架构方案的更多相关文章

  1. MVC模块化架构

    全面解析ASP.NET MVC模块化架构方案 什么叫架构?揭开架构神秘的面纱,无非就是:分层+模块化.任意复杂的架构,你也会发现架构师也就做了这两件事. 本文将会全面的介绍我们团队在模块化设计方面取得 ...

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

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

  3. Asp.net mvc项目架构分享系列之架构概览

    Asp.net mvc项目架构分享系列之架构概览 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4.项目架构 ...

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

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

  5. ASP.NETCORE MVC模块化

    ASP.NETCORE MVC模块化编程 前言 记得上一篇博客中跟大家分享的是基于ASP.NETMVC5,实际也就是基于NETFRAMEWORK平台实现的这么一个轻量级插件式框架.那么今天我主要分享的 ...

  6. ASP.NET MVC 多语言方案

    前言: 好多年没写文章了,工作很忙,天天加班, 每天都相信不用多久,就会升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰,想想还有点小激动~~~~ 直到后来发生了邮箱事件,我竟然忘了给邮箱密 ...

  7. 解析ASP.NET Mvc开发之EF延迟加载

    目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 ------------------------ ...

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

    对于一个企业级项目开发,模块化是非常重要的. 默认Mvc框架的AreaRegistration对模块化开发真的支持很好吗?真的有很多复杂系统在使用默认的分区开发的吗?我相信大部分asp.net的技术团 ...

  9. Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”

    整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...

随机推荐

  1. div实现自适应高度的textarea,实现angular双向绑定

    相信不少同学模拟过腾讯的QQ做一个聊天应用,至少我是其中一个. 过程中我遇到的一个问题就是QQ输入框,自适应高度,最高高度为3row. 如果你也像我一样打算使用textarea,那么很抱歉,你一开始就 ...

  2. Kooboo CMS技术文档之一:Kooboo CMS技术背景

    语言平台 依赖注入方案 存储模型 1. 语言平台 Kooboo CMS基于.NET Framework 4.x,.NET Framework 4.x的一些技术特性成为站点开发人员使用Kooboo CM ...

  3. C#发送邮箱

    之前自己从来没有做过发送邮箱的功能,前段时间项目需要,在找了很多帖子之后,终于实现了. 之后有整理了一下,写了一个类.直接给类传递信息,就可以发送了. 这里还需要说明的是,发送邮箱需要开通POP3/S ...

  4. AutoMapper的介绍与使用(一)

    软件环境 vs2015 asp.net mvc 5 .NET Framework 4.5.2 AutoMapper 5.2.0.0 AutoMapper安装 新建asp.net mvc 项目 Auto ...

  5. .Net语言 APP开发平台——Smobiler学习日志:如何快速在手机上实现ContextMenu

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的&qu ...

  6. StatePattern(状态模式)

    /** * 状态模式 * @author TMAC-J * 状态模式和策略模式很像,其实仔细研究发现完全不一样 * 策略模式各策略之间没有任何关系,独立的 * 状态模式各状态之间接口方法都是一样的 * ...

  7. 多本地代码工作点更新到2个远端GIT仓库

    摘要:本文介绍了笔者多个本地工作节点(地方)的多台电脑(PC/笔记本电脑)同步源码到2个远端的GIT(一个GITHUB国外强制公开,一个oschina国内可不公开). 作者:太初 转载说明:请指明原作 ...

  8. 【每日一linux命令1】linux命令路径

    一.路径: 执行命令前必须要考虑的一步是命令的路径,若是路径错误或是没有正确的指定,可能导致错误 的执行或是找不到该命令.要知道设置的路径,可执行以下命令: echo $PATH 显示结果: 这时我们 ...

  9. 理解Storm并发

    作者:Jack47 PS:如果喜欢我写的文章,欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 注:本文主要内容翻译自understanding-the-parall ...

  10. [PHP源码阅读]trim、rtrim、ltrim函数

    trim系列函数是用于去除字符串中首尾的空格或其他字符.ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符. 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下 ...