| Home |

輕鬆使用不需要設定資料庫的 WebPart 功能

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
posted on 2008/7/3 19:00 | 1 人收藏 5 人推薦 我要推薦 | 閱讀數 : 820 | 分類[ ASP.NET ] 訂閱

關連文章

Feedback

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by jas at 2008/7/13 上午 11:46
請問一下,我照您的方法實作,但沒有考慮到firefox的狀況,我直接繼承WebParts.WebPartManager。

之後都會出現例外的錯誤

不到路徑 'c:\inetpub\wwwroot\Test\UserData\_Personalization.xml' 的一部分。

是我那裡做錯了嗎?小弟還是個新手,希望您能多指導一下

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by eric at 2008/7/17 下午 12:13

看起來應該是檔案路徑的問題

請問你是頁面一載入就錯了嗎?

因為這樣看不太出來耶

可能的話盡量把錯誤的原始碼還有錯的地方貼上來

這樣比較找的到喔

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by jas at 2008/7/21 下午 03:06
想不到大大有上來看!



後來我加了這一段就可以了,該不會是VS2008的問題吧

'存放於App_Data\UserData\ 目錄之下
path += "\App_Data\UserData\" & Me.UserID & "\"

IO.Directory.CreateDirectory(path)←

不過還是要再請教一下,如果說我想讓A使用者看到B使用者的設定,又要如何改寫呢?

懇請大大教教小弟吧!!

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by jas at 2008/7/21 下午 03:38
小弟似乎大略想出做法了,先實作看看。到時候再來發表心得!感謝大大

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by jas at 2008/8/13 下午 04:50
後來是在Init時更改Session的內容就行了

不過

感覺用Session不是很好的作法^~^

謝謝大大啦!

# re: 輕鬆使用不需要設定資料庫的 WebPart 功能 回覆

Left by eric at 2008/8/14 上午 09:58

請問你指的 "在Init時更改Session的內容"

是什麼意思呢?

可以把程式碼貼出來看看嗎 ^^

回應:




 
Please add 7 and 4 and type the answer here:

Copyright © Eric

Design by Bartosz Brzezinski

Design by Phil Haack Based On A Design By Bartosz Brzezinski