WebParts on Master Pages

by matt 6. September 2006 21:16

Last time I spent a very long time griping about how bad WebParts' PersonalizationProvider is, and how it doesn't support web parts on master pages. And I started off the post by saying that SingleUserBlog does just that. What gives?

Out of the box, the PersonalizationProvider doesn't support it, but it's really quite easy to add it. It's just not nice.

This is what Darren had already done in SingleUserBlog; derive from SqlPersonalizationProvider. Override the horrible protected methods I was grumbling about last time, and just call the base method, substituting the proper path with a constant string. Simple.

But what happens when you want to add a new provider? For example, an MS Access based one? When you add this provider, you add a runtime dependency to this provider. As soon as you derive from this protected method, you've added a compile-time dependency, and that's a whole different kettle of fish, and generally not something you take on lightly - after all, what happens if you also want to support SQLite, or just plain old xml? You can't just keep adding dependencies. On top of that, the MS Access providers are all sealed classes - you can't derive from there. (Fortunately, they come with source. Dodged the bullet this time.)

I came up with a slightly different, but only marginally better solution. Look at the docs for PersonalizationProvider and follow along at home. (And read the remarks section. This alone should show you that the class is messed up.)

I created a class that derives from PersonalizationProvider and takes as a parameter the name of the real PersonalizationProvider to use. It uses this name to look up the real provider in PersonalizationAdministration.Providers[]. It then defers nearly all methods to this provider. It allows the base class to handle load and save and overrides the dodgy protected methods. Here's where it gets messy.

When LoadPersonalizationBlobs is called, it uses reflection to call into the real provider and call it's implementation of LoadPersonalizationBlobs. The same happens for SavePersonalizationBlobs.

This works as well as the SqlPersonalizationProvider derived class. It avoids adding dependencies, and copes with sealed classes. But it's fragile - if the provider doesn't implement this hidden, protected API, you're stuffed. If your asp.net host doesn't allow reflection, you're stuffed. And above all, it's using reflection! Another bad smell - if you've had to use reflection to do something, you've probably already gone wrong.

So, what's the proper solution? Well, due to the messy design of the PersonalizationProvider, there isn't one. To support this very useful situation, you need to hack it. It's just a case of deciding how you want to hack it.

Because the PersonalizationProvider is responsible for selecting the path and username to save against, you have to create a new provider, which is a shame. You could make it slightly nicer by having it ask the WebPartManager (well, a derived version) that's sitting on the master page, what the values should be. But you still need a new provider.

I think SingleUserBlog's best choice is to use three methods. First, keep the SqlPersonalizationProvider derived class. You're deriving off a class in System.Web, so you're not adding any dependencies. Secondly, the reflection based method will work with what I suspect will be the majority of custom providers out there.

But my preferred choice would be to create a new provider from scratch for Sub. One of the main reasons I started using Sub was because it didn't use Sql Server for the blog data. So Sql Server shouldn't be the default provider for personalisation (or anything else) in Sub. It would be much nicer to have a simple xml based provider. This kind of provider wouldn't be much good in most other web apps - it won't exactly scale to a large site with loads of pages that loads of users could customise. But we know the usage it will get in Sub - one web page, customised by one user. Xml file should be able to cope with that. Given these requirements, I have no problem creating a Sub-specific provider for this.

Brendan's even got a head start on this (although it's not in the current codebase).

Tags:

Comments

Add comment


(Will show your Gravatar icon)

biuquote
  • Comment
  • Preview
Loading



About the author

Something about the author

Calendar

<<July 2010>>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar

RecentComments

Comment RSS

License

Creative Commons License
Except where otherwise noted, content on this site is by Matt Ellis and is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.

©2010 Matt Ellis