Showing posts with label Delegate Control. Show all posts
Showing posts with label Delegate Control. Show all posts

Tuesday, January 22, 2013

Determine which SharePoint Web Front End Server you are hitting

Often, we need to identify which WFE server on SharePoint we are hitting when the farm has load balancing.

I decided to create a very simple feature that would display the server name by overriding the GlobalNavigation delegate control of each page that was being accessed across every site collection and sub sites in a web application.

When accessing any page, you will see the server name similar to below:




First, I created the user control, and added one simple label:

<asp:Label ID="lblServerName" runat="server" BackColor="Green" ForeColor="White"></asp:Label>

In the code behind, I put code to check whether the current user is a farm administrator, or if the query parameter, "showserver" has been passed into the url. If either are true, then I display the name of the sharepoint server on the label:

 protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                if (IsFarmAdmin() || ServerParamIsSet())
                {
                    this.lblServerName.Width = new Unit("100%");
                    this.lblServerName.Text = string.Format("{0}", Page.Server.MachineName);
                }
            }
            catch { }
        }



Next, I added an Elements manifest, and specified the path to where the control template will be deployed to on the server, a sequence number lower than 100, and specified it to place the user control in the GlobalNavigation delegate control placeholder.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="GlobalNavigation" Sequence="90" ControlSrc="~/_ControlTemplates/SPServerName/SPServerName.ascx" />
</Elements>


Finally, I created a feature and set it to deploy to the web application.


Installation instructions:
1. Download the wsp I uploaded to http://spservername.codeplex.com/
2. Deploy the solution to your farm
3. Go to the web application features, and enable the SPServerName feature


Notes:
  • There are no changes made to any master page and the feature can easily be turned on and off
  • By default, Farm administrators will always see the server name at the top of the page.
  • Non-farm administrators can also display the server name if they pass in the query parameter "showserver=1"
Ex:

http://myportal.com/siteabc?showserver=1

 

Monday, October 15, 2012

How to create a SharePoint Delegate Control that injects JavaScript to all SharePoint pages

Recently, I needed a way to insert some JavaScript files into all pages in all of the SharePoint site collections and sites under an entire web application.

The thought of changing all the master pages in every site collection seemed not only tedious, but unmanageable. Every time a new site collection is created, we would have to remember to modify the master pages. Also, if a site collection owner decided to use their own master pages, we would have no way of maintaining those either.

So, after banging my head trying to come up with a better solution, I stumbled upon the delegate control!

A detailed description of how it works and what it does can be found here:


The beauty of the delegate control is that you can basically overwrite anything in the master page.

I wanted to add a simple JavaScript file to all of the pages in the master page.

So I started by following the example below. I modified this code in step 12 from the hardcoded script to instead read from a JavaScript file that is located in my layouts folder.

  protected override void CreateChildControls()
        {
            base.CreateChildControls();

            string srcScript = "/_layouts/Company/CompanyScript.js";
            this.Controls.Add(new ScriptLink() { Name = srcScript, Language = "javascript", Localizable = false });
        }


The step by step process can also be found here as well: http://msdn.microsoft.com/en-us/library/ms470880.aspx

Step by step process to creating a delegate control:
1.      Start SharePoint development tools in Microsoft Visual Studio 2010.
2.      On the File menu, point to New, and then click Project.
3.      In Project Types, under Visual Basic or C#, select Empty SharePoint Project.
4.      Type EcmaScriptDelegate as the project name. Click OK.
5.      In the SharePoint Customization Wizard, choose Deploy as a farm solution. Click Finish.
6.      In the Solution Explorer, right-click the EcmaScriptDelegate project. Select Add and then New Item.
7.      In the Add New Item dialog box, click the Code group and choose the Class template. Type EcmaScriptDelegateControl as the Name and then click Add.
8.      Next, you must add a reference to System.Web. In the Solution Explorer, right-click the References folder and select Add Reference. In the Add Reference dialog, click the .NET tab and find System.Web in the list. Click OK.
9.      In the EcmaScriptDelegateControl file that is displayed, add the following using statement.
using System.Web.UI.WebControls;
10.  Change the base class of EcmaScriptDelegateControl to WebControl by modifying the following line.
class EcmaScriptDelegateControl : WebControl

11.  Override the OnLoad method by adding the following code.

protected override void OnLoad(EventArgs e)
{
  base.OnLoad(e);
}

12.  Inside the OnLoad method, add the following code to put JavaScript on the page.

string helloAlert = "alert('Hello, world!');";
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "popup", helloAlert, true);

Now, you have built the delegate control for the project. Next, you will create the Feature to deploy the control.
To create a Feature to deploy the control
1.      In the Solution Explorer, right-click the EcmaScriptDelegate project and select Add and then New Item.
2.      In the Add New Item dialog box, choose the Empty Element template and type EcmaScriptDelegateFeature as the Name. Click Add.
3.      Insert the following XML inside the Elements element. The Id attribute identifies the delegate where the control is rendered. The ControlAssembly and ControlClass attributes are unique to your control. For more information about how to find the full assembly name, see How to: Create a Tool to Get the Full Name of an Assembly.


The most flexible thing about the delegate control is that it can be defined at the 4 scopes:

·         Web
·         Site collection
·         Web application
·         Farm

Thus, I can set the feature of this scope to activate at any level, and have it immediately show up in ALL of my pages.

The best part is, when you deactivate the feature, it is completely gone and has no impact! No messing with the master page!

JavaScript to add a global link near Site Actions menu in SharePoint 2010

The goal is to add a link next to the Site Actions menu that would always lead back to the portal home, similar to below.




Using IE Developer Tools, I was able to determine the location where I wanted to place my link was inside of the RibbonContainer-TabRowLeft element.

You can modify the master page and inject the following javascript to achieve this:

Read my following post to see how to make this work on all site collections across a web application by using a delegate control!




ExecuteOrDelayUntilScriptLoaded(ExecuteDefaultLoad, "sp.js");

function ExecuteDefaultLoad()
{

 var isWikiEdit = false;
 if ( document.forms[MSOWebPartPageFormName]._wikiPageMode != null )
 {
  if( document.forms[MSOWebPartPageFormName]._wikiPageMode.value == "Edit" )
    {
     isWikiEdit = true;
    }
  }

 var inDesignMode = document.forms[MSOWebPartPageFormName].MSOLayout_InDesignMode.value;
 if (inDesignMode == "1" || isWikiEdit) 
 {  
  // this page is currently in edit mode 
 } 
 else 
 {  
  AddHomeLink();
 } 
}


function AddHomeLink()
{
 var ribbonContainerRowLeft = document.getElementById("RibbonContainer-TabRowLeft");
 if( ribbonContainerRowLeft != null )
 {
  if( ribbonContainerRowLeft.children != null && ribbonContainerRowLeft.children[0] != null )
  {  
  var newSpan = document.createElement("span");
  newSpan.innerHTML='<a class="ms-menu-a" style="cursor:pointer;white-space:nowrap;"    href="javascript:;" title="SharePoint Portal Home" onclick="window.location=\'/\';return false;"><img src="/_layouts/images/hhome.png"  border="0px"/></a>';
  newSpan.className = 'ms-SPLink ms-SpLinkButtonInActive ms-welcomeMenu';
  newSpan.onmouseover= function() {  this.className = "ms-SPLink ms-SpLinkButtonActive ms-welcomeMenu"}; 
  newSpan.onmouseout= function() {  this.className = "ms-SPLink ms-SpLinkButtonInActive ms-welcomeMenu"}; 
  ribbonContainerRowLeft.insertBefore(newSpan, ribbonContainerRowLeft.children[0]);
  }
 }
}