使用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)”为其他项目使用,具有很强的重用性。

环境准备

仍然考虑上文中的场景:将面向用户的前台和面向管理员的后台进行分离。

  1. 首先新建一个ASP.NET MVC3项目MyPortableAreaDemo(前台项目),项目模板选择“Internet Application”,视图引擎选择“Razor”。
  2. 新增一个空的MVC项目MyPortableAreaDemo.Admin(后台项目),删除Global.asax.
  3. 在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:

2012-6-6 21-52-49

或者在Package Manager Console里面输入:Install-Package MvcContrib 进行安装。

2012-6-6 21-59-31

使用MvcContrib

打开AdminAreaRegistration.cs,然后将其基类AreaRegistration修改为PortableAreaRegistration,将RegisterArea方法声明修改为(重要!):

public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus)

为默认路由加上命名空间限制,并且在RegisterArea方法中加入RegisterAreaEmbeddedResources()。现在看起来应该是这样子:

2012-6-10 19-39-00

在MyPortableAreaDemo.Admin/Controllers下面添加一个HomeController和Index的Action,并且添加相应的View文件:

2012-6-10 19-40-13

下面这一步非常重要:

将所有的css,js,image静态文件的属性-生成操作(Build Action)选择“嵌入的资源(Embedded Resources)”。这意味着这些静态文件都将被编译进dll文件里面,而不是像之前那样,以单独物理文件存在。这样做的好处是整个项目里面的结构都是相对固定的,一个dll就包括了整个工程里的所有内容,可复用性高。缺点是每次修改了这个项目里的内容(即便是修改js或view等静态内容),也必须要重新编译整个项目。这就要看个人的取舍了,你可以权衡这样做是否值得。

2012-6-10 17-34-03

现在在主项目里面引用Admin项目。在主项目里面添加一个叫做Areas的文件夹,并将MyPortableAreaDemo/Web.config复制到新建的Areas文件夹下。

为什么需要这样做呢?这是因为Admin项目里的Portable Area在被主项目加载时,会被映射到这个Areas文件夹里,此时Controller就会在Areas下面去寻找对应的Views(而不是在主项目里寻找)视图。

好了,现在编译(记住,Portable Areas项目修改任何内容都必须重新编译!)整个解决方案,从主项目启动后访问:/Admin/Home/Index,如果一切顺利,你会看到:

2012-6-10 18-49-47

访问静态文件

前面我们提到所有的静态文件(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,可以随意复制引用,可重用性较好。

但是,这种方式也存在以下不足之处:

  1. 由于所有静态资源都被编译到dll中,这就不可避免造成dll的体积变得越来越大,尤其在图片比较多的情况下更为明显。
  2. 静态资源的访问形式。如果上面的Content,Scripts文件夹下面还有子文件夹(这是很常见的情形),只能通过resource的方式访问,而不能通过伪物理地址的方式,不算太友好。

基于上面两点,建议只将view视图文件作为内嵌资源编译到dll中,所有的静态文件(js,css,image)可以放到主项目中,直接访问。或者放在Admin项目里面,通过Build Event的方式同步到主项目相应目录里(参考上文)。

接下来准备研究一下nopCommerce的项目分离方式,插件式开发,希望每天都能进步一些。

项目源码下载:http://files.cnblogs.com/dingji/MyPortableAreaDemo.zip

posted @ 2012-06-10 21:15  Lyon.L  阅读(9258)  评论(38编辑  收藏