Iteration 10 is complete and the drop can be downloaded here.
In iteration 10 we mainly concentrated on refactoring, code cleanup and reusable assets. We will continue refactoring and scrubbing the code in the remaining iterations but please take a look at what we've done so far and provide us feedback.
Not to be confused with Hierarchical Object Store which uses SPPersistedObject to build a hierarchy of elements to store configuration data, our notion of “Hierarchical Configuration” describes the ability to retrieve a configuration setting and not know where in the hierarchy that information was persisted. The information could be set at the SPFarm and therefore be available to all code running in that scope. Same goes for the SPWebApplication, SPSite, and SPWeb.
We also support the ability to over-ride a value set higher in the hierarchy. For example, a config setting could be persisted in the SPWebApplication, thus making it available to all SPSites and SPWebs underneath it. However, you could also persist a setting using the same key in an SPSite or SPWeb.
We implemented “Hierarchical Configuration” with Microsoft.Practices.SPG.Common.Configuration.ConfigManager and the various implementations of IPropertyBag (SPFarmPropertyBag, SPWebAppPropertyBag, SPSitePropertyBag, and SPWebPropertyBag).
For an example of how we utilize Hierarchical Configuration, take a look at the Contoso.PSS.GlobalNavigation project. In WebAppFeatureReceiver we use ConfigManager to persist the sitemap xml into the SPWebApplication.
configManager.SetByKey("Microsoft.Practices.SPG.Common.Navigation.NavigationXml", Resources.DefaultSiteMapXml, webApp);
This value is retrieved by the HierarchicalConfigSiteMapProvider:
string siteMapXml = configManager.GetByKey<string>("Microsoft.Practices.SPG.Common.Navigation.NavigationXml");
I’ll go into more detail on the HierarchicalConfigSiteMapProvider later, but you can see from this example that a config setting is persisted in the WebApp and then retrieved by our business logic. The ConfigManager.GetByKey method starts at the current SPWeb and queries the property bag with the key. If the key is not found, the SPWeb’s parent SPSite is queried. If the key is not found in the SPSite, the parent SPWebApplication is queried, and so forth up to the SPFarm.
In a previous iteration, we implemented global navigation through deploying modifications to layouts.sitemap and merging those modifications by calling SPWebService.ApplyApplicationContentToLocalServer() or the corresponding STSADM command copyappbincontent. This approach mainly demonstrated what could be done out of the box to configure navigation in SharePoint. We then used the out-of-the-box XmlSiteMapProvider which is typically already configured in web.config to read from layouts.sitemap. The downside to this approach was that stsadm –o copyappbincontent or SPWebService.ApplyApplicationContentToLocalServer() would need to be executed on every web front end in the farm to update all layouts.sitemap files. In order to move to an approach that is easier to deploy across a farm, we went with a custom site map provider.
The HierarchicalConfigSiteMapProvider extends StaticSiteMapProvider and loads site map nodes on initialization, thus this custom site map provider is appropriate for cases where navigation changes very infrequently.
As mentioned above, the HierarchicalConfigSiteMapProvider leverages Hierarchical Configuration and retrieves sitemap xml from the ConfigManager using the key: “Microsoft.Practices.SPG.Common.Navigation.NavigationXml“. When first initialized, the HierarchicalConfigSiteMapProvider creates a sitemap structure based on the sitemap xml retrieved from the ConfigManager.
The Contoso.PSS.GlobalNavigation WebAppFeatureReceiver adds the appropriate nodes to web.config, saves Contoso PartnerPortal specific sitemap xml to the SPWebApplication, and adds a delegate control that will get picked up by default.master.
In SPG v1, the ServiceLocator could self initialize by knowing about Contoso services that would be necessary for the application to run. In this drop, we’ve made the ServiceLocator much more generic. Now, feature receivers can register their own service implementations, adding to or potentially over-writing previous service registrations.
There are many examples throughout the Contoso.PSS reference implementation for how to use the ServiceLocator to get an instance of a service. This functionality has changed little since SPG v1. However take a look at the Contoso.PSS.Portal project’s WebFeatureReceiver FeatureInstalled method for an example of how this feature is registering type mappings using ServiceLocatorConfig.
In a previous iteration, we implemented a custom look and feel via custom masterpage and CSS. We decided to use the ContosoTheme feature we developed in SPG v1 (Contoso.RI.UpdateTheme) instead of the custom masterpage and CSS. One advantage of using a theme is that system and application pages can also be branded.
In a previous iteration, we implemented the subsite creation process but realized that the process of creating subsites may need to be customized or extended. This iteration, we refactored the subsite creation process into several workflow activities (Microsoft.Practices.SPG.SubSiteCreation.Workflow). We also provide a workflow that stitches these workflow activities together (SubSiteCreation.cs). The workflow activities are:
The Microsoft.Practices.SPG.SubSiteCreation SharePoint solution project packages the above worflow and activities into features.