Wednesday, April 13, 2011

Property Bag in Application Setting Manager Does Not Find a Key… Easily

I am working on a custom SharePoint 2010 application now, which relies on Microsoft SharePoint 2010 Guidance for developers. Today I came across an interesting issue while utilizing Application Setting Manager component of the guidance library. I thought I’ve set up my application according to the instructions, but I could not get settings retrieved. It turned out that there is a nuance that was not obvious from documentation, which I’d like to point out.

So the setting manager stores configuration settings in a property bag of a web site, site collection, web application or a farm. It can be hierarchical, or you can specify level at which you want to store a setting. Quite powerful. In my case I used a site collection scoped feature to deploy my settings and store them in a site collection property bag. Here is a simplified fragment of my feature receiver class provisioning application settings:

var site = properties.Feature.Parent as SPSite;
var locator = SharePointServiceLocator.GetCurrent();

// Acquire instances of config manager and property bag
var configManager = locator.GetInstance<IConfigManager>();
configManager.SetWeb(site.RootWeb);
var bag = configManager.GetPropertyBag(ConfigLevel.CurrentSPSite);

// Provision application settings
configManager.SetInPropertyBag("Key1", "Value1", bag);
configManager.SetInPropertyBag("Key2", "Value2", bag);

To retrieve the settings I used the following logic:

var locator = SharePointServiceLocator.GetCurrent();
var config = locator.GetInstance<IConfigManager>();
var bag = config.GetPropertyBag(ConfigLevel.CurrentSPSite);

if (!bag.Contains(key))
{
throw new MyKeyNotFoundException();
}

I would be not finding the key and getting an exception. My problem was in just relying on the intellisense – why not? Well, the Microsoft guidance had it right though: in the examples  the check is made as follows:

if (!config.ContainsKeyInPropertyBag(key, bag))
{
throw new MyKeyNotFoundException();
}

And this one works fine.  You can check quite easily what is in your site’s property bag; this and availability of the source code of Microsoft.Practices.SharePoint.Common library help to understand what is going on. Here is how you can see your site collection’s property bag contents using PowerShell (it is stored in the root web of the site collection):

$web = Get-SPWeb http://yoursitecollectionaddress/
$web.AllProperties | fl

You will find that your keys are in the form PnP.Config.Key.Key1._Site_ where the highlighted parts are attached to your actual key. The prefix is a constant, the suffix depends on a property bag type you use. Now if you try calling original method bag.Contains(key) passing it PnP.Config.Key.Key1 – then it will find the key!

One other observation, – you are probably using SharePoint Service Locator pattern with the setting manager, and like I do have unit tests. I needed to replace implementation of IConfigManager and IPropertyBag interfaces with mock classes. Without knowing about this “feature” my mock implementation would find a value for the key as follows: bag.Contains(“Key1”) == true, which would add confusion when the same key would not work in a web site. So try to always use config.ContainsInPropertyBag(key, bag) method instead.