今日は、Nancy で静的ファイル (JavaScript、CSS など) を扱う方法について説明します。
前回のデモでは、コンテンツのこの部分も使用しました
しかし、私たちはそれを深く理解しておらず、使用するレベルにとどまりました。
今日のトピックに入る前に、使い慣れた 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 という 2 つのフォルダーがあり、それぞれ Style1.css、Style2.css、js1.js、js2.js が含まれているとします
それをバンドル管理に渡す方法を見てみましょう
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 のみを使用します。
まず具体的な使用法を見て、次にその内部実装を簡単に分析しましょう。
このアプリケーションに必要な参照を追加します
好みの方法に従って、Nancy 関連の参照を追加します
古いルール: 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 }
3. コンテンツ、アセット、その他の 3 つの新しいフォルダーを作成し、アセット フォルダーの下にスタイル シートを保存するサブ フォルダーを作成します
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;}
古いルール: ビュー フォルダー、ホーム フォルダー
index.html、default.html、custom.html、other.html、sub.html の 5 ページを追加します
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
新しい DemoBootstrapper.cs を作成し、DefaultNancyBootstrapper を継承させ、 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 の構成で構成した項目は 1 つだけです。
アセットフォルダーが処理されます。他に手動で設定する必要はありません。
ただし、コンテンツの下のスタイルは正常に表示できます。 !その他の下のものは正常に表示できません! !アセットサブフォルダsubのスタイルも正常に表示されます! !
これはあまり合理的とは思えません。
Network の内容を見ると、other の下にあるスタイル シートが正常にロードできないという単純なものではなく、直接 404 を与えていることがわかります。 ! !
それでは、さらに深く見て、ここで何が起こっているのか見てみましょう!
Nancy のソース コードのコピーをフォークし、ローカルにクローンして、何が起こるかを確認します。 (実際、上記の例は私がソースコードに追加したデモです)
まず、今日のテーマの内容を見てください。 コンベンション
名前から、今日のテーマに関連していることがわかります。静的ファイルは 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 つではないことがわかります。 !むしろ複数含まれています。ここでは静的ファイルについてのみ説明します。
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
看名字都已经知道大概实现了什么东西,一个基于某个目录,一个基于某个单独的文件。
这里需要注意一下这两个方法的参数!
还有一些其他的东西是用于拼接目录和处理Cache的。
把这几个重要的类看了一下,是不是对这个静态文件的默认配置也清晰了不少呢?
然后对自定义Convetion配置的理解也是类似的,所以这里就不再累赘了。
从"引导程序"的ConfigureConventions中可以知道,无论我们自定义多少个Convetion,
都是要添加到StaticContentsConventions这个集合中的。
ConfigureConventions 与 BundleConfig 都是用于处理静态文件的,有相同之处,也有各自的特点。
在项目开发过程中,我们可能会根据习惯把css、javascript这些静态文件放在自己喜欢的位置,
但是在Nancy中这个的处理需要十分注意的是,只要我们没有将css和javascript文件放在content中时,就一定要记得在Convention中进行配置!
否则页面死活不是我们期待的那样。。。。
所以我个人感觉这块内容不是很友好,一旦不小心忘了配置,而且发现页面样式不对,首先想到的是不是样式的路径写错了
而不会直接考虑到Nancy的Convention配置这一层面。
为此,提醒各位使用Nancy的朋友,并建议各位: 只要您的项目用到了静态文件,请务必要override我们的ConfigureConventions !!