當我們在做一個網站時,可能經常會有這樣一個需求,要給我們做的網站添加一個自定義的圖示。
在Nancy中,預設是的下面這樣

一個妹子的頭像,其實也是挺好看的!!
那麼當我們想要替換這個預設的,應該要怎麼做呢?
下面就來看看具體的實作
首先,準備一張名為 favicon.ico或 favicon.png 圖檔
這裡有兩種實作方法提供參考
方法一:替換預設的圖示(IRootPathProvider的實作)
如果我們是使用預設的IRootPathProvider的實作,這個時候,我們直接添加圖檔在我們的項目根目錄即可
Nancy會去搜尋這個預設的RootPath的favicon資源,它找到的第一個就将會是我們網站的圖示。
效果如下:
有時候,預設的不一定是最好的,是以我們可以
自己去實作IRootPathProvider這個接口,但一個項目中,隻能有一個實作(除了預設的)
具體如下
1 public class CustomRootPathProvider : IRootPathProvider
2 {
3 public string GetRootPath()
4 {
5 return AppDomain.CurrentDomain.GetData(".appPath").ToString();
6 }
7 }
其中,GetRootPath傳回的是絕對路徑!!
這個路徑可以用你能想到的任何方式得到!
然後,我們需要在“引導程式”中做點事
1 protected override IRootPathProvider RootPathProvider
2 {
3 get { return new CustomRootPathProvider(); }
4 }
這樣做是比較保險的一種做法(不需要特地将我們的圖檔資源設定為嵌入的資源)
方法二:使用嵌入的圖示(Override FavIcon)
這種方法需要我們去重寫 FacIcon這個方法
1 protected override byte[] FavIcon
2 {
3 get { return this.favicon ?? (this.favicon = LoadFavIcon()); }
4 }
5 private byte[] LoadFavIcon()
6 {
7 using (var resourceStream = GetType().Assembly.GetManifestResourceStream("NancyFavIconDemo.favicon.ico"))
8 {
9 var tempFavicon = new byte[resourceStream.Length];
10 resourceStream.Read(tempFavicon, 0, (int)resourceStream.Length);
11 return tempFavicon;
12 }
13 }
其中,GetMainifestResourceStream的參數是“程式集名稱.資源名稱”(NancyFavIconDemo是我這個Demo的程式集名稱,favicon.ico是我在根目錄的一個圖檔)
還有重要的一步是
将我們的圖檔屬性中的Build Action設定為 Embedded Resource(嵌入的資源)
具體原因我們可以參考
Assembly.GetManifestResourceStream Method (String)裡面的Remark
A manifest resource is a resource (such as an image file) that is embedded in the assembly at compile time.
此時,我們同樣可以看到相同的效果
如果 我們沒有設定為嵌入的資源,那麼我們的resourceStream對象将一直為空
下面我們來看看Nancy這一塊内容的内部實作
關于favicon的實作就是在FavIconApplicationStartup.cs裡面
來看看它的描述
就像前面說的,它會去找favicon,找到就用找到的,沒找到就用預設的。
裡面有一個帶IRootPathProvider參數構造函數,可以簡單了解為指定要搜尋的範圍。
1 /// <summary>
2 /// Initializes a new instance of the <see cref="FavIconApplicationStartup"/> class, with the
3 /// provided <see cref="IRootPathProvider"/> instance.
4 /// </summary>
5 /// <param name="rootPathProvider">The <see cref="IRootPathProvider"/> that should be used to scan for a favicon.</param>
6 public FavIconApplicationStartup(IRootPathProvider rootPathProvider)
7 {
8 FavIconApplicationStartup.rootPathProvider = rootPathProvider;
9 }
下面是預設的圖示實作方法,我們override的實作和它的基本一緻!!
1 private static byte[] ExtractDefaultIcon()
2 {
3 var resourceStream =
4 typeof(INancyEngine).Assembly.GetManifestResourceStream("Nancy.favicon.ico");
5
6 if (resourceStream == null)
7 {
8 return null;
9 }
10
11 var result =
12 new byte[resourceStream.Length];
13
14 resourceStream.Read(result, 0, (int)resourceStream.Length);
15
16 return result;
17 }
預設圖示在ErrorPipeline.cs和FormatterExtensions.cs之間(不細心去看,壓根就看不見)
裡面還有一個“搜尋”圖示的方法
1 private static byte[] LocateIconOnFileSystem()
2 {
3 if (rootPathProvider == null)
4 {
5 return null;
6 }
7
8 var extensions = new[] { "ico", "png" };
9
10 var locatedFavIcon = extensions.SelectMany(EnumerateFiles).FirstOrDefault();
11 if (locatedFavIcon == null)
12 {
13 return null;
14 }
15
16 try
17 {
18 return File.ReadAllBytes(locatedFavIcon);
19 }
20 catch (Exception e)
21 {
22 if (!StaticConfiguration.DisableErrorTraces)
23 {
24 throw new InvalidDataException("Unable to load favicon", e);
25 }
26
27 return null;
28 }
29 }
我們可以發現,我們用的字尾可以是.ico和.png。