從 .NET 程式集提供映像(二)

來源:互聯網
上載者:User
程式 目錄:
增強代碼
整理
安全性
小結
關於作者

增強代碼

代碼中首先要處理的是大小寫形式。HTTP 認為以下所有 URL 都相同,因為 URL 不區分大小寫。

<img src=http://www.163design.net/n/a/".mfr?assem=ImageServer&image=winxp.gif" />
<img src=http://www.163design.net/n/a/".mfr?assem=ImageServer&image=winxp.gif" />
<img src=http://www.163design.net/n/a/".mfr?assem=ImageServer&image=winxp.gif" />



我們的代碼目前有一個問題,由於它不保留原 HTTP 要求不區分大小寫特徵,因此必須向 LoadAndReturnImage 函數再添加一些代碼。

不區分大小寫

我們要做的是從程式集載入映像而不考慮大小寫,但由於 Assembly.GetManifestResourceStream 是區分大小寫,因此還得另想辦法。Assembly.GetManifestResourceNames() 函數將返回給定程式集內的所有資源清單,因此我們要做的就是調用此列表,與這些資源名稱進行不區分大小寫比較,然後使用尋找出的名稱:

Assembly resourceAssem = Assembly.Load ( assembly ) ;

// 尋找緩衝的名稱
string[] names = HttpContext.Current.Application [ assembly ] as string[] ;

if ( null == names )
{
// 擷取程式集內所有資源的名稱
names = resourceAssem.GetManifestResourceNames() ;
Array.Sort ( names , CaseInsensitiveComparer.Default ) ;
HttpContext.Current.Application [ assembly ] = names ;
}

// 如果此程式集記憶體在一些資源,
// 檢查所需的資源
if ( names.Length > 0 )
{
// 在名稱數組中尋找映像
int pos = Array.BinarySearch ( names , image ,
CaseInsensitiveComparer.Default ) ;

if ( pos > -1 )
WriteImage ( resourceAssem , names[pos] , true ) ;
}



這裡我載入了包含資源的程式集,然後尋找應用程式緩衝以查看該程式集內的資源清單是否已被載入和緩衝。如果沒有,我通過調用 Assembly.GetManifestResourceNames() 來讀取資源清單,然後對列表進行排序,並將其儲存在應用程式狀態中。

然後,我就可以使用 Array.BinarySearch() 方法對名稱列表執行二進位搜尋。這比按順序搜尋字串列表要快得多,且在應用程式狀態儲存資源清單所需的系統開銷也較小。

這樣就解決了區分大小寫問題,但效能如何呢?目前,每次當映像請求到達時,我們都要調用全部代碼 - 除了最小的 Web 網站之外,其餘所有的請求都可能會造成嚴重的效能問題。下一節我們將處理這個問題。

緩衝

像普通的映像和一些 ASPX 頁面一樣,把從程式集返回的映像進行緩衝是很有用的 - 因為這些映像駐留在程式集中,一般不會頻繁地更改。

如果我們在編寫一個簡單的 ASPX 頁面,則可以添加 OutputCache 指令以快取頁面面。但在我們的方案中,我們需要一種方法能夠通過編程方式將緩衝控制項標題添加到響應流中。幸運的是,在 ASP.NET 中這很容易完成。在把映像寫入輸出資料流的函數中,只需添加以下幾行:

response.Cache.SetExpires ( DateTime.Now.AddMinutes ( 60 ) ) ;
response.Cache.SetCacheability ( HttpCacheability.Public ) ;
response.Cache.VaryByParams["assem"] = true ;
response.Cache.VaryByParams["image"] = true ;
// 將映像寫入響應流...



此設定使映像在一小時(這個時間顯然可以延長以減少伺服器負載)後到期,並定義映像可以在任意位置(用戶端、Proxy 伺服器、伺服器等)進行緩衝。它還定義了更改緩衝行為的參數。現在,代碼幾乎已經完成了,但我們需要決定如何處理異常情況。

關於異常的編程

我們的代碼中可能會引發很多異常。現在,使用者的瀏覽器可能會取消連結,甚至可能仍然會遇到 ASP.NET 錯誤頁面。我們可以推測出很多種可能發生的情況。如下所示:

·程式集可能不存在。
·程式集存在但不包含任何映像。
·程式集可能不包含所請求的映像。

代碼也可能會造成其他錯誤。當找不到映像時,瀏覽器預設的響應是返回一個帶有紅十字的映像以表示一個中斷的超連結。

您當然希望用自己的預設映像來代替此映像。我已將一個預設的取消連結映像包含在 ImageServer 程式集中,當發生異常時,該映像將返回到瀏覽器。此行為可以通過在 web.config 檔案的 AppConfig 部分添加一個設定來實現。

當發生錯誤時,如果要覆蓋預設行為(返回鏈上的異常),請將以下內容添加到 web.config 中。

<appSettings>
<add key="MFRShowBrokenLink" value="true" />
</appSettings>



現在,當代碼中出現異常時,將向瀏覽器返回取消連結映像,並在追蹤記錄檔中寫入警告。




圖4:連結斷開時返回的映像


如果查看追蹤記錄檔,您會看到有關映像不存在的項,該項與下面類似。




圖5:無效映像請求的樣本追蹤記錄檔輸出


