Deploying and applying a master page as a feature

Keeping on with my run of posts about stuff that can be done with features, here is the latest thing I have done. The scenario this time is that we want to have a feature that will not only deploy a masterpage when it is activated, but we want to set it as the current masterpage for the site as well. So first thing is first, go and make yourself an appropriate masterpage, then put your feature together. Here is an example what my feature looks like
 
Feature.xml
 
<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="b6721f55-d5a7-48f4-abca-46a1633ad596"
          Title="My New Master Page"
          Description="Deploys and uses a new master page"
          Version="12.0.0.0"
          Hidden="FALSE"
          Scope="Web"
          DefaultResourceFile="core" 
          ReceiverAssembly="dll_name, Version=1.0.0.0, Culture=neutral, PublicKeyToken=PublicKey"
          ReceiverClass="Namespace.ClassName"
          xmlns="
http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/> 
    <ElementFile Location="MyCustom.master" />
  </ElementManifests>
</Feature>
 
Elements.xml
 
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="
http://schemas.microsoft.com/sharepoint/">
        <Module Name="CustomMaster" Url="_catalogs/masterpage">
                <File Url="MyCustom.master" Type="GhostableInLibrary" >
                        <Property Name="ContentType" Value="My Custom master page" />
                        <Property Name="MasterPageDescription" Value="This is my custom master page" />
                        <Property Name="Title" Value="MyCustom.master" />
                </File>
        </Module>
</Elements>
 
receiver.cs
 
/// <summary>
/// Applies the custom master page to the site
/// </summary>
/// <param name="properties"></param>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
   SPWeb web = (SPWeb)properties.Feature.Parent;
   web.AllProperties["OldMasterUrl"] = web.MasterUrl;
   web.AllProperties["OldCustomMasterUrl"] = web.CustomMasterUrl;
   web.MasterUrl = web.ServerRelativeUrl + "/_catalogs/masterpage/MyCustom.master";
   web.CustomMasterUrl = web.ServerRelativeUrl + "/_catalogs/masterpage/MyCustom.master";
   web.Update();
}
 
/// <summary>
/// Restores the original masterpage that was on the site when this feature was activated
/// </summary>
/// <param name="properties"></param>
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
   SPWeb web = (SPWeb)properties.Feature.Parent;
   web.MasterUrl = web.AllProperties["OldMasterUrl"];
   web.CustomMasterUrl = web.AllProperties["OldCustomMasterUrl"];
   web.Update();
}
 
OK, so lets go over what is here. In the feature.xml file, just make sure that you add your master page as an elements file. Then in elements.xml we are defining a module that is used to deploy a file – we specify the URL that it is deployed to, which is relative to where the feature is being activated, which is any given site in a site collection in this instance as the feature’s scope is set to ‘web’. We add a file attribute to the module, telling SharePoint to take our mycustom.master page and put it there, and we set some properties of the file. We give it a name (which goes in the contenttype attribute), description and set the title to be the name of the file.
 
Now comes the cool bit – in feature.xml we specified a reciever, which is a class with code that will run when the feature is actived/deactived etc. (Now that I think about it, I don’t think that I have mentioned that I set up my features using WSP builder and Visual Studio – very very easy way to do things, just chosoe to add a new item in VS and select efature with receiver, and it will add the appropriate class and XML for you). In the reciever we are adding code that sets the main master page, and the custom master page attributes of the site. We also store the existing values as site properties that can be retrieved in the feature deactivating event so we can restore the original state of the site when the feature is deactivated. Bundle that up into a solution, deploy it and then you can deploy your master page where ever you want.
 
You could even take this code further by having it scan through sub sites and applying the master page to all subsites. Then you can apply the same master page to a section of a site collection – Much easier than deploying and setting masterpages through the UI.

Feature Stapling – Why you should love it

