[View full width] Imports System Imports System.Web Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Custom personalization provider which takes into account the ''' id query string parameter. ''' </summary> Public Class QueryStringPersonalizationProvider Inherits SqlPersonalizationProvider ''' <summary> ''' Called when data is saved to the database ''' </summary> Protected Overrides Sub SavePersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String, ByVal dataBlob() As Byte) Dim queryStringId As String = HttpContext.Current.Request("id") If Not queryStringId Is Nothing Then path += "?0" width="14" height="9" align="left" src="/books/3/444/1/html/2/images/ccc.gif" /> WebPartManager, ByVal path As String, ByVal userName As String, ByRef sharedDataBlob() As Byte, ByRef userDataBlob() As Byte) Dim queryStringId As String = HttpContext.Current.Request("id") If Not queryStringId Is Nothing Then path += "?0" width="14" height="9" align="left" src="/books/3/444/1/html/2/images/ccc.gif" /> sharedDataBlob, userDataBlob) End Sub ''' <summary> ''' Called when a user's personalization data is reset ''' </summary> Protected Overrides Sub ResetPersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String) Dim queryStringId As String = HttpContext.Current.Request("id") If Not queryStringId Is Nothing Then path += "?docText">The class in Listing 29.11 overrides three methods of the base SqlPersonalizationProvider class: the SavePersonalizationBlob(), LoadPersonalizationBlob(), and ResetPersonalizationBlob() methods. The Blob, in this context, refers to the serialized blob of personalization data. In each of these methods, the value of the query string parameter named ID is added to the path associated with the state data being saved. In other words, the state data is scoped to the path and ID query string parameter. After you add the class in Listing 29.11 to your application's App_Code folder, you need to configure the custom personalization provider. The Web configuration file in Listing 29.12 configures the QueryStringPersonalizationProvider as the application's default personalization provider. Listing 29.12. Web.Config <?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <connectionStrings> <add name="Northwind" connectionString="Server=localhost;Trusted_Connection=true; Database=Northwind"/> </connectionStrings> <system.web> <webParts> <personalization defaultProvider="QueryStringPersonalizationProvider"> <providers> <add name="QueryStringPersonalizationProvider" type="myControls.QueryStringPersonalizationProvider" connectionStringName="localSQLServer" /> </providers> </personalization> </webParts> </system.web> </configuration> | CD Note The Web.Config file in this section is named Web.Config_listing12 on the CD so that it does not interfere with the other code samples in this chapter. You can test the QueryStringPersonalizatonProvider by opening the MovieList.aspx page on the CD that accompanies this book in your browser. When you click on a movie title, you are linked to the MovieDetails.aspx page, which displays a particular movie. Notice that you can personalize each version of the MovieDetails.aspx page differently. For example, you can enter different text in the TextPart control for each movie (see Figure 29.6 and Figure 29.7), even though the different movies are displayed by the same page. Figure 29.6. Displaying Star Wars movie details. Figure 29.7. Displaying Jaws movie details. Building an Anonymous Personalization Provider The default SqlPersonalizationProvider stores personalization data for a user only when the user is authenticated. This requirement makes sense. Typically, you do not want to store personalization data for every random stranger who visits your website. However, there are situations in which you might want to enable anonymous users to personalize a Web Part application. For example, you might want to create a customizable portal page, such as those used for My MSN or My Yahoo, and not require users to register at your website prior to performing the customization. Fortunately, modifying the existing SqlPersonalizationProvider to support anonymous users is not that difficult because another part of the ASP.NET Framework already includes the infrastructure for identifying anonymous users. The ASP.NET Framework supports a feature called Anonymous Identification, which is used to support anonymous ASP.NET Profiles. Note The Profile class is discussed in Chapter 22, "Maintaining Application State." In this section, you learn how to create an Anonymous Personalization Provider. To create this custom personalization provider, you need to modify three of the standard classes used by the Web Part Framework. First, you need to create the Anonymous Personalization Provider class itself. This class is contained in Listing 29.13. Listing 29.13. AnonSqlPersonalizationProvider.vb [View full width] Imports System Imports System.Web Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Custom Personalizaton Provider which enables ''' anonymous personalization ''' </summary> Public Class AnonSqlPersonalizationProvider Inherits SqlPersonalizationProvider ''' <summary> ''' Saves personalization data to the database ''' </summary> Protected Overrides Sub SavePersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String, ByVal dataBlob() As Byte) If Not HttpContext.Current.Request.IsAuthenticated Then userName = HttpContext.Current.Request.AnonymousID End If MyBase.SavePersonalizationBlob(webPartManager, path, userName, dataBlob) End Sub ''' <summary> ''' Loads personalization data from the database ''' </summary> Protected Overrides Sub LoadPersonalizationBlobs(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String, ByRef sharedDataBlob() As Byte, ByRef userDataBlob() As Byte) If Not HttpContext.Current.Request.IsAuthenticated Then userName = HttpContext.Current.Request.AnonymousID End If MyBase.LoadPersonalizationBlobs(webPartManager, path, userName, sharedDataBlob , userDataBlob) End Sub ''' <summary> ''' Deletes personalization data from the database ''' </summary> Protected Overrides Sub ResetPersonalizationBlob(ByVal webPartManager As WebPartManager, ByVal path As String, ByVal userName As String) If Not HttpContext.Current.Request.IsAuthenticated Then userName = HttpContext.Current.Request.AnonymousID End If MyBase.ResetPersonalizationBlob(webPartManager, path, userName) End Sub ''' <summary> ''' Determines whether the page opens in User or Shared ''' personalization scope ''' </summary> Public Overrides Function DetermineInitialScope(ByVal webPartManager As WebPartManager, ByVal loadedState As PersonalizationState) As PersonalizationScope Return webPartManager.Personalization.InitialScope End Function End Class End Namespace | The AnonPersonalizationProvider overrides four methods of the base SqlPersonalizationProvider class. If a user is anonymous, then the LoadPersonalizationBlob(), SavePersonalizationBlob(), and ResetPersonalizationBlob() methods use the anonymous ID associated with the user rather than the normal username. The DetermineInitialScope() method is also overridden because the default implementation of this method automatically puts anonymous users into Shared personalization scope. Next, you need to modify the standard WebPartPersonalization class. The standard version of this class prevents anonymous users from modifying state information. The updated AnonWebPartPersonalization class is contained in Listing 29.14. Listing 29.14. AnonWebPartPersonalization.vb [View full width] Imports System Imports System.Collections Imports System.Web Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Overrides the standard WebPartPersonalization class ''' to enable anonymous users to modify state. ''' </summary> Public Class AnonWebPartPersonalization Inherits WebPartPersonalization Public Sub New(ByVal webPartManager As WebPartManager) MyBase.New(webPartManager) End Sub Protected Overrides ReadOnly Property UserCapabilities() As IDictionary Get If HttpContext.Current.Request.IsAuthenticated = True Then Return MyBase.UserCapabilities Else Dim capabilities As Hashtable = New Hashtable() capabilities.Add(WebPartPersonalization.ModifyStateUserCapability, WebPartPersonalization.ModifyStateUserCapability) Return capabilities End If End Get End Property End Class End Namespace | In Listing 29.14, the UserCapabilities property is overridden. The new version of this property ensures that all users, even anonymous users, have the capability to modify state information. Next, because a custom WebPartPersonalization class has been created, the standard WebPartManager control has to be modified before you can use it. The updated WebPartManager control is contained in Listing 29.15. Listing 29.15. AnonWebPartManager.vb Imports System Imports System.Web.UI.WebControls.WebParts Namespace myControls ''' <summary> ''' Modifies the base WebPartManager control ''' to use the AnonWebPartPersonalization class ''' </summary> Public Class AnonWebPartManager Inherits WebPartManager Protected Overrides Function CreatePersonalization() As WebPartPersonalization Return New AnonWebPartPersonalization(Me) End Function End Class End Namespace | In Listing 29.15, the base CreatePersonalization() method of the WebPartManager control is overridden to use the custom AnonWebPartPersonalization class. Next, you are ready to enable the Anonymous Personalization Provider. The web configuration file in Listing 29.16 contains the necessary configuration settings. Warning You might need to restart your application to load the new personalization provider. Listing 29.16. Web.Config <?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.web> <anonymousIdentification enabled="True"/> <authentication mode="None" /> <webParts> <personalization defaultProvider="AnonProvider"> <providers> <add name="AnonProvider" type="myControls.AnonSqlPersonalizationProvider" connectionStringName="localSQLServer"/> </providers> <authorization> <allow users="Administrators" verbs="enterSharedScope"/> </authorization> </personalization> </webParts> </system.web> </configuration> | CD Note The configuration file in Listing 29.16 is saved with the name Web.Config_listing16 on the CD so that it does not interfere with the other code samples in this chapter. The Web configuration file in Listing 29.16 does three things. First, it enables Anonymous Identification. When this feature is enabled, a GUID is generated automatically for each user and stored in a browser cookie. Second, the configuration file disables authentication by setting the Authentication Mode to the value None. Finally, the configuration file configures the AnonPersonalizationProvider as the default personalization provider for the application. Warning You might need to restart your application to load the new personalization provider. At this point, it's finally time to try out the Anonymous Personalization Provider. The Web Form page in Listing 29.17 can be customized by strangers. Listing 29.17. TestAnonymous.aspx <%@ Page Language="VB" %> <%@ Register TagPrefix="custom" Namespace="myControls" %> <%@ Register TagPrefix="user" TagName="PersonalizationManager" src="/books/3/444/1/html/2/~/PersonalizationManager.ascx" %> <%@ Register TagPrefix="user" TagName="TextPart" src="/books/3/444/1/html/2/~/TextPart.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <script runat="server"> Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs) WebPartManager1.DisplayMode = WebPartManager1.DisplayModes(e.Item.Text) End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <style type="text/css"> .personalizationManager { border:dotted 2px orange; padding:5px; background-color:White; font:12px Arial, Sans-Serif; } .personalizationManager span { padding-right:10px; margin-right:10px; border-right:solid 1px black; } .personalizationManager a { text-decoration:none; } .column { float:left; width:30%; height:200px; margin-right:10px; border:solid 1px black; background-color: white; } .menu { margin:5px 0px; } html { background-color:#eeeeee; } </style> <title>Anonymous Personalization</title> </head> <body> <form runat="server"> <custom:AnonWebPartManager Runat="server" /> <user:PersonalizationManager runat="server" /> <asp:Menu OnMenuItemClick="Menu1_MenuItemClick" Orientation="Horizontal" Css Runat="server"> <Items> <asp:MenuItem Text="Browse" /> <asp:MenuItem Text="Design" /> </Items> </asp:Menu> <asp:WebPartZone Css Runat="server"> <ZoneTemplate> <user:TextPart Title="Text Part" Description="Displays block of text" Runat="server" /> </ZoneTemplate> </asp:WebPartZone> <asp:WebPartZone Css Runat="server" /> </form> </body> </html> | After you open the page in Listing 29.17, you can update the text displayed by the TextPart Web Part (see Figure 29.8). If you close your browser and return to the website in two years, the same text will appear. Figure 29.8. Using the Anonymous Personalization Provider. If you want to simulate two anonymous users, then you need to open two different types of browsers (opening multiple instances of Internet Explorer doesn't work because they all share the same browser cookies). For example, you can open the Default.aspx page in both Internet Explorer and Mozilla Firefox and make different changes to the same page. Warning There is one undesirable consequence of the way that the Anonymous Personalization Provider was implemented in this chapter. Anonymous users are added to the aspnet_Users database table without being marked as anonymous. To fix this problem you need to modify the following line in the aspnet_PersonalizationPerUser_SetPageSettings stored procedure: EXEC dbo.aspnet_Users_CreateUser @ApplicationId, @UserName, 0, @CurrentTimeUtc, @UserId OUTPUT The 0 parameter hard codes all users as authenticated. |