zoukankan      html  css  js  c++  java
  • Nancy之静态文件处理

    今天我们来谈谈Nancy中的静态文件(JavaScript,CSS等)该如何处理。

    在前面的Demo中,我们也已经用到了这一块的内容,

    但并没有深入理解,只是停留在使用的层面上。

    在进入今天的正题之前,我们先来简单看看我们熟悉的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're
    11             // 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的内容可以参考

    因为它不是我们今天的主要内容,只是拿来与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 五个页面

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>index</title>
     5     <meta charset="utf-8" />
     6 </head>
     7 <body>
     8     <a href="/default">page with default convention</a><br />
     9     <a href="/custom">page with custom convention</a><br />
    10     <a href="/other">page without custom convention</a><br />
    11     <a href="/sub">page sub</a>
    12 </body>
    13 </html>
    index.html
     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>default</title>
     5     <meta charset="utf-8" />
     6     <link href="../../content/style.css" rel="stylesheet" />
     7 </head>
     8 <body>
     9    <p>这是引用 /content/sytle.css 的页面(默认的convention配置)</p>
    10 </body>
    11 </html>
    default.html
     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>custom</title>
     5     <meta charset="utf-8" />
     6     <link href="../../assets/style.css" rel="stylesheet" />
     7 </head>
     8 <body>
     9    <p>这是引用 /assets/style.css 的页面(自定义Convention配置)</p>
    10 </body>
    11 </html>
    custom.html
     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>other</title>
     5     <meta charset="utf-8" />
     6     <link href="../../other/style.css" rel="stylesheet" />
     7 </head>
     8 <body>   
     9     <p>这是引用 /other/style.css 的页面(没有Convention配置)</p>
    10 </body>
    11 </html>
    other.html
     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4     <title>sub</title>
     5     <meta charset="utf-8" />
     6     <link href="../../assets/sub/style.css" rel="stylesheet" />
     7 </head>
     8 <body>
     9    <p>这是引用 /assets/sub/style.css 的页面(自定义Convention配置,子文件夹测试)</p>
    10 </body>
    11 </html>
    sub.html

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

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

    1     public class DemoBootstrapper : DefaultNancyBootstrapper
    2     {
    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         /// <summary>
    2         /// Initializes a new instance of the <see cref="NancyConventions"/> class.
    3         /// </summary>
    4         public NancyConventions()
    5         {
    6             this.BuildDefaultConventions();
    7         }    

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

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

     1         private void BuildDefaultConventions()
     2         {
     3             var defaultConventions =
     4                 AppDomainAssemblyTypeScanner.TypesOf<IConvention>(ScanMode.OnlyNancy);
     5             this.conventions = defaultConventions
     6                 .Union(AppDomainAssemblyTypeScanner.TypesOf<IConvention>(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<Func<NancyContext, string, Response>>
    4             {
    5                 StaticContentConventionBuilder.AddDirectory("Content")
    6             };
    7         }  

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

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

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

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

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

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

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

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

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

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

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

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

    九、简单总结

    ConfigureConventions 与 BundleConfig 都是用于处理静态文件的,有相同之处,也有各自的特点。

    在项目开发过程中,我们可能会根据习惯把css、javascript这些静态文件放在自己喜欢的位置,

    但是在Nancy中这个的处理需要十分注意的是,只要我们没有将css和javascript文件放在content中时,就一定要记得在Convention中进行配置!

    否则页面死活不是我们期待的那样。。。。

    所以我个人感觉这块内容不是很友好,一旦不小心忘了配置,而且发现页面样式不对,首先想到的是不是样式的路径写错了

    而不会直接考虑到Nancy的Convention配置这一层面。

    为此,提醒各位使用Nancy的朋友,并建议各位:只要您的项目用到了静态文件,请务必要override我们的ConfigureConventions !!

  • 相关阅读:
    IOS应用内嵌cocos2dx游戏项目
    C++ 动态内存
    C++ 文件和流
    【转】SQL中的锁、脏读、不可重复的读及虚读
    【转】WCF扩展系列
    【转】WCF设置拦截器捕捉到request和reply消息
    关于拦截器模式的理解
    【转】netty源码分析之LengthFieldBasedFrameDecoder
    【转】使用nginx搭建高可用,高并发的wcf集群
    【转】Nginx 反向代理 负载均衡 虚拟主机配置
  • 原文地址:https://www.cnblogs.com/catcher1994/p/5162917.html
Copyright © 2011-2022 走看看