使用MvcContrib分离ASP.NET MVC项目
概述
在ASP.NET MVC复杂项目的开发中,随着项目规模的扩大,我们可能需要对不同模块按需进行分离。可以使用ASP.NET MVC框架提供的“区域(Areas)”功能来组织项目,具体参见《使用Areas分离ASP.NET MVC项目》。但是从上文可以看出,几个项目都是围绕Areas,通过“Build Event”最后整合到一起,总是有些“藕断丝连”的感觉。可以说,通过Areas独立出来的项目,并没有达到彻底的分离。在上文的评论中,有朋友指出可以使用MvcContrib,于是学习了一下。
MvcContrib(Portable Area)可以将一个MVC项目里的所有内容(包括Views,Controllers,Scripts等)都编译到一个dll里面。如此一来,该MVC项目就可以作为一个“插件(或部件)/Plugin(or Widget)”为其他项目使用,具有很强的重用性。
环境准备
仍然考虑上文中的场景:将面向用户的前台和面向管理员的后台进行分离。
- 首先新建一个ASP.NET MVC3项目MyPortableAreaDemo(前台项目),项目模板选择“Internet Application”,视图引擎选择“Razor”。
- 新增一个空的MVC项目MyPortableAreaDemo.Admin(后台项目),删除Global.asax.
- 在MyPortableAreaDemo.Admin项目上面右键,添加一个类AdminAreaRegistration.cs并输入以下内容:
public class AdminAreaRegistration : AreaRegistration { public override string AreaName { get { return "Admin"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); } }
安装MvcContrib
使用NuGet为MyPortableAreaDemo.Admin安装MvcContrib:
或者在Package Manager Console里面输入:Install-Package MvcContrib 进行安装。
使用MvcContrib
打开AdminAreaRegistration.cs,然后将其基类AreaRegistration修改为PortableAreaRegistration,将RegisterArea方法声明修改为(重要!):
public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus)
为默认路由加上命名空间限制,并且在RegisterArea方法中加入RegisterAreaEmbeddedResources()。现在看起来应该是这样子:
在MyPortableAreaDemo.Admin/Controllers下面添加一个HomeController和Index的Action,并且添加相应的View文件:
下面这一步非常重要:
将所有的css,js,image静态文件的属性-生成操作(Build Action)选择“嵌入的资源(Embedded Resources)”。这意味着这些静态文件都将被编译进dll文件里面,而不是像之前那样,以单独物理文件存在。这样做的好处是整个项目里面的结构都是相对固定的,一个dll就包括了整个工程里的所有内容,可复用性高。缺点是每次修改了这个项目里的内容(即便是修改js或view等静态内容),也必须要重新编译整个项目。这就要看个人的取舍了,你可以权衡这样做是否值得。
现在在主项目里面引用Admin项目。在主项目里面添加一个叫做Areas的文件夹,并将MyPortableAreaDemo/Web.config复制到新建的Areas文件夹下。
为什么需要这样做呢?这是因为Admin项目里的Portable Area在被主项目加载时,会被映射到这个Areas文件夹里,此时Controller就会在Areas下面去寻找对应的Views(而不是在主项目里寻找)视图。
好了,现在编译(记住,Portable Areas项目修改任何内容都必须重新编译!)整个解决方案,从主项目启动后访问:/Admin/Home/Index,如果一切顺利,你会看到:
访问静态文件
前面我们提到所有的静态文件(js,css,image)都被编译到了dll中,那么我们如何访问这些静态内容呢?尝试直接访问/Admin/Scripts/jquery-1.4.4.min.js,浏览器会提示“无法找到资源”。因此我们还需要修改一下AdminAreaRegistration.cs,添加如下路由:
context.MapRoute( "ResourceRoute", base.AreaRoutePrefix + "/resource/{resourceName}", new { controller = "EmbeddedResource", action = "Index" }, new[] { "MvcContrib.PortableAreas" } );
这段路由的意思是将所有的静态资源都交给MvcContrib.PortableAreas.EmbeddedResource去处理,因此现在我们可以使用:/Admin/resource/Scripts.jquery-1.4.4.min.js来访问jquery。注意其中的“Scripts.jquery-1.4.4.min.js”中间是“.”而不是“/”。
在View视图中,还可以用<%= Url.Resource("Scripts.jquery-1.4.4.min.js") %>的访问形式。Url.Resource()方法集成在MvcContrib中。
通过这种方式,我们可以完全控制程序集中的所有静态内嵌资源,如果想通过访问物理文件的方式访问内嵌资源,可以添加如下路由:
//Scripts context.MapRoute( AreaName + "_Scripts", base.AreaRoutePrefix + "/Scripts/{resourceName}", new { controller = "EmbeddedResource", action = "Index", resourcePath="Scripts" }, new[] { "MvcContrib.PortableAreas" } ); //Content context.MapRoute( AreaName + "_Content", base.AreaRoutePrefix + "/Content/{resourceName}", new { controller = "EmbeddedResource", action = "Index", resourcePath = "Content" }, new[] { "MvcContrib.PortableAreas" } );
注意其中的resourcePath的值。现在我们就可以直接使用/Admin/Scripts/jquery-1.4.4.min.js这种方式来访问内嵌资源了。
总结
通过MvcContrib Portable Area我们可以将MVC项目进行有效分离,并且使用内嵌资源的方式,将整个分离出来的项目编译成一个dll,可以随意复制引用,可重用性较好。
但是,这种方式也存在以下不足之处:
- 由于所有静态资源都被编译到dll中,这就不可避免造成dll的体积变得越来越大,尤其在图片比较多的情况下更为明显。
- 静态资源的访问形式。如果上面的Content,Scripts文件夹下面还有子文件夹(这是很常见的情形),只能通过resource的方式访问,而不能通过伪物理地址的方式,不算太友好。
基于上面两点,建议只将view视图文件作为内嵌资源编译到dll中,所有的静态文件(js,css,image)可以放到主项目中,直接访问。或者放在Admin项目里面,通过Build Event的方式同步到主项目相应目录里(参考上文)。
接下来准备研究一下nopCommerce的项目分离方式,插件式开发,希望每天都能进步一些。
项目源码下载:https://files.cnblogs.com/dingji/MyPortableAreaDemo.zip