Support case volumes coming in for MOSS 2007 is huge.  When we try and help customers to find answers to complex problems/questions, many a times we end up learning great stuffs & things that sometime make us yell “Wow, it’s amazing stuff man!!”.  Well, this was one of such “case” and I thought I’d share this out.

 

The requirement was as simple as it could be.  Customizing MySite in MOSS 2007.  Well, that’s fairly simple I though!  And immediately had the following questions bugging me:

 

1.       We cannot create a custom site definition for MySite as the template ID is hard coded in the source!  So, is there any other way?

2.       Well if that’s not possible, can I modify the SPSPERS folder? No way!

3.        Would creating a custom master page help?  Well, it could have, but that requires laying hands on OOB files which is owned by Microsoft – so don’t do it at any cost J

 

Feature the savior

 

Thankfully, we have this very useful and new feature in MOSS/WSS called Features.  It’s a new innovation that allows us to switch on a particular stuff on different scopes (farm, web, site).  With a little help from SharePoint API’s & carefully designing a feature.xml & element.xml file,  I was finally able to get a solution ready that works like charm!  Not to forget, I had to hit my head hard against a concrete wall before I could reach there.  Hopefully, this write up will save time for most of you who might think of customizing MySite in MOSS 2007.

 

First thing first – create a custom master page

 

This was very simple for me.  I just had to copy the default.master page file into a folder and write the text “y0 man! MOSS 2007 feature rocks!” sentence within the <BODY> tag.  Obviously, this is something you wouldn’t call as customization, but in a way it is – you know what I mean? J

 

The default.master page found under the TEMPLATE\GLOBAL folder structure under 12 hive is the master page used by MySite by default.  I am going to try to be a bit more visually descriptive in my posts, so below is a screenshot:

Grab a copy of this file and put in another folder where you would also be putting your feature files soon.  Customize whatever you want in that file.  When I say this, I assume you know what you are doing J  Once you do that and believe you have the master page you want, proceed further.

 

Do I need to do something with Visual Studio 2005 at all?

 

Yes, you have to.  You need to create a new class library in Visual Studio 2005.  Add reference to Microsoft.SharePoint.dll (this is actually displayed as Windows® SharePoint® Services).  Add a using directive to both Microsoft.SharePoint & Microsoft.SharePoint.Administration namespaces.  And derive your main class from SPFeatureReceiver.  I used the below code for the specific case I worked on…

 

using System;

using System.Diagnostics;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

 

namespace MySiteFeatureStaple

{

    public class MySiteFeatureStaple : SPFeatureReceiver

    {

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)

        {

            //throw new Exception("The method or operation is not implemented.");

        }

 

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

        {

            //throw new Exception("The method or operation is not implemented.");

        }

 

        public override void FeatureActivated(SPFeatureReceiverProperties properties)

        {

            SPSecurity.RunWithElevatedPrivileges(delegate()

            {

                EventLog eventlog = new EventLog();

                eventlog.Source = "MySiteFeatureStaple";

                eventlog.WriteEntry("Starting Activation of the MySite Master Page Switcher Feature");

                try

                {

                    SPSite mysite = properties.Feature.Parent as SPSite;

                    SPWeb myweb = mysite.RootWeb;

                    if (myweb.WebTemplate == "SPSPERS")

                    {

                        using (myweb)

                        {

                            myweb.Description = "MySite :: " + DateTime.Now.ToShortDateString();

                            if (myweb.MasterUrl.Contains("default.master"))

                            {

                                myweb.MasterUrl = myweb.MasterUrl.Replace("default.master", "sridhar.master");

                                myweb.ApplyTheme("MyReflector");

                            }

                            myweb.Update();

                            eventlog.WriteEntry("Found site using 'SPSPERS' template & updated it with the custom master page");

                        }

                    }

                    if (myweb.WebTemplate == "SPSMSITEHOST")

                    {

                        using (myweb)

                        {

                            myweb.Description = "MySite :: " + DateTime.Now.ToShortDateString();

                            if (myweb.MasterUrl.Contains("default.master"))

                            {

                                myweb.MasterUrl = myweb.MasterUrl.Replace("default.master", "sridhar.master");

                                myweb.ApplyTheme("MyReflector");

                            }

                            myweb.Update();

                            eventlog.WriteEntry("Found site using 'SPSMSITEHOST' template & updated it with the custom master page");

                        }

                    }

                }

                catch (Exception e)

                {

                    eventlog.WriteEntry(String.Format("Error activating MySite master page switcher feature {0} : ", e.Message));

                }

            });           

        }

 

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            SPSecurity.RunWithElevatedPrivileges(delegate()

            {

                EventLog eventlog = new EventLog();

                eventlog.Source = "MySiteFeatureStaple";

                eventlog.WriteEntry("Starting De-activation of the MySite Master Page Switcher Feature");

                try

                {

                    SPSite mysite = properties.Feature.Parent as SPSite;

                    SPWeb myweb = mysite.RootWeb;

                    if (myweb.WebTemplate == "SPSPERS")

                    {

                        using (myweb)

                        {

                            if (myweb.MasterUrl.Contains("sridhar.master"))

                            {

                                myweb.MasterUrl = myweb.MasterUrl.Replace("sridhar.master", "default.master");

                                myweb.ApplyTheme("none");

                            }

                            myweb.Update();

                            eventlog.WriteEntry("Removed custom master page from site using 'SPSPERS' template");

                        }

                    }

                    if (myweb.WebTemplate == "SPSMSITEHOST")

                    {

                        using (myweb)

                        {

                            if (myweb.MasterUrl.Contains("sridhar.master"))

                            {

                                myweb.MasterUrl = myweb.MasterUrl.Replace("sridhar.master", "default.master");

                                myweb.ApplyTheme("none");

                            }

                            myweb.Update();

                            eventlog.WriteEntry("Removed custom master page from site using 'SPSMSITEHOST' template");

                        }

                    }

                }

                catch (Exception e)

                {

                    eventlog.WriteEntry(String.Format("Error de-activating MySite master page switcher feature {0} : ", e.Message));

                }

 

            });

        }

    }

}

 

I don’t really think the RunWithElevatedPrivileges() call is required, however…. J

 

There are specific aspects that need your attention on the above code.  As you might have seen, SPFeatureReceiver is an abstract class and so we have implemented all the abstract methods in it irrespective of whether we are using them or not.  The code specifically “looks for” MySite and swaps the default.master page with sridhar.master page.  As I said, I tried this out for a customer’s scenario.  You can change this to suit your needs.  I’ve also used ApplyTheme() method to apply a custom theme (wondering how to do this? Here you go) to MySite.  Additionally, as any good software programmer does, I’ve added few lines for logging stuffs regarding what’s happening or if something has gone wrong.

 

Compile this project.  Install the assembly file into GAC.

 

We are not done yet – most important part is to create the feature we need

 

So, we have our DLL that will perform the logic of checking whether a site is a MySite or not and if so, apply a custom master page and a custom theme to it.  Now, we need to create a feature to be able to install/uninstall & activate/deactivate it at will.

 

There’s no hard & fast rule in creating a feature.xml & element.xml file.  Just pop open a notepad file, name it feature.xml and add the following tags as shown below:

Oh yes, if you use Visual Studio 2005 things would be easier for you.  My suggestion for working with XML in Visual Studio 2005:

 

1.       Create a new XML file with name feature.xml

2.       Pop open the XML file’s properties.

3.       You should see a schemas option in the properties window.

4.       For working with features (i.e., creating feature.xml & element.xml files) you can add a reference to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML\wss.xsd file.

5.       This will make things easier for you as you’ll experience IntelliSense™.

 

Coming to the above feature.xml file, it’s pretty simple to understand.  It has a GUID (generated using GUIDGEN), a title, description, version.  The important attributes though are:

·         Scope:  The scope at which the feature would be activated.  For this discussion, I have specified “Site”, which means the feature will be installed at the site collection level.  “Web” would be at a particular site level.  “Farm” would be at the farm level and will be available universally to all sites falling under the farm.

·         ReceiverAssembly/ReceiverClass: Since we are installing the assembly in GAC, we have to sign it with a strong name.  The full assembly name after signing needs to be specified for ReceiverAssembly.  The ReceiverClass name depends on your namespace and your main class name.

·         There’s a <ElementManifests> tag under which the location of the custom master page file is specified.  I had this master file put in the same folder as the feature and so I just provide the master page file name.  There’s also another location that points to MySiteFeatureStapleElement.xml (element.xml file as it is known).  You’ll see what that is in the next section.

 

Create element.xml file

The element.xml file I created looks like what is shown below:

It’s just a description of what, where & how the custom master page is, while in the feature we just defined it.  As you can see, it talks about where to upload the custom master page to, what’s the file name, is it ghostable or not and a unique name.

 

Note: The element.xml file can be named anything e.g., sharepointrocks.xml.  But make sure the feature.xml is named as is and that the correct element.xml file is referenced in feature.xml file.

 

Installing Custom MySite Feature

 

That’s it, you are almost done!  Now, you just need to install/activate this feature to see the magic J  Goto 12 hive BIN folder and use the stsadm tool:

 

stsadm –o installfeature –name <feature name>

stsadm –o activatefeature –name <feature name> -url <http://sharepointurl>

 

In case you are wondering which URL you need to specify?  It should be the URL of the web application that you created for MySite.  Even if you provide the URL of the site from where your user will be accessing their MySite, it would work.  After all, the feature will only get activated in MySite.  See the difference below:

This approach would be a supported method of accomplishing MySite customization.  I've also enclosed a sample application that you can refer to.