ASP.NET 提供了一個讓使用者輕鬆自訂客製化頁面的功能 - Web Parts
但是預設必須使用SQLExpress 或 SQL Server資料庫來儲存使用者的設定檔
對於不想大費周張開欄位使用資料庫儲存的人來說實在是很麻煩...
如果能夠使用一般的XML檔案來儲存使用者個人化資訊或許會是更方便的選擇。
稍微搜尋看了一些文章發現,其實 Web Part 是依賴.Net的 Personalization 個人化機制來儲存資訊
所以只要自己實做一個 PersonalizationProvider,想要把資訊存成任何格式都可以。
關於 Web Parts 的架構可以參考 聖殿祭司的文章 裡面說的很詳細
本篇文章的範例會將使用者的個人化資訊序列化之後,存在XML檔案中。
在微軟的 OpenSource 網站 CodePlex 中,找到了一個名為 ASP.NET XmlProvider Library 的 Project
剛好符合我想要用XML來儲存的需求,於是我引用了此Project中的 XmlProviders.dll 與 XmlProviders.XmlSerializers.dll
並且繼承改寫 XmlProviders.XmlPersonalizationProvider 來達成我的需求。
本文章因為只使用到 XmlPersonalizationProvider 的功能,ASP.NET XmlProvider Library 中的其他功能便不多加解釋,
有興趣請自行參考 ASP.NET XmlProvider Library 的 Source Code。
本文章範例將使用小弟比較熟的VB語法,看不習慣的人請自行 轉換
首先開啟 ASP.NET XmlProvider Library Project
從 ASP.NET XmlProvider Library 的 web.config 設定中我們可以看出,XmlPersonalizationProvider 會將瀏覽網頁的個人化資訊存到網站的 App_Data 目錄底下的 MyApp_Personalization.xml 中。
02 <personalization defaultProvider="XmlProvider">
03 <providers>
04 <clear/>
05 <add name="XmlProvider"
06 type="XmlProviders.XmlPersonalizationProvider"
07 dataStorePath="App_Data" applicationName="MyApp"/>
08 </providers>
09 </personalization>
10 </webParts>
11
大家有沒有發現一個奇怪的地方... 如此一來,不管網站中有多少個使用者在瀏覽和編排 Web Parts 版面,全部都會儲存到同樣一份Xml檔案。
不就失去 Web Parts 個人化的意義了嗎?
於是我們直接檢視 XmlPersonalizationProvider 的 SourceCode,
發現可以直接複寫其中的 LoadPersonalizationBlobs. ResetPersonalizationBlob. SavePersonalizationBlob 方法,以及
並且新增 UserID 以及 StoreFilePath 屬性,就可以讓 XmlPersonalizationProvider 在讀取.儲存.和重載個人化檔案時,
都可以直接使用每個特定UserID資料夾中的Xml檔。
02 Inherits XmlProviders.XmlPersonalizationProvider
03
04 Private FUserID As String
05 Private FStoreFilePath As String
06
07 ''' <summary>
08 ''' 使用者ID。
09 ''' </summary>
10 Public Property UserID() Property UserID() As String
11 Get
12 Return FUserID
13 End Get
14 Set(ByVal value As String)
15 FUserID = value
16 End Set
17 End Property
18
19 ''' <summary>
20 ''' 檔案儲存路徑。
21 ''' </summary>
22 Public ReadOnly Property StoreFilePath() ReadOnly Property StoreFilePath() As String
23 Get
24 Dim path As String
25
26 If HttpContext.Current IsNot Nothing Then
27 path = HttpContext.Current.Server.MapPath(DataStorePath)
28 Else
29 path = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath
30 Dim dataStorePath As String = Me.DataStorePath.Replace("~/", String.Empty)
31 path = System.IO.Path.Combine(path, dataStorePath)
32 End If
33 '存放於App_Data\UserData\ 目錄之下
34 path += "\UserData\" & Me.UserID & "\"
35 Return System.IO.Path.Combine(path, String.Format("{0}_Personalization.xml", UserID))
36 End Get
37 End Property
38
39
40 Protected Overrides Sub LoadPersonalizationBlobs() Overrides Sub LoadPersonalizationBlobs(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String, ByRef sharedDataBlob As Byte(), ByRef userDataBlob As Byte())
41 '設定 UserID 等於 TWebPartManager 的 UserID 屬性
42 Me.UserID = CType(webPartManager, TWebPartManager).UserID
43
44 Dim spaces As WorkspaceCollection = WorkspaceCollection.Load(StoreFilePath)
45 If spaces.SharedPersonalizationBlob IsNot Nothing Then
46 sharedDataBlob = spaces.SharedPersonalizationBlob
47 End If
48
49 Dim space As Workspace = spaces.FindByUserAndPath(userName, path)
50 If space IsNot Nothing AndAlso space.PersonalizationBlob IsNot Nothing Then
51 userDataBlob = space.PersonalizationBlob
52 End If
53 End Sub
54
55
56 Protected Overrides Sub ResetPersonalizationBlob() Overrides Sub ResetPersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String)
57 '設定 UserID 等於 TWebPartManager 的 UserID 屬性
58 Me.UserID = CType(webPartManager, TWebPartManager).UserID
59
60 Dim spaces As WorkspaceCollection = WorkspaceCollection.Load(StoreFilePath)
61 Dim space As Workspace = spaces.FindByUserAndPath(userName, path)
62
63 If space IsNot Nothing Then
64 spaces.Workspaces.Remove(space)
65 spaces.Save(StoreFilePath)
66 End If
67 End Sub
68
69
70 Protected Overrides Sub SavePersonalizationBlob() Overrides Sub SavePersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String, ByVal dataBlob As Byte())
71 '設定 UserID 等於 TWebPartManager 的 UserID 屬性
72 Me.UserID = CType(webPartManager, TWebPartManager).UserID
73
74 Dim spaces As WorkspaceCollection = WorkspaceCollection.Load(StoreFilePath)
75
76 If Not [String].IsNullOrEmpty(userName) Then
77 Dim space As Workspace = spaces.FindByUserAndPath(userName, path)
78
79 If space Is Nothing Then
80 space = New Workspace()
81 space.Path = path
82 space.UserName = userName
83 spaces.Workspaces.Add(space)
84 End If
85
86 space.PersonalizationBlob = dataBlob
87 Else
88 spaces.SharedPersonalizationBlob = dataBlob
89 End If
90
91 spaces.Save(StoreFilePath)
92 End Sub
93 End Class
另外為了讓頁面可以更方便的直接設定 UserID,我們可以將.Net 原本的 WebPartManager 控制項繼承下來,並且只簡單的加了一個 UserID 屬性。
02 Imports System.Web.UI.WebControls.WebParts
03
04 Namespace WebControls
05
06 Public Class TWebPartManager
07 Inherits Microsoft.Web.Preview.UI.Controls.WebParts.WebPartManager
08
09 Private FUserID As String
10
11 ''' <summary>
12 ''' 對應儲存 WebParts 資訊的使用者帳號名稱。
13 ''' </summary>
14 Public Property UserID() Property UserID() As String
15 Get
16 Return FUserID
17 End Get
18 Set(ByVal value As String)
19 FUserID = value
20 End Set
21 End Property
22
23 End Class
24
25 End Namespace
最後只要在放置 Web Parts 頁面事件中,將當下登入的使用者ID,設定給繼承下來的 TWebPartManager 控制項,即可正常運行。
2 Me.TWebPartManager1.UserID = Me.Session("UserID")
3 End Sub
不知道各位有沒有發現到 TWebPartManager 控制項 所繼承的是 Microsoft.Web.Preview.UI.Controls.WebParts.WebPartManager
而不是原本的 System.Web.UI.WebControls.WebParts.WebPartManager,為什麼會有 NameSpace 上的差異呢?
主要是因為 Web Parts 控制項在原本.Net 2.0的版本下對於 FireFox 瀏覽器的支援性有問題,無法進行拖曳變換排版的功能。
所以我安裝了 ASP.NET 2.0 AJAX Futures January CTP,並且直接引用了修正的dll檔,所以會有命名空間上的差異。
ASP.NET 2.0 AJAX Futures January CTP 可 在此下載
請注意! 要使用新版本的 WebPartManager 必須搭配新版的 WebPartZone 才可使用,
因此我也繼承新版的 WebPartZone Control,名為 TWebPartZone,此 Control 不需要改寫任何方法。
02 Imports System.Web.UI.WebControls.WebParts
03
04 Namespace WebControls
05
06 Public Class TWebPartZone
07 Inherits Microsoft.Web.Preview.UI.Controls.WebParts.WebPartZone
08
09 End Class
10
11 End Namespace
本範例提供了簡單使用 Web Parts 的一個基本範例,小弟功力還很弱。
僅與大家分享一些學習心得,請大家多多批評指教,謝謝!
留言列表