Now, as I’m sure you all know by now modifying the files in the 12 hive of a MOSS isntallation is not supported by Microsoft, as when they release updates or service packs any of your changes can and will be lost, and may even prevent an update from happening etc. etc. So what do you do when you need to modify SharePoint’s out of the box site definitions? They live in the 12 hive so you can’t (shouldn’t) go and just change the files. In most circumstances I would just say to make a new site definition and use that instead, but the particular circumstance I have come across at work is that we need to change the inbuilt meeting workspaces. These site defintions differ from the others in that there appears to be some hard coded bits in MOSS that handle these sites differently (for example, only the site definitions and templates based off the MPS template will appear when you create a meeting workspace for a calendar event). So if you want a new meeting workspace, creating a new definition wont cut it because whatevery ou do, it just wont be the MPS template.
 
This is where feature stapling comes to the rescue. Feature stapling allows you to attach a feature to all sites of a given template and configuration, so you can do things to the site definition without actually modifying it. Chris Johnson has a very helpful blog post where he describes how to staple a feature to a site definition. Lets have a quick look at how it’s done.
 
First, create a feature like usual (it must be scoped for the ‘Farm’ level and activated in the central administration site), and in the elements file add a tag like this:
 
<FeatureSiteTemplateAssociation Id="29D85C25-170C-4df9-A641-12DB0B9D4130" TemplateName="MPS#0" />
 
