Skip to main content

Cloud

What’s wrong with this code?

Let’s play a little game I call "What’s wrong with this code?" (I sometimes play the solitaire version the morning after I’ve done some late-night development…)

Here’s the quick scenario. I used Becky Bertram’s blog post as a starting point and created a feature that was intended to provision and deploy a custom master page to new MySites. The feature was stapled to the MySite site definition, and the code in question was included in the FeatureReceiver class. Pretty straightforward, right?

So here’s the code:

   1:  public class FeatureReceiver : SPFeatureReceiver 
   2:  {
   3:      string _defaultMasterUrl = "/_catalogs/masterpage/default.master";
   4:      string _customizedMasterUrl = "/_catalogs/masterpage/MySiteCustomMaster.master";
   5:      
   6:      public override void FeatureActivated(SPFeatureReceiverProperties properties) 
   7:      {
   8:          SPSite site = properties.Feature.Parent as SPSite;
   9:          if (site == null)
  10:              return;
  11:   
  12:          if (site.ServerRelativeUrl.Length > 1)
  13:          {
  14:              _customizedMasterUrl = site.ServerRelativeUrl + _customizedMasterUrl;
  15:              _defaultMasterUrl = site.ServerRelativeUrl + _defaultMasterUrl;
  16:          }
  17:   
  18:          SPWeb rootWeb = site.RootWeb;
  19:          rootWeb.AllProperties["OldMasterUrl"] = rootWeb.MasterUrl;
  20:          rootWeb.AllProperties["OldCustomMasterUrl"] = rootWeb.CustomMasterUrl;
  21:          rootWeb.MasterUrl = _customizedMasterUrl;
  22:          rootWeb.CustomMasterUrl = _customizedMasterUrl;
  23:          rootWeb.Update();
  24:          
  25:          foreach (SPWeb subWeb in rootWeb.Webs)
  26:          {
  27:              ProcessSubWebs(subWeb, true);
  28:          }
  29:      }
  30:      
  31:      // other code omitted for brevity
  32:  }
 

The code worked well in my development environment, and seemed to be OK when we deployed for user testing, but then we started to get intermittent "File not found" errors. It wasn’t on every MySite that was created, but it happened on enough that it wasn’t a fluke.

Tony bailed me out.

He opened one of the sites in SharePoint Designer and got a more detailed exception:

Could not load master page "/personal/user1/personal/user2/personal/user3/_catalogs/masterpage/MySiteCustomMaster.master"

What?!? What kind of URL is that?

The value for the custom master page is supposed to be "/personal/user1/_catalogs/masterpage/MySiteCustomerMaster.master" where "user1" is the user name of the user whose MySite is being provisioned.

So I looked back at the code.

I noticed that I was using private class members to store the value for the customized master page, and prepending to those (in lines 14 and 15 above) with the site’s relative URL. The only thing that could be happening — and what WAS happening — was that the instance of the feature receiver class was persisting and being used for provisioning multiple sites. I added some logging to the class and could see it in action: the URL would be correct the first time through, then prepended with the next user’s info, followed by the next, etc.

After that, the solution was easy: encapsulate the values so that the value in the private member wasn’t changed.

   1:  private string GetCustomizedMasterUrl(SPSite site)
   2:  {
   3:      if (site.ServerRelativeUrl.Length > 1)
   4:          return site.ServerRelativeUrl + _customizedMasterUrl;
   5:      else
   6:          return _customizedMasterUrl;
   7:  }

.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode, .ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode pre
{font-size:small;color:black;font-family:consolas, "Courier New", courier, monospace;background-color:#ffffff;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode pre
{margin:0em;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .rem
{color:#008000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .kwrd
{color:#0000ff;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .str
{color:#006080;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .op
{color:#0000c0;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .preproc
{color:#cc6633;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .asp
{background-color:#ffff00;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .html
{color:#800000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .attr
{color:#ff0000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .alt
{background-color:#f4f4f4;width:100%;margin:0em;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .lnum
{color:#606060;}

I haven’t had the opportunity to dig in any more and figure out just how long the feature receiver class persists, but it does for at least some period of time.

I can understand arguments in favor of persisting the feature receiver instances, but it simply was not the behavior I was expecting. I made a bad assumption and thought that each feature installation would result in a new instance of the feature receiver class. I’d also generally say that based on this, it’s probably a development best practice to encapsulate any feature receiver data that may vary between feature instances at the method level.

Technorati Tags: ,,,MySites

.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode, .ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode pre
{font-size:small;color:black;font-family:consolas, "Courier New", courier, monospace;background-color:#ffffff;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode pre
{margin:0em;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .rem
{color:#008000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .kwrd
{color:#0000ff;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .str
{color:#006080;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .op
{color:#0000c0;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .preproc
{color:#cc6633;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .asp
{background-color:#ffff00;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .html
{color:#800000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .attr
{color:#ff0000;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .alt
{background-color:#f4f4f4;width:100%;margin:0em;}
.ExternalClass681ED06F60164C2786096A07E27A5720 .csharpcode .lnum
{color:#606060;}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Matthew Morse

More from this Author

Follow Us