利用WebResource.axd通過一個URL來訪問裝配件的內置資源

 本文英文原版及代碼下載:
http://aspnet.4guysfromrolla.com/articles/080906-1.aspx

利用WebResource.axd通過一個URL來訪問裝配件的內置資源

導言:

很多ASP.NET server控件都需要另外的外部資源來實現某些功能.比如,使用任何一個ASP.NET validation驗證控件時,都需要一系列的JavaScript functions來執行它們的客戶端驗證.雖然可以在頁面上添加這些JavaScript functions,不過更高效的方法是將這些函數封裝在一個外部的JavaScript文件裏,然後在頁面通過<script src="PathToExternalJavaScriptFile" type="text/javascript" >的形式來將該文件包含在頁面裏.這樣一來不僅可以實現對頁面的瘦身,還可以允許瀏覽器對該JavaScript文件施行緩存(這樣就不用每個頁面在登錄/回傳時向瀏覽器發送該JavaScript代碼了)

在ASP.NET 2.0之前,用戶瀏覽器要訪問這種外部資源的話,我們必須將它們作爲具體的文件放在文件系統裏.如果你使用ASP.NET 1.x的驗證控件的話,你的頁面必須添加一個對JavaScript文件的引用,如/aspnet_client/system_web/version/WebUIValidation.js.這些外部文件有礙最後的部署.

爲解決這個問題,ASP.NET 2.0允許將外部資源植入控件的裝配件裏,通過一個指定的URL對其訪問.將外部images, JavaScript files,CSS files植入控件的裝配件後,部署就容易了,因爲所有的資源都包含在.dll文件裏了. 完成植入操作後,在ASP.NET 2.0頁面裏我們可以通過一個指定的URL(WebResource.axd)來實現對這些資源的訪問.

本文我們探討如何將外部資源植入裝配件以及如何通過一個指定的URL來對其訪問,該技術簡化了安裝和部署.

一個Custom Control示例...

爲了考察ASP.NET 2.0裏的外部資源特性,我們需要構建一個包含外部資源的自定義控件.就本文而言,我將創建一個很簡單的控件來對TextBox控件的基本函數進行擴充.該控件—FunkyTextBox,在其客戶端的onkeypress event事件裏,用一個color數組裏定義的顏色隨機的改變TextBox的底色.

該行爲需要一些客戶端腳本:首先,我們要添加一個函數來獲取一個隨機數,然後根據該隨機數設置TextBox的背景顏色.第二,我們要定義要用到的color數組.我們可以輕而易舉的繞開外部文件,直接向頁面注入要用到的JavaScript.下面的代碼顯示了FunkyTextBox控件的完整代碼(爲簡化起見,using聲明、命名空間、以及定義好的colors數組都省略掉了)

public class FunkyTextBox : TextBox
{
    protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
    {
        // Wire up the onkeypress event handler to the ChangeBackgroundColor() JavaScript function
        writer.AddAttribute("onkeypress", "ChangeBackgroundColor(this);");

        base.AddAttributesToRender(writer);
    }


    protected override void OnPreRender(EventArgs e)
    {
        // Dump in the JavaScript directly into the page
        // (Although the external JavaScript approach is more efficient)
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "FunkyTextBox",
@"
function ChangeBackgroundColor(ctrl)
{
  var rndNum = Math.floor(Math.random() * 256);
  if (ctrl && funkyTextBoxColors.length > rndNum)
    ctrl.style.backgroundColor = funkyTextBoxColors[rndNum];
}

var funkyTextBoxColors =  new Array('#89C142', '#EF14E5', '#75762C', '#BB9E24', '#BF4A44', '#9D4A77', ...);
", true);

        base.OnPreRender(e);
    }
}

該server control繼承自ASP.NET的TextBox,重寫了2個方法.第一,在AddAttributesToRender方法裏,添加了一個客戶端特性(client-side attribute),那麼任何時候,當用戶在textbox控件裏鍵入字符時,就會調用名爲ChangeBackgroundColor的JavaScript function,傳入對該textbox的引用.第二, 在FunkyTextBox的PreRender event事件裏,通過 Page.ClientScript class's RegisterScriptBlock method方法直接將所需要的JavaScript注入到頁面裏.具體來說,定義了ChangeBackgroundColor function和funkyTextBoxColor數組,而ChangeBackgroundColor function獲取一個隨機值,再根據該值用funkyTextBoxColor數組裏對應的顏色來設置背景色.

