by Martin
25. november 2010 15:13
I've been doing a project for a client requiring a custom site definition template.
This template included various custom lists to be instantiated along with the site definition. This worked like a charm. The lists had <data> elements inside the <list>-elements (in short: had folders created when provisioned, great article here: http://geekswithblogs.net/kit/archive/2008/08/25/124679.aspx ). This also worked fine until I found out that is was also a requirement to have links in the navigation on the left-hans side to the lists.
This is NOT easily accomplished!
Because if you set the OnQuickLaunch-property of a ListTemplate-element at best it adds it under a "Libraries"-heading in the navigation. I wanted it to be a link in the "root" of the navigation. A had to do this with a featurereceiver. Easily accomplished in it self but not in practice.
I added a feature-element to my CAML in onet.xml activating my feature when the site was provisioned. Problem was just that the lists wasn't created at this point, so I couldn't get a reference to them (I didn't want to hard code the URL's). In short: feature leveraging featurereceiver was activated before lists were instantiated. OK I thought: instead I'll just move the list instatiation to a separate feature, activate the feature instanting the lists in the CAML of my onet.xml. This led to a plethora of exceptions in my ULS and no site(s) being provisioned (something like "Column 'LinkTitle' does not exist" and various others...).
There was another alternative to accomplish my goal: Create an ExecuteUrl-element and call an applicationpage which activated the feature (and hence the featurereceiver). This didn't seem to work either.. I had the below code
protected void Page_Load(object sender, EventArgs e)
{
try
{
Guid featGuid = new Guid("70dc1ed8-5664-46cc-8068-310c033879b8");
if (SPContext.Current.Web.Webs.Count > 0)
{
//Activate feature
for (int i = 0; i < SPContext.Current.Web.Webs.Count; ++i )
{
using (SPWeb web = SPContext.Current.Web.Webs[i])
{
if (web.Features[featGuid] != null)
{
//Feature already activated, continue
continue;
}
//Add feature to trigger feature receiver
web.Features.Add(featGuid);
}
}
}
SPUtility.Redirect(SPContext.Current.Web.Url, SPRedirectFlags.Default, System.Web.HttpContext.Current);
}
catch { }
}
This didn't work either: It threw an exception: Updates not allowed on GET requests. D'oh, Remember to set the AllowUnsafeUpdates-property to true AND revert it after you're done:
protected void Page_Load(object sender, EventArgs e)
{
try
{
Guid featGuid = new Guid("70dc1ed8-5664-46cc-8068-310c033879b8");
if (SPContext.Current.Web.Webs.Count > 0)
{
//Activate feature
for (int i = 0; i < SPContext.Current.Web.Webs.Count; ++i )
{
using (SPWeb web = SPContext.Current.Web.Webs[i])
{
if (web.Features[featGuid] != null)
{
//Feature already activated, continue
continue;
}
bool allowUnsafeUpdates = web.AllowUnsafeUpdates;
//Allow unsafe updates
web.AllowUnsafeUpdates = true;
//Add feature to trigger feature receiver
web.Features.Add(featGuid);
//Update
web.Update();
//Reverse setting
web.AllowUnsafeUpdates = allowUnsafeUpdates;
//Updaet again to reflect changes
web.Update();
}
}
}
SPUtility.Redirect(SPContext.Current.Web.Url, SPRedirectFlags.Default, System.Web.HttpContext.Current);
}
catch { }
}
Mission accomplished!