close

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.dllXmlProviders.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 中。

01     <webParts>
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檔。

01 Public Class TXmlPersonalizationProvider
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() 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() 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(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(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(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 屬性。
 

01 Imports System.Web.UI
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() 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 控制項,即可正常運行。
 

1     Protected Sub TWebPartManager1_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles TWebPartManager1.Init
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 不需要改寫任何方法。
 

01 Imports System.Web.UI
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 的一個基本範例,小弟功力還很弱。

僅與大家分享一些學習心得,請大家多多批評指教,謝謝

DotBlogs Tags: .Net Web WebParts

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 11 的頭像
    11

    冠霖的部落格

    11 發表在 痞客邦 留言(4) 人氣()