一、介紹
ASP.NET Web應用程序用一種內置的方法訪問簡單的“鍵/值”配置數據。在Web.config文件中,你可以創建節來存儲簡單的“鍵/值”對。例如,新建一個ASP.NET項目,在Web.config文件中添加如下的標記作為元素的子標記:
該節包含了用兩個標記定義的“鍵/值”對,你可以通過Page對象內置的ConfigurationSettings屬性獲得它們的值。作為開始,在你的項目中新建一個名為customItems.aspx的Web窗體,將下面的代碼添加到該窗體的Page_Load事件中:
Dim aKey As String
Response.Write("
AppSettings ")
For Each aKey In ConfigurationSettings.AppSettings.Keys
Response.Output.WriteLine(aKey & "=" & _
ConfigurationSettings.AppSettings.Item(aKey))
Next
編譯運行customItems.aspx Web窗體,就能看到標記的值了。For循環檢索了節中所有的標記,并將鍵及其對應的屬性值顯示出來。這種簡單的“鍵/值”機制對于許多一般性需求來講是完美的,比如在整個應用范圍內存儲數據庫連接字符串,但對于更復雜的數據它卻不是足夠健壯。幸運的是,微軟同樣建立了創建自定義配置數據的機制,利用ASP.NET框架讀取一個或多個節,而不是僅通過某一具體應用中的代碼去讀固定的標記列表。節定義了框架預期在Web.config文件其余部分發現的標記名稱,同時聲明了處理其特定類型內容的類的類型和位置。
在解析配置文件時,ASP.NET引擎通過讀取元素的標記建立起一個可能的標記列表,其中每一個標記都包含了一個“name”和一個“type”,聲明了在文件其余內容中預期的標記名稱和相應的配置節處理程序。下面用一個小實驗來演示一下整個工作過程。在項目中Web.comfig文件末尾的標記前邊,添加一個新標記如下。
保存Web.config文件并運行項目,將會得到一個“無法識別的配置節‘customItems’”的錯誤,這個錯誤的發生是由于沒有聲明標記的節處理程序所致。但是如果瀏覽整個Web.config文件,你不會看到有任何一個標記的配置節處理程序聲明,這就帶來了一個問題,這些配置節處理程序究竟是在哪兒聲明的?(在讀這篇文章的時候,如果你同時按照上述步驟進行了操作,那么請在繼續下去之前將標記從Web.config文件中刪掉。)
事實上每一個Web應用程序都有兩個配置文件:保存在系統文件夾下的根machine.config文件和在你應用程序根目錄下的Web.config文件。你可以在操作系統文件夾下的\Microsoft.NET\Framework\\CONFIG文件夾里找到machine.config文件,其中對應于服務器上安裝并被激活的.NET框架。machine.config文件中關于配置的設置適用于在服務器上的所有應用程序,除非被局部設置所重置。瀏覽整個machine.config文件,可以看到一個包含了一組標記的標記,這些標記聲明了你能在Web.config文件中看到的那些默認標記的配置節處理程序。為了使這一過程更易于理解,可以更進一步將標記分組放在標記中,其中分別存放一組相關的節標記。
我之所以引出machine.config文件,是因為有兩種方法添加自定義標記:可以用任一種缺省的系統配置節處理程序來解析自定義標記內容,也可以創建你自己的配置節處理程序。
二、使用系統配置節處理程序解析自定義標記
1.在元素中創建一個新的標記,如下:
type="System.Configuration.NameValueSectionHandler,System, Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"
/>
作者提醒:Version和PublicKeyToken的值可能和你的.NET框架版本不同,要在系統中找出正確的值只需從任一個已存在的元素中復制即可!
2.將新建的標記放在Web.config文件中的結束標記之前進行測試,例如:
key="SomeKey" value="SomeValue" />
3.保存Web.config文件,將如下高亮部分代碼增加到customItems.aspx Web窗體中的Page_Load事件中:
Dim aKey As String
Response.Write("
AppSettings ")
For Each aKey In ConfigurationSettings.AppSettings.Keys
Response.Output.WriteLine(aKey & "=" & _
ConfigurationSettings.AppSettings.Item(aKey))
Next
Response.Write("
CustomSystemItems ")
For Each aKey In CType(ConfigurationSettings.GetConfig _
("customSystemItems"), _
System.Collections.Specialized.NameValueCollection).Keys
Response.Output.WriteLine(aKey & "=" & _
ConfigurationSettings.AppSettings.Item(aKey))
Next
4.現在再次編譯執行該Web窗體。這次,可以看到CustomSystemItem頭信息尾隨了一行“SomeKey=SomeValue”,它對應著在元素中增加的一個子元素。
通過修改machine.config文件,可以將定義好的自定義標記應用到在服務器上運行的任意Web應用程序上。但很可能你并不總是希望標記處理程序應用于所有應用程序,如果是這樣,可以在Web.config文件中增加標記和標記,而不是在machine.config文件中。測試一下,首先刪除之前在machine.config文件中定義的標記并保存,接著,在Web.config文件中緊跟著開始標記增加一個標記,并在其中置入標記。例如:
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
5.為了能夠看到變化,在web.config文件中的節再附加一個標記。
key="SomeKey" value="SomeValue" />
key="AnotherKey" value="AnotherValue" />
保存web.config文件并再次運行customItems.aspx Web窗體,可以看到有兩個值而不再只是一個。無需重新編譯應用程序即可完成測試,ASP.NET能夠立即應用新的配置。
使用這種方式可以定義任意數量的自定義標記。然而,使用普通的標記,以及“key”和“value”這種固定的屬性名稱,總顯得不是特別直觀。從可維護性方面考慮,創建可以同時控制標記和屬性名稱的自定義標記會更有效一些。
三、定義解析自定義標記的自定義配置節處理程序
假定需要定義一系列文章,每一篇都有一個標題,一個URL,沒有或有多個作者,那么如下所示的標記結構就會比泛泛的更容易維護:
url="http://www.somewhere.com/article1.aspx">
Russell Jones
url="http://www.somewhere.com/article2.aspx" />
Russell Jones
Barry Jones
增加標記及其內容(即上邊的XML段)到Web.config文件末尾的標記之前并保存。
作者提醒:先不要運行這個項目,否則會因為還沒有為節定義配置節處理程序而出錯!
為了能夠從配置文件中識別標記,必須創建相應的自定義配置節處理程序。創建自定義配置節處理程序并不難,但需要一個單獨的項目。這是因為配置節處理程序執行機制會根據程序的名稱來搜索exe文件或dll文件。我將會帶領大家用VB.NET來演示整個過程,而在本文源代碼下載中也包括功能完全相同的C#項目(譯者注:作者提供的本文相關源碼下載地址是http://www.devx.com/assets/sourcecode/6600.zip)。
新建一個類庫項目并命名為CustomItemHandler,刪除VS默認生成的類而在項目中添加一個名為CustomTagHandler的新類。自定義配置節處理程序必須實現IconfigurationSectionHandler接口,這個接口只有一個名為Create的方法,該方法接受三個參數:一個名為parent的object變量,一個HttpConfigurationContext對象變量,一個名為section的XmlNode變量。
Imports System
Imports System.Collections
Imports System.Xml
Imports System.Configuration
Public Class CustomTagHandler
Implements IConfigurationSectionHandler
Public Function Create(ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As System.Xml.XmlNode) As Object _
Implements System.Configuration. _
IConfigurationSectionHandler.Create
' Implementation here
End Class
當ASP.NET框架讀到節點時,將創建CustomTagHandler類的實例并調用它的Create方法。XmlNode參數包含了希望讀取的所有設置——在本例中也就是自定義標記及其內容。在這三個參數中,通常只用到XmlNode參數,但考慮到完備性,parent對象保存了相應父配置節的配置設置,參數configContext——HttpConfigurationContext類的實例——則主要被用來獲取Web.config文件的虛擬路徑。
你可以按照自己的意愿設置自定義配置節的內容,簡單或復雜均可。我則選擇一種比簡單“鍵/值”對要復雜一些的例子,以展示使用XML格式配置文件的可行性。
Create方法返回了一個Object對象,你可以決定你希望返回的對象類型,但因為這是在實現接口方法,所以不能改變方法的返回類型。也正因為此,調用自定義配置節處理程序的代碼必需將返回對象轉換成正確類型。
CustomTagHandler類在讀取標記中的子標記時,將一系列Article對象存入一個ArrayList中,每個Article對象有三個公共只讀的屬性,分別保存了對應文章的標題、URL和作者。注意因為每篇文章會有任意數量的作者,所以Article對象同樣使用一個ArrayList來實現作者列表。必須認識到很重要的一點是,這里并不對數據做任何處理!只需簡單地返回這些XML節點本身,然后讓調用程序提取數據即可,你可以根據任何需要,例如將作者列表作為XML節點集返回。創建的自定義配置節處理程序的重點是能夠讓你在任何需要的時候提取數據進行處理。這里給出CustomTagHandler 類和 Article類的完整代碼。
Imports System
Imports System.Collections
Imports System.Xml
Imports System.Configuration
Public Class CustomTagHandler
Implements IConfigurationSectionHandler
Public Function Create(ByVal parent As Object, _
ByVal configContext As Object, _
ByVal section As System.Xml.XmlNode) As Object _
Implements System.Configuration. _
IConfigurationSectionHandler.Create
Dim NArticle, NAuthor As XmlNode
Dim articleNodes, authorNodes As XmlNodeList
Dim authors As ArrayList
Dim aTitle As String
Dim aURL As String
Dim articles As New ArrayList()
articleNodes = section.SelectNodes("article")
For Each NArticle In articleNodes
aTitle = NArticle.Attributes.GetNamedItem("title").Value
aURL = NArticle.Attributes.GetNamedItem("url").Value
authors = New ArrayList()
authorNodes = NArticle.SelectNodes("authors//author")
If Not authorNodes Is Nothing Then
For Each NAuthor In authorNodes
authors.Add(NAuthor.InnerText)
Next
End If
articles.Add(New Article(aTitle, aURL, authors))
Next
Return articles
End Function
End Class
Public Class Article
Private m_title, m_url As String
Private m_authors As ArrayList
Public Sub New
(ByVal aTitle As String, ByVal aURL As String, ByVal authors As ArrayList)
m_title = aTitle
m_url = aURL
m_authors = authors
End Sub
Public ReadOnly Property Title() As String
Get
Return m_title
End Get
End Property
Public ReadOnly Property URL() As String
Get
Return m_url
End Get
End Property
Public ReadOnly Property Authors() As ArrayList
Get
Return m_authors
End Get
End Property
End Class
四、使用自定義配置節處理程序
現在可以對CustomItemHandler類進行測試了。首先,確定代碼編譯無誤。為了能夠測試這個類,還需要增加一個標記以聲明處理標記的自定義配置節處理程序。現在回到在文章開始時創建的ASP.NET項目中,添加引用之前編譯CustomItemHandler項目所生成的CustomItemHandler.dll文件。具體操作是,在解決方案資源管理器窗口中右鍵單擊“引用”并選擇“添加引用”,在彈出窗口中選擇“.NET”標簽并單擊“瀏覽”按鈕,在CustomItemHandler項目中的bin子文件夾中可以找到該DLL文件。
接下來,對Web.config文件再做一次修改。在早先創建的標記中添加一個新的標記,設置name屬性為“articlesVB”,設置type屬性為之前創建的配置節處理程序的類名和程序集(assembly)名稱(譯者注:也就是相應類庫dll文件的名稱)。至此,節應該類似如下所示(版本號可能會有所不同):
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
type="CustomItemHandler.CustomTagHandler,
CustomItemHandler"/>
警告:Web.config本身是XML文件,因此是區分大小寫的!請確保屬性值同標記、程序集(assembly)和類的名稱都是匹配的。
把如下代碼添加到customItems.aspx Web窗體中,以獲取文章信息并將標題顯示為超鏈接:
Dim articles As ArrayList
Dim anArticleVB As CustomItemHandler.Article
Dim o as Object
Dim s As String
Response.Write("
ArticlesVB ")
articles = CType(System.Configuration. _
ConfigurationSettings.GetConfig _
("articlesVB"), ArrayList)
If Not articles Is Nothing Then
For Each o In articles
anArticleVB = CType(o,
CustomItemHandler.Article)
Response.Output.WriteLine _
("
"""" & ">" & anArticleVB.Title & _
"")
If Not anArticleVB.Authors Is Nothing Then
s = "by "
For Each obj In anArticleVB.Authors
s += CType(obj, String) & ", "
Next
Response.Output.WriteLine _
(s.Substring(0, s.Length - 2))
End If
Next
End If
最后,編譯并運行customItems.aspx Web窗體,可以看到尾隨著一列文章信息的“ArticlesVB”標題(如圖二所示),這些信息都是在Web.config文件的節中定義的。
你可以按照本文所給的步驟,為能夠存儲在配置文件中的任何類型的信息構建配置節處理程序。我們已經知道了如何使用內建的節來讀取一般的“鍵/值”設置,如何使用系統定義的配置節處理程序來讀取自定義節中的系統定義屬性值,以及如何創建并聲明自定義配置節處理程序。當希望自定義節應用于某特定服務器上的所有ASP.NET應用程序時,自定義配置節處理程序可以放在machine.config文件中,而希望自定義節只應用于一個應用程序時,則可以放在Web.config文件中。
本文作者:A. Russell Jones
文章來源:http://www.devx.com/dotnet/Article/16927/0/page/1
|