Friday, 3 May 2013

SharePoint 2013 - Delegate Controls - Beware of throwbacks to the SharePoint 2010 14 Hive

Delegate controls are particularly useful in SharePoint when you want to add functionality to all pages within your site without changing the master page. For example, if you want to add an external JavaScript library (such as JQuery) to every page, you can do this easily by registering a delegate control. An example of this approach can be seen here: http://blogs.msdn.com/b/kaevans/archive/2011/04/06/adding-jquery-to-every-page-in-sharepoint-with-delegate-controls.aspx

A delegate control is registered through an Elements.xml with a ControlSrc property pointing to your custom delegate control.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead"
           Sequence="100"
           ControlSrc="~/_controltemplates/MyAppName.Core/MyDelegateControl.ascx" />
</Elements>
Problem is, the above code will work in SharePoint 2010 but NOT in SharePoint 2013. You will get an exception like the following:
DelegateControl: Exception thrown while building custom control 'Microsoft.SharePoint.SPControlElement': System.Web.HttpException (0x80004005): The file '/_controltemplates/MyAppName.Core/MyDelegateControl.ascx' does not exist.    
 at System.Web.UI.Util.CheckVirtualFileExists(VirtualPath virtualPath)    
 at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)    
 at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)    
 at System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean ensureIsUpToDate)    
 at System.Web.UI.TemplateControl.LoadControl(VirtualPath virtualPath)    
 at Microsoft.SharePoint.Utilities.SPUtility.CreateUserControlFromVirtualPath(TemplateControl tctlPage, String sControlPath)    
 at Microsoft.SharePoint.SPControlElement.BuildCustomControl(TemplateControl tctlPage, String sControlAssembly, String sControlClass, String sControlSrc, XmlNode xnElementDefinition, SPFeatureDefinition featdefElement, String sElementId)    
 at Microsoft.SharePoint.WebControls.DelegateControl.BuildCustomControlResilient(SPControlElement ctlelemDefinition)

The control itself DOES exist - so this is a somewhat misleading exception. Looking at this issue more closely, SysInternals ProcessMon will show you the way:



Looking closely, it is actually referencing the 14 Hive rather than the 15 Hive as a throwback to SharePoint 2010. So to fix this, you simply need to update your ControlSrc to include 15 in the path:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead"
           Sequence="100"
           ControlSrc="~/_controltemplates/15/MyAppName.Core/MyDelegateControl.ascx" />
</Elements>
As an alternative, you could also use a Module and a custom action for registering a ScriptLink to something like jQuery or knockout.js.

DDK

7 comments:

Unknown said...

Thanks a lot !

Unknown said...
This comment has been removed by the author.
Dinesh said...

I have a issue with this in SP2010,
After adding new javascrpt code using Delegate control(AdditionalPageHead), code working fine but all other button on every page are not working.

I am following this post
http://blogs.msdn.com/b/kaevans/archive/2011/04/06/adding-jquery-to-every-page-in-sharepoint-with-delegate-controls.aspx
and i am sure the button issue are comming after activating feature,
Please help me on this.

Thanks,
Dinesh

Unknown said...

Thank you very much...saved my day

Maksym Dykhtiaruk said...

Thanks David, I didn't realize that was reading your blog :)

Cheers,
Oaktoner

Martin Pyman said...

Thanks! This made my weekend

adogg said...

+1 saved me. Having to pull out procmon to figure this out is not something that one should be forced to do, but glad you did.