當把FunkyTextBox添加到一個ASP.NET頁面後,最終頁面將包含如下的代碼:

<script type="text/javascript">
<!--

function ChangeBackgroundColor(ctrl)
{
    var rndNum = Math.floor(Math.random() * 256);
    if (ctrl && funkyTextBoxColors.length > rndNum)
        ctrl.style.backgroundColor = funkyTextBoxColors[rndNum];
}

var funkyTextBoxColors =  new Array('#89C142', '#EF14E5', '#75762C', '#BB9E24', '#BF4A44', '#9D4A77', ...);
// -->
</script>


Here is a FunkyTextBox:
<input οnkeypress="ChangeBackgroundColor(this);" name="MyTextBox" type="text" id="MyTextBox" />

通過OnPreRender method方法將JavaScript注入到頁面,而FunkyTextBox控件呈現爲一個 <input type="text">標記,其onkeypress event事件調用ChangeBackgroundColor function函數.

將JavaScript轉移到一個外部文件以對頁面瘦身

該FunkyTextBox控件使用的JavaScript很簡單,稍微複雜點的控件爲實現其功能所需的JavaScript遠不止這麼多.直接將JavaScript植入頁面將增大頁面的size,也會讓用戶花更多的時間加載頁面. 爲了對頁面瘦身,應將JavaScript轉移到一個外部文件裏,再在頁面裏添加一個<script>標籤,以實現對JavaScript file的引用,比如:

<script src="PathToExternalJavaScriptFile" type="text/javascript" >

用<script>元素來替換JavaScript就達到了對頁面瘦身的目的.此外,如果瀏覽器對外部文件實施緩存的話,那麼我們就只需要下載一次就可以了(如果直接將JavaScript植入頁面的話,每個頁面每次登陸/加載時都要進行加載)

在ASP.NET 1.x裏,對這些外部資源文件——JavaScript文件、CSS classes, images等,都需要與custom control一起加載和展開.在ASP.NET 2.0裏我們可以將這些外部資源植入該控件的裝配件,再通過一個指定的URL實現對這些資源的訪問.

將外部文件植入控件的Assembly

要將資源植入控件的裝配件,我們需要在Visual Studio裏把資源添加到你的server control project裏(本文結尾處可下載的代碼裏,包含了FunkyTextBox Web control Project,以及一個test website).對FunkyTextBox控件來說,我添加了一個名爲Funky.js的文件,它包含的JavaScript就是我們在前面的OnPreRender方法向頁面注入的那個JavaScript..

完成添加後,在Solution Explorer裏選中它並打開Properties窗口,將Build Action設置爲"Embedded Resource", 如下圖:

這樣一來,一旦你生成解決方案時,該文件就會被植入最終的assembly裏.

通過一個URL來訪問Embedded Assembly


對這些內置資源,我們可以通過WebResource.axd HTTP Handler來進行訪問。通過一個URL,比如http://yoursite/WebResource.axd?d=assemblyKey&t=dateTimeOfLastAssemblyWrite, 其中,assemblyKey是要訪問的裝配件的名稱的加密處理後的string, 而dateTimeOfLastAssemblyWrite描述了該裝配件最後一次被修改的日期.給定一個有效的assemblyKey,那麼WebResource.axd HTTP Handler就可以返回內置資源的內容.

使用WebResource.axd HTTP Handler,我們要面臨3個問題:

1.通過WebResource.axd HTTP Handler,使一個內置資源允許被訪問.
2.向WebResource.axd HTTP Handler傳遞準確的querystring值,以便檢索某個特定的內置資源
3.將第2步生成的URL放置在ASP.NET頁面恰當的位置

默認情況下是不允許WebResource.axd HTTP Handler對裝配件裏的內置資源進行訪問的,爲重寫該行爲,我們必須向server control project的AssemblyInfo文件添加一個特性(attribute),具體來說,要添加一個WebResource特性,比如:

[assembly: WebResource(webResource, contentType, performSubstitution)] 

注意:如果你使用的是Visual Basic,那麼你需要用“<”和“>”來限定裝配件,比如<assembly: WebResource(...)>.要看該AssemblyInfo文件的話,在Solution Explorer裏選"Show All Files",它出現在 "My Project"文件夾下;再者,WebResource特性位於System.Web.UI命名空間,因此我們要在AssemblyInfo.cs文件頂端添加using System.Web.UI聲明(如果是VB的話,用Imports System.Web.UI).

其中webResource參數指定了要訪問的資源的名稱,其命名模式爲:RootNamespace.PathToFile.對本文示例而言,根命名空間爲FunkyTextBox;又因資源文件在工程的根目錄下,那麼PathToFile就是Funky.js(假如Funky.js位於根目錄的Scripts文件夾,那麼PathToFile值就變成了Scripts.Funky.js).因此,webResource參數的值就爲FunkyTextBox.Funky.js.

而contentType參數指定了要檢索的資源的MIME type.當查詢一個外部資源時,瀏覽器單獨向服務器發出一個HTTP request.而MIME type就告知瀏覽器要返回的數據的類型.對JavaScript文件而言,其對應的contentType類型爲text/javascript,有關MIME Media Types的更多信息,請參閱官方的MIME types清單.

最後,performSubstitution是一個可選的布爾值,用於指明該資源是否可以被其它的外部資源引用.比如,你可能將image文件和一個JavaScript文件植入到了裝配件裏,而該腳本文件可能需要引用某些image資源.如果確實需要的話,就將performSubstitution參數設爲True.

對本文用到的控件而言,我們用如下的attribute聲明來對Funky.js外部文件註冊:

[assembly: WebResource("FunkyTextBox.Funky.js", "text/javascript")]

對資源進行註冊後,我們就可以用WebResource.axd HTTP Handler來對其進行訪問了.剩下的工作就是寫代碼來生成該外部資源對應的相應URL.

爲此,我們使用ClientScriptManager class類裏的GetWebResourceUrl(type, webResource) method方法.其中type參數就是該控件的類型,

webResource參數就是前面的WebResource特性裏使用的webResource的值. 比如,要獲取一個從該server control裏訪問內置的Funky.js資源的URL,我這樣實現:

Page.ClientScript.GetWebResourceUrl(this.GetType(), "FunkyTextBox.Funky.js")

另外,我們在FunkyTextBox控件的OnPreRender事件裏,將RegisterClientScriptInclude 方法和GetWebResourceUrl方法搭配使用,將相應的JavaScript包含進來(<script src="PathToExternalJavaScriptFile" type="text/javascript" >),如下:

protected override void OnPreRender(EventArgs e)
{
    // When pre-rendering, add in external JavaScript file
    Page.ClientScript.RegisterClientScriptInclude("FunkyJavaScript",
                 Page.ClientScript.GetWebResourceUrl(this.GetType(),
                                             "FunkyTextBox.Funky.js"));

    base.OnPreRender(e);
}

通過這個重寫的OnPreRender方法,控件將向頁面添加如下的標記:

<script src="/TestWebsite/WebResource.axd?d=NLu6bm6a2XinJZt4M-ujmQ13X5ALig6NEAZa1-AxV0HCbE3M-

VHNomDQt_qnxjdT0&t=632902136868023078" type="text/javascript"></script>

Here is a FunkyTextBox:
<input οnkeypress="ChangeBackgroundColor(this);" name="MyTextBox" type="text" id="MyTextBox" />

這樣就將JavaScript引進來了.WebResource.aspx HTTP Handler獲取該內置資源並將其發送回客戶端.

結語

本文我們考察瞭如何將資源植入一個自定義ASP.NET server control的裝配件裏,以及如何通過一個URL來訪問這些資源.這是ASP.NET 2.0裏的新技術,便於開發者將外部資源植入裝配件.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章