本文討論的所有代碼都可以通過本頁頂部的 MFRImages.exe 下載連結獲得。此下載包括本節完成的所有增強工作。還包括一些測試頁,通過這些測試頁可以查看使用處理常式和 ASPX 方法來呈現映像的結果。

整理

下面要添加一種方法,以返回駐留在程式集內的映像的正確 URL,然後自訂控制項編寫人員(或是您)可以調用此方法來返回映像。

如果已選擇了處理常式方法來提供映像,則您所需的函數如下。

public static string ConstructImageURL ( Assembly assembly, string image )
{
return string.Concat ( ".mfr?assem=" ,
HttpUtility.UrlEncode ( assembly.FullName.ToString ( ) ) ,
"&image=" ,
HttpUtility.UrlEncode ( image ) ) ;
}



對於這段代碼,我使用的是 string.Concat(),因為它比 string.Format() 大約快 4 倍。每個小技巧都會有所協助! 然後可以用它來設定您在自訂控制項中建立的所有映像的 ImageURL 屬性。

安全性

到目前為止的討論中,我們一直基於程式集名稱和資源名稱提供映像。這沒什麼不好,但這意味著任何人都可以得到磁碟上的程式集名稱,並可以嘗試通過將其他程式集名稱傳遞給處理常式來進行攻擊。

為了避免這個潛在的問題,最好用某種方法對返回的值進行加密。我們可以提供一些從程式集名稱和映像名稱產生的散列碼,或使用程式集名稱和映像名稱的加密格式,然後在接收到請求後再進行解密。

前一種方法(使用散列碼)需要伺服器中有尋找表,並且表中為每個提供的映像填充了內容。這就給 Web 領域帶來一個潛在的問題。在 Web 領域,可能一個伺服器提供初始映像請求(並緩衝散列碼),而另一個伺服器實際響應映像。

因此,我選擇了第二種方法,即在返回到使用者的 URL 中包含加密的程式集名稱和映像名稱。這樣就不會遇到 Web 領域中存在的問題,但卻意味著需要從瀏覽器多傳送一些資料到伺服器,因為映像 URL 要長一些。

範例程式碼包含一個類,它使用 Triple-DES(資料加密標準)演算法加密和解密字串。通常,程式集名稱和映像名稱在傳遞到用戶端之前已進行了加密。當請求映像時,這些值被解密,並調用與原來相同的代碼。

我已將這些內容以可配置的方式添加到解決方案中。在 web.config 中僅有一個標誌,如果設定為“true”,則會在向用戶端提供資源名稱時對其進行加密:

<appSettings>
<add key="MFRSecure" value="true" />
</appSettings>



在處理常式的 ProcessRequest 方法中,我對此標記進行檢查:

bool secure = false ;
string shouldSecure = ConfigurationSettings.AppSettings["MFRSecure"] ;

if ( null != shouldSecure )
secure = Convert.ToBoolean ( shouldSecure ) ;

string assembly = context.Request.QueryString["assem"] ;
string image = context.Request.QueryString["image"] ;

if ( secure )
{
assembly = Crypto.Decrypt ( assembly ) ;
image = Crypto.Decrypt ( image ) ;
}

ManifestImageLoader.RenderImage ( assembly , image ) ;



類似地,在前面介紹的 ConstructImageURL 方法中,在程式集名稱和映像名稱被傳遞給用戶端之前,我對它們進行了加密。代碼的很多部分都可以進行擴充或改進。下面是我的幾點建議。

·當無法找到資源時,配置項不對使用的映像進行寫入程式碼,而是指定映像的 URL。這樣在出現異常時,您就可以從磁碟(或從其他程式集)載入特定的映像並將其返回到瀏覽器。·映像的緩衝逾時也可以定義為配置項。
·可以擴充代碼,以允許從程式集提供任何類型的映像 - 目前,mime 類型被寫入程式碼為 image/GIF。
·對於為何此樣本中的代碼不能提供者集內的其他資源,沒有什麼原因 - 您完全可以提供 TXT 檔案、WAV 檔案等。

小結

本文介紹了兩種方法,用於從程式集檢索格式適合包含在 Web 網站中的映像。第一種方法是從 ASPX 頁面提供映像,這種方法簡單而且不需要修改 Web 服務器配置,但是提供映像的 ASPX 頁面的路徑必須正確,以使映像能夠正確顯示。

另一種方法是從自訂處理常式提供映像。這種方法克服了基於路徑的限制,但需要更改 IIS 設定資料庫,以允許由 aspnet_isapi.dll 擴充程式提供 .mfr 副檔名。而且還要為給定的應用程式修改 web.config。我個人建議使用處理常式方法而不要使用 ASPX 方法,因為在 Web 服務器中配置處理常式方法後,使用起來會更容易(而且不需要路徑)。

關於作者

Morgan 是 Microsoft 在英國工作的應用程式開發顧問,專攻 Visual C#、控制項、WinForms 和 ASP.NET。自從 2000 年發布 PDC 以來,他就從事 .NET 工作,並且非常喜歡 .NET,因此加盟該本公司。他的首頁是 http://www.morganskinner.com/,在那兒您可以找到他寫的其他一些文章的連結。在有限的閑暇時間裡,他喜歡在自家的花園中鋤鋤草,或者享受幾塊風味獨特的菜肉烘餅。


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。