我们先来简单看看我们熟悉的ASP.NET MVC中是如何管理我们项目中的这些静态文件呢?

其实当我们新建一个MVC的项目时,已经生成了一个“模板”让我们参考,

这个“模板”就是App_Start下面的 BundleConfig.cs

 1     public class BundleConfig 2     { 3         // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 4         public static void RegisterBundles(BundleCollection bundles) 5         { 6             bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 7                         "~/Scripts/jquery-{version}.js")); 8             bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 9                         "~/Scripts/jquery.validate*"));10             // Use the development version of Modernizr to develop with and learn from. Then, when you're11             // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.12             bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(13                         "~/Scripts/modernizr-*"));14             bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(15                       "~/Scripts/bootstrap.js",16                       "~/Scripts/respond.js"));17             bundles.Add(new StyleBundle("~/Content/css").Include(18                       "~/Content/bootstrap.css",19                       "~/Content/site.css"));20         }21     }

其中的ScriptBundle和StyleBundle分别是用于管理js和css的类,这两个类都是继承了Bundle这个类!

它位于System.Web.Optimization程序集,如果想要用这个功能,记得添加引用喔!

那我们要怎么使用这个呢?

现在假设在根目录下面有css和js两个文件夹,里面分别存放着Style1.css、Style2.css和js1.js、js2.js

下面就来看看怎么把它交于Bundle管理

1      bundles.Add(new ScriptBundle("~/bundles/js").Include(2                     "~/js/js1.js",3                     "~/js/js2.js"));4       bundles.Add(new StyleBundle("~/bundles/css").Include(5                     "~/css/Style1.css",6                     "~/css/Style2.css"));

 其中的“~/bundles/js”和"~/bundles/css"是虚拟路径!

 然后就是在页面中使用(就是用我们刚才的虚拟路径)

1  @Styles.Render("~/bundles/css")2  @Scripts.Render("~/bundles/js")

是不是很方便呢!更多关于Bundle的内容可以参考

http://www.asp.net/mvc/overview/performance/bundling-and-minification

因为它不是我们今天的主要内容,只是拿来与Nancy中的静态文件处理形成对比,便于我们的理解。

下面就来看看Nancy中的静态文件怎么处理。

为了演示的方便,这里仅使用css。

先看看具体的使用,然后再简单分析其内部的实现。

一、新建一个空的asp.net应用程序

在这个应用程序中添加我们需要的引用,这里可以根据前面介绍的,

按自己喜欢的方式、方法来添加Nancy相关的引用

二、建立Modules

老规矩:Modules文件夹、HomeModule.cs

 1     public class HomeModule : NancyModule 2     { 3         public HomeModule() 4         { 5             Get["/"] = _ => 6             { 7                   return View["index"]; 8             }; 9 10             Get["/default"] = _ =>11             {12                 return View["default"];13             };14 15             Get["/custom"] = _ =>16             {17                 return View["custom"];18             };19 20             Get["/other"] = _ =>21             {22                 return View["other"];23             };24 25             Get["/sub"] = _ =>26             {27                 return View["sub"];28             };29         }30     }

三、新建content、assets、other三个文件夹,以及在assets文件夹下面新建一个sub文件夹用于存放样式表

四、分别添加一些简单的样式在这些文件夹中

content下面的sytle.css内容如下

1 body {background-color:#00ffff;}2 p {font-size:xx-large; }

assets和other下面的style.css内容如下

1 body {background-color:#00ffff;}2 p {font-size:xx-large;color:#ff0000;}

assets/sub下面 的style.css内容如下

1 body {background-color:#808080;}2 p {font-size:xx-large;color:#ff0000;}

五、添加Views

老规矩:Views文件夹、Home文件夹

添加 index.html、default.html、custom.html、other.html、sub.html 五个页面

 index.html

 default.html

 custom.html

 other.html

 sub.html

六、在"引导程序"中配置Convention(至关重要的一步)

新建DemoBootstrapper.cs,使其继承DefaultNancyBootstrapper并且override我们的ConfigureConventions

1     public class DemoBootstrapper : DefaultNancyBootstrapper2     {3         protected override void ConfigureConventions(NancyConventions nancyConventions)4         {5             base.ConfigureConventions(nancyConventions);6             nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("assets"));7         }8     }

七、运行结果

八、结果分析与探讨

1、default.html 用的样式是在content下面的,能正常加载样式!

2、custom.html用的样式是在assets下面的,能正常加载样式!

3、other.html用的样式是在other下面的,不能正常加载样式!!

4、sub.html用的样式是在assets/sub下面的,能正常加载样式!

很明显,结果有点出乎我们的意料,我们在Convetion的配置中,只配置了一项!

就是对assets文件夹进行了处理。其他都没有手动配置!

但是在content下面的样式是能够正常显示的!!而other下面的是不能正常显示的!!assets的子文件夹sub的样式也正常显示!!

这个给人貌似不是很合理的感觉。

看看Network的内容会发现other下面的样式表不是不能正常加载那么简单,而是直接给个404!!!

 

那我们就深入的去看看这里面到底发生了什么事吧!

fork一份Nancy的源码,clone到本地,来看看个所以然。(其实上面的例子我就是在源码上面添加的一个Demo)

首先看看我们今天的主题Conventions下面的东西

其中从名字就可以看出跟我们今天的主题静态文件,相关的就有7个!!

但这并不是我们的出发点,我们的出发点是下面这个!

1     protected override void ConfigureConventions(NancyConventions nancyConventions)2         {3             base.ConfigureConventions(nancyConventions);4             nancyConventions.StaticContentsConventions.Add(StaticContentConventionBuilder.AddDirectory("assets"));5         }

 

Convention的配置指引着我们要先去看看NancyConvetions这个类

在其构造方法中调用了 BuildDefaultConventions 这个方法

1         /// 2         /// Initializes a new instance of the  class.3         /// 4         public NancyConventions()5         {6             this.BuildDefaultConventions();7         }

这就很明显的告诉我们,无论如何,它都会有默认的Conventions!!而且看了里面的实现

会发现,默认的Convention还不仅仅是一个!!而是包含多个。这里我们仅探讨关于静态文件的。

 1         private void BuildDefaultConventions() 2         { 3             var defaultConventions = 4                 AppDomainAssemblyTypeScanner.TypesOf(ScanMode.OnlyNancy); 5             this.conventions = defaultConventions 6                 .Union(AppDomainAssemblyTypeScanner.TypesOf(ScanMode.ExcludeNancy)) 7                 .Select(t => (IConvention)Activator.CreateInstance(t)); 8             foreach (var convention in this.conventions) 9             {10                 convention.Initialise(this);11             }12         }

现在我们就该去找关于静态文件的默认Convetion

发现刚才的7个相关中,有一个DefaultStaticContentsConventions

它实现了IConvention接口(Nancy中基本都是接口化编程,很Nice!!)。

其中的初始化方法中

1         public void Initialise(NancyConventions conventions)2         {3             conventions.StaticContentsConventions = new List>4             {5                 StaticContentConventionBuilder.AddDirectory("Content")6             };7         }

是不是跟我们自定义配置几乎相差无几!!我想看到AddDirectory的参数"Content",大家也应该都知道了

为什么我们的content下面的样式,没有配置都能正常加载(我去,它默认都是content,能不正常加载么。。)

里面的StaticContentConventionBuilder又是何方神圣呢?

这个是静态基于目录的帮助类

里面有两个主要的方法 AddDirectory和AddFile ,都是返回Func类型的东东。

看名字都已经知道大概实现了什么东西,一个基于某个目录,一个基于某个单独的文件。

这里需要注意一下这两个方法的参数!

还有一些其他的东西是用于拼接目录和处理Cache的。

把这几个重要的类看了一下,是不是对这个静态文件的默认配置也清晰了不少呢?

然后对自定义Convetion配置的理解也是类似的,所以这里就不再累赘了。

从"引导程序"的ConfigureConventions中可以知道,无论我们自定义多少个Convetion,

都是要添加到StaticContentsConventions这个集合中的。