So what is it the WebPartManager stores in the personalization system?
This article is about the inner workings of the WebPartManager from ASP.NET 2.0. If you don't know exactly what I'm talking about, check these links:
ASP.NET 2.0
Web Parts
Personalization system
So you probably know that all of the properties you can set on Web Parts in ASP.NET 2.0 are stored inside the personalization system. In this article, you can find out how the storage happens and how you can plug in your own storage provider for personalization. If you have a look at the actual data persisted inside the personalization system (regardless of the provider used), you will find that it is a large BLOB. When you are inside a running Web Part age, this is not something you have to worry about, as the Web Part Infrastructure will set the correct values to your object properties automatically. There are situations, however, where you want to have access to the information stored from other contexts:
when you want to "copy" web parts from one page to another
when you are migrating information from a web patr based system to another (or vice versa)
when you need to update the personalized settings of other users (think of a tool that does certain updates necessary for a new version of a specific control)
So for these cases, we want to be able to access the information stored by the WebPartManager control from outside. Maybe from a console application, a WinForms application or another web page. In this article, I will explain how the WebPartManager stores the information for a Web Part page and I will show code for accessing this information.
We will first have a look at how the information is stored. Essentially, the blob in the personalisation system is the binary representation of an object array. The encoding/decoding of the array to the binary data is performed by a class called System.Web.UI.ObjectStateFormatter. In the resulting object array, each element has a fixed meaning based upon the order in the array:
Repeat | Type | Meaning
___________________________________________________________________
| int | Must have the value 1 if the array is filled
| int | The number of described controls
control | Type | Type of the control (optional)
| | string | Virtual path of UserControl (optional)
| | string | Control ID
| | int | Number of properties
| prop | IndexedString | Key
| - | object | Value
| | int | Number of custom properties
| cust | IndexedString | Key
- - | object | Value
So the first element of the array normally holds an Int32 with value 1. The second element holds the number of controls described. This is the number of times the 'control' block occurs. Within the control block, there are two more repeating sections, here labeld 'prop' and 'cust', each representing an arbitrary number of name-value pairs. Each is preceded by an int indicating the number of blocks we can expect. An IndexedString is a special kind of string the has a better performance when it is used often as a key in dictionary structures.
The array contains a control entry for all Web Parts on the page and the WebPartManager itself. When you cretae a WebBrowsable property on your Web Part, you will find this back in the properties dictionary for your Web Part. If your part implements System.Web.UI.WebControls.WebParts.IPersonalizable, you may also have "Custom Properties". Most Web Parts do not use this facility though. The WebPartManager on the other hand, relies heavily on these custom properties, to store extra information about the page.
The sample project
I created a small library that knows how to decode the binary store of the WebPartManager. It contains a class WebPartBlobEncoder with a static method Decode on it. This method expects a byte array (or base64 encoded string) and returns a Dictionary<string, PersonalizationInfo>. PersonalizationInfo is a simple data holder class that contains properties like these:
Then I created a sample console project to use the library. It decodes some hardcoded base64 strings (from my personalization database) and sends information about the contents to the Console:
The result:
The most important limitation now is that the information inside the WebPartManager's custom properties is still an array with a lot of seemingly unrelated values. I will complete the code to expose this in a strong-typed way as well and I will make sure that the Encoding also works. That will allow you to make changes to the configuration from an outside tool. When this works, I will release the library via this blog.