This tag will assign the feature with an ID of 29D85C25-170C-4df9-A641-12DB0B9D4130 to all basic meeting workspaces (Configuration option 1 for the MPS template). When you think about it, this is a really powerful way to get things done. So in my example at work, I have bound many features to the blank meeting workspace (MPS#1) so that when someone creates a site based off that definition, all of my features are turned on in it by default. So if I have features that created document libraries, deploy master pages, or do whatever else, they all happen automatically when the site is created. Even cooler than that is that if the stapled features if are hidden ones, the users of the site won’t see them and can’t turn them off, so the whole experience is much more transparent. It really does give the effect of having the site definition changed, but without modifying the files in the 12 hive.
 
Another very cool thing to do with this is to implement features that have recievers (a receiver is a piece of code that runs when the feature is activated/deactivated). If you write some code into a receiver, it will effectivly run whenever a site of the given template is created, perfect for doing all sorts of things that feature’s wont normally do for you, so your new site really can be customised to be just like you need it to be – all without modifying the site definiton. So if you have managed to read this far down, I have hopefully explained why you (as a develoepr at least) should love the idea of feature stapling – it is just cool.

Link event work spaces to items in a calendar with code

I came across this handy bit of code in some stuff I was working on today and thought it was worth sharing. The scenario is that you have an item in a calendar and you want to link it to an existing site for its workspace (as opposed to creating a new one which will happen when you tick the box to use a worksoace for the event). Now the obvious thing here is that it’s not often that the event workspace and the event will become unlinked, but if you have just migrated the content from one environment to another then (depending on how you have migrated) they might have become unlinked. Anyway, here is the code to created the link again
 
SPSite site = new SPSite("SharePointURL");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["List Name"];
SPListItem item = list.GetItemByID(ItemId); // Get the list item however you need to, it doesn’t have to be get item by ID
 
SPWeb eventWeb = web.Webs["Web Name or Guid of the event workspace"];
 
SPMeeting meeting = SPMeeting.GetMeetingInformation(eventWeb);
meeting.LinkWithEvent(web, list.ID.ToString(), item.ID, "WorkspaceLink", "Workspace")
 
The SPMeeting class is used to create the link to the event workspace. The cool thinkg about this is that it will automatically handle everything for us, so it doesn’t matter if the event is recurring, and all the information about the event wil appear on the event workspace exactly as if it was created like a new one. For our project at work we took this basic code and put it into a loop that matched up the names of events with the names of sub sites and created then created the link, and I gotta say I was pretty happy with the results. I got this code from an example on MSDN at http://msdn2.microsoft.com/en-us/library/ms434156.aspx?s=21.

Adding a link to the Shared Services Provider home page

This is an interesting one that I came across at work today. The requirement is to be able to add a custom link to the MOSS SSP home page without modifying any of the files in the 12 hive (as we all know that modifying those files isn’t supported anyway, so changing those files shouldn’t be done anyway). With the help of Google I managed to come across a few blog posts that pointed me in the right direction. The first of which was "Modifying ’system’ pages in SharePoint safely – with sample code" by Chris O’Brien – in this post he discuss how to add custom links to the site settings and central administration pages by using features. Basically the general thing is that the CustomAction element in the feature will add the link. For example:
 
<CustomAction Id="MyDeletedItems"
              GroupId="SiteCollectionAdmin"
              Location="Microsoft.SharePoint.SiteSettings"
              Sequence="10"
              Title="My recycle bin items"
              Rights="ManageWeb,BrowseUserInfo">
  <UrlAction Url="_layouts/custom/MyRecycleBinItems.aspx" />
</CustomAction>
 
This is the example Chris gives on his blog, it adds a link to the Site Settings page that goes to a page he has created. The location ang group attributes control exactly where the link will appear (with the sequence being the controler for what order it appears in the list). There is come good doco on MSDN about the groups and locations, see http://msdn2.microsoft.com/en-us/library/bb802730.aspx.
 
The one thing that isn’t covered on MSDN that I couldn’t find anywhere else is the groups and location for adding to the Shared Services page. Well the location is the easy bit to get, if you open the SSP site in SharePoint designer and have a look at the tag that renders the links, it has a location attribute of "Office.Server.ServiceProvider.Administration", so thats the location we need. Next is the group attribute to get your link to appear under an existing heading. I was ableto find all of the groups with the exception of the audiences on (I’ll admit I didn’t look too hard though). Yo ucan find them by looking at the out of the box features in the LAYOUTS/FEATURES folder of the 12 hive. They will have the CustomAction tags like the one defined above, and from here you can get the group names. Here is a list of the ones I found
 
  • User Profiles and My Sites (Group: UAP)
  • Search (Group: Search)
  • Excel Services Settings (Group: ExcelServer)
  • Office SharePoint Usage Reporting (Group: PortalAnalytics)
  • Business Data Catalog (Group: BDC)

I would hazard a guess that the audience group would just be ‘Audiences’ or something to that extent, once I have time to have a good look for it, I’ll update this post with the correct group name.

So with those groups you can now add a link to the SSP home page by using a feature (the CustomAction tag goes into yoru elements manifest file). When you activate the feature the link appears, deactivate it and it geos away, all without editing a file in the 12 hive. Thats mission accomplished in my book!

 

Finding everything that isn’t a word in a regular expression

This might sound like a pretty basic thing to do, but I found myself hitting Google up for an answer to this one and I thought it was worth sharing. Most people who know some basic things to do with regular expressions will know that you can find all the words in a string by using w (with a word being made up of only alphanumeric characters). I had a scenario today where I needed to find all the non-alphanumeric characters in a string so I could remove them. The answer is simple, you can use W (note the uppercase W instead of the w) – this will return the exact opposite of w, so every non-alphanumeric character in a string, so removing this characters in C# was as easy as this:
 
RegEx.Replace(StringValue, "\W", String.Empty);

Install OneNote Mobile onto Windows Mobile 6

Taken from my old blog http://souls-end.spaces.live.com on 23/1/2008
 
Well I am in my new job now, and as always with a new job, comes new toys, new software, and lots of new information. The first new thing that I had a good play around with is OneNote 2007, which I am really liking the look of. But one of the cool things you can do is to sync data from one note to your windows mobile device.
To do this just plug you device in while OneNote is running and you should get a balloon pop up telling you that you can install it. This is where things went a little pear shaped for me, I ran the installer but got an error at the end of it "Cannot copy file" with the usual babble about checking available space and write protection. After a short while I gave up on this, and I jumped on the plane back home. When we landed and I turned my phone back on though, surely enough there goes the OneNote mobile installation! Now I’m not sure if its a Windows Mobile 6 thing or my phone just didn’t feel loved enough to run it first time, but the restart seemed to do the trick. So if you find yourself having that error, restart your device and see where you are when the dust settles.

Merging Windows Live contacts with your Windows Mobile 6 device

1

Taken from my old blog http://souls-end.spaces.live.com on 18/12/2007
 
Following on from my post about my new phone, I thought I might spend the next couple of posts talking about stuff I have done with the phone, and stuff that I have found pretty helpful. I’m going to start with one I figured out yesterday, to do with contacts on Windows Live Messenger, and contacts in your phone.
So Windows Mobile 6 comes with Windows Live Messenger installed as part of the load, and I gotta say that I think they did a great job with the interface – much more pleasant than messenger on my old Windows Mobile 5 iMate. When you sign into messenger for the first time though, it will add all of your messenger contacts to your mobiles contact list, attempting to merge the data with what you already have where it can. This is great – it means your phone then becomes the connection between your outlook contacts, and your hotmail address book and WLM contacts, in a way not to dissimilar to what outlook does in showing the status of a contact if you have messenger running and you’re signed in. The thing is though, that the merging process isn’t perfect, and I did find myself with some duplicate contacts in my phones contact list, even though the email addresses were all up to date.
The way around this – on your device, sign in to messenger, and delete the duplicate contacts added by messenger (the ones with the messenger icon next to them, not the outlook ones). This will remove them from your contacts list in messenger, but you will add them right back. Next go to the original outlook contact on your device, and under the menu select ‘Add to Windows Live’. You will be prompted to select an email address for the user from their contact details, but then they will be put back into your messenger contacts, and you will notice the outlook icon will change to the messenger icon – so now no more duplicate contacts!

I find having the messenger functionality combined with my contact list is great, and while the mobile device isn’t signed in very often, its useful when it is connected to see who’s online, who’s offline, and who isn’t a messenger contact. All in all, so far so good on Windows Mobile 6 – more to come in the next few days!

SharePoint custom master pages and the page edit consoles

Taken from my old blog at http://souls-end.spaces.live.com on 30/11/2007
 
So back to something SharePoint related, and I have to thank Heather Solomon for providing me with the solution to this annoying problem (check her blog out at http://www.heathersolomon.com/blog/, she knows her stuff – especially when it comes to branding SharePoint). Anyway, the issue is to do with when you are coming up with a new master page for a MOSS 2007 site, and you are starting from scratch (or using the minimal master page provided by MS). You might find that when you look at your pages, they look fine – until you go into edit mode and you get the web part properties window appearing at the bottom of your page instead of the right side, and your content just goes all over the place.
The problem is caused by the WSSDesignConsole control (and also the PublishingConsole according to Heather, but I didn’t have this issue as I have put mine onto the page differently I think). This control would normally look like this in your master page:
<!– Edit console that appears in page Edit mode –>
<asp:ContentPlaceHolder ID="WSSDesignConsole" runat="server">
    <wssuc:DesignModeConsole id="IdDesignModeConsole" runat="server"/>
</asp:ContentPlaceHolder>
<!– Publishing console control –>
This will give you the little toolbar with the exit edit mode link, but the problem is caused by the HTML that this little guy renders. It was designed to fit within a default SharePoint master page, with its HTML around it in all the tables based glory that it is. So what they did here is to start the edit toolbar with a <tr> tag instead of its own <table> tag – Hence the havoc that you will see on the page when you put this one on if your tables are different to those in a standard MS master page, or you have a non tables based layout. The solution is simple though, just put the thing inside a <table> tag, like so:
<!– Edit console that appears in page Edit mode –>
<asp:ContentPlaceHolder ID="WSSDesignConsole" runat="server">
    <table><wssuc:DesignModeConsole id="IdDesignModeConsole" runat="server"/></table>
</asp:ContentPlaceHolder>
<!– Publishing console control –>
And just like that your problems are solved. Now you can also set some properties of the table, like a border, width, height, or whatever else you want. An easy fix for an annoying problem. Thanks to Heather for making a post about it as well, I was ready to rip my hair out trying to figure out what I was doing wrong!