Wednesday, June 11, 2008

Modifying the 'My Links' URL with the Sharepoint Deligate control

Allright, fresh day and refreshing requirement.. a request from the client that they do not need a 'my site' previlege available to all the users in the company. But they remain would like to use the 'My Links' link after the welcome control on each page. They also wanted the 'My Profile' option remain there, so that the user information will be dipsplayed when searched on their name. No worries! there is a way!!

Disable 'my site' and enable 'personal features' & 'manage user profiles'
  1. Go to the ssp personalization permissions page ( Sharepoint Central Admin -> ssp-> service provider -> User Profiles and My Sites ->Personalization services permissions)
  2. Check the user name that you want to disable the 'my site' option. In this case all the users( NT Authority\Auth users)
  3. Click on 'modify permissions' and un select the 'Personal site' right.
  4. Thats it! Now, 'my site' link on all the pages is disabled for the 'NT Auth\Auth users'.
  5. Check the 'Manage User Profiles' and 'Personal Features' rights. Manage user Profiles right will allow the user to have 'My Profile' . Personal Features right will allow the user to enjoy the 'my links' .

So far, we are done with disabling the 'my site' feature. Now lets look at the 'my links' and 'my profile' links. 'My Links' link is on every page. Fine! even the 'Add Links' link within the my links works very fine. But there is a bump on the 'modify links' link. You will get displayed with an as usual un detrmining confused sharepoint error : 'Un Expected Error'. To view the actual error, modify the web.config file located at the 'c:\intepub\wwwroot\wss\virtual dir\your web app port/web.config. modify the config file to set some boolean flags.. false to true! Do it only on Dev/QA servers. Enabling the below debugging option on production server could result in server's performance.

<SafeMode CallStack="true" />
  <customErrors mode="Off" /> 
   <compilation debug="true" />   

Just save the file. No IISRESET needed.
After the above changes the error you see is 'Object reference not set to an instance of an object. at Microsoft.SharePoint.Portal.MySiteMapProvider.get_Home()'

The above error occured because the out of the box 'modify links' points to http://mysitehost/_layouts/MyQuickLinks.aspx .
'my site host' in the above URL will point to your my site HOST URL configured for your server. If we look at the URL, the second part '_layouts/MyQuickLinks' is fine.

Even the modify links works if you replace the 'mysitehost' with any existing site name.
http://any existing site1/_layouts/MyQuickLinks.aspx.
So, now we confirmed that there is a problem with the http://mysitehost/. Okay, now open another IE and copy paste the 'http://mysitehost" and see.
URL is redirected to'http://webapp/_layouts/mysite.aspx'. The logic inside the mysite.aspx causes to create or navigate to 'http://mysitehost/personal/userid'. As we all know, this URL is a my site URL for the person 'user id' . In the first section of this article, we prohibited the 'my sites' according to the client's requirement.

So, all we need to do is modify the 'modify links' URL within the 'my links' link.

Now, lets analyze the 'my links' link existing on the page.
How this control is brought to every page? Ans: Masterpage.
Lets look open the master page in the sharepoint designer in a split mode. I love this mode, as it allows me to highlight the code for a corresponding control in the design mode.
Lets go a head and click on the 'my links' link to highlight the code.
The 'My Links' code shows:

<td class="ms-globallinks">     <SharePoint:DelegateControl ControlId="GlobalSiteLink2" Scope="Farm" runat="server"/></td>    

Now, we are confirmed that, My Links is a delegate control with a control Id: GlobalSiteLink2.
And we also know that, delegates are usually regestered in the sharepoint environment by including them in the 'elements.xml' file of a feature. So, if we can re write the delegate with the logic that modifies the URL of the 'modify links' we are set!

make up for the changes:

  1. 'My site' is a feature, thats added to sharepoint and available at the "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MySite".
  2. If you navigate to the above file system, you will see two XML files. 'Feature.XML' and 'MySiteFeatureElements.xml'.
  3. Open the 'MySiteFeatureElements.XML' to see the tag:
    <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/mylinks.ascx"/>
  4. All we need to do is modify the 'mylinks.ascx' to include the new logic or write a brand new '.ascx' and place in the control templates folder available at the 'C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES'.
    All we need to do is replace the '

    <spswc:mylinksmenucontrol id="MyLinksMenu" runat="server">' with <spswc:<em>yourclassfilename</em> id="MyLinksMenu" runat="server" />

    So lets start writing the actual class and go step by step!

Actual Fix:

Step 1: Create the class to include the logic for the modify links URL.

  1. Open Visual Studio 2005 -> File -> New -> Project -> class library -> Name it as 'ModifyLink'
  2. Add the following code inside the class file
    using System;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.Portal.WebControls;
    namespace ModifyLink{
    public class ExtendedModifyLinks : MyLinksMenuControl
    protected override ArrayList LoadMenuItems()
    ArrayList myArray = base.LoadMenuItems();
    MenuItemTemplate myMenu = (MenuItemTemplate)(myArray [myArray .Count - 1]);
    myMenu.ClientOnClickNavigateUrl = SPContext.Current.Site.Url + "/_layouts/MyQuickLinks.aspx";
    myMenu.ClientOnClickScript = "window.location='" + SPContext.Current.Site.Url + "/_layouts/MyQuickLinks.aspx'";
    myArray .RemoveAt(myArray .Count - 1);
    myMenu.Add(myArray );
    return myMenu;
  3. In the above code, we copied the last link within the 'my links' link and modified it to use a new URL. Once the duplicated array item is ready, we replaced that with the exisiting Menu item in the Array.
  4. Strong name the project and Build. Copy the oupt put dll to 'GAC' and 'C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin' folder.
  5. iisreset.

Step 2: Create the custom '.ascx' delegate control

  • Go to "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\CONTROLTEMPLATES" folder.
  • Copy the "MyLinks.ascx" and paste in the same folder. Rename the "Copy of MyLinks.ascx" to 'ModifiedMyLinksControl.ascx'
  • Modify the ascx to use the above class assembly dll.
    Replace the below line:
    <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

    <%@ Register Tagprefix="SPSWC" Namespace="YourControlClassNamespace" Assembly="YourControlClassAssemblyName, Version=<version>, Culture=neutral, PublicKeyToken=yourToken<keyToken>" %>

    In my case, it is:

    <%@ Register Tagprefix="SPSWC" Namespace="ModifyLink" Assembly="ModifyLink, Version=, Culture=neutral, PublicKeyToken="123rrdfert423"%>
  • Also, replace the below line

    <SPSWC:MyLinksMenuControl id="MyLinksMenu" runat="server" />

    <SPSWC:YourControlClassName id="MyLinksMenu" runat="server" />

    In my case, it is:
    <SPSWC:ExtendedModifyLinks id="MyLinksMenu" runat="server" />
  • Step 3: Writing the feature:
    1. Go to the My site feature in the Features folder:
      C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES\MySite
    2. Backup the existing xml files(copy the two existing xml files: feature.xml and MySiteFeatureElements.xml and paste in the same folder)
    3. Do not touch the feature.xml
    4. Modify the 'MySiteFeatureElements.xml' file to:
      <Elements xmlns=";
      <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
      <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/ModifiedMyLinksControl.ascx"/>
      <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
    5. Save the 'MySiteFeatureElements.xml' .

    install the Feature to a server:

    1. STSADM -o installfeature -filename MySite\feature.xml
    2. If you have 'my site' feature already installed on the server,
      you can do a -force to overwrite the site feature.
      STSADM -o installfeature -filename MySite\feature.xml -force

      for some reason, the -force did not work for me. So I un istalled the feature and re installed.
      to un install: STSADM -o uninstallfeature -filename MySite\feature.xml
    3. As this 'my site' feature is scoped as 'farm' level, need not to activate at a site collection level.
    4. If you think, changing the my site feature directly causes a problem, you can create a new feature( add a new folder inside the 'features' folder and copy paste the 'feature.xml' and elements.xml')
    5. Now the 'modify links' link will target to a new location.