Thứ Năm, 14 tháng 10, 2010

SharePoint 2010 Woes: Avoid comments in your CustomAction-XML for Ribbon customizations

For a customer project I had to add a custom tab to the Ribbon of SharePoint 2010 for a specific library. In this tab I wanted to have several groups of controls. In one group I needed to have a button that triggers the standard upload functionality of SharePoint (Command="UploadDocument"). So far this is a pretty straight forward process.

If you've ever created a CustomAction to add a tab to the Ribbon, you'll agree that you've to write a looot of XML. I personally believe it's a best practice to comment the code one creates. If you have a XML-document with hundreds of lines of mark-up, usually it makes sense to add a comment here and there. In my case my CustomAction-XML was commented like this:


<Groups
Id="Test.Ribbon.Tab.Groups">
  <!--
    Group "New" with Button "Upload"
-->
  <Group
Id="Test.Ribbon.Tab.NewGroup"

>
    <Controls
Id="Test.Ribbon.Tab.NewGroup.Controls">
  <Button
Id="Test.Ribbon.Tab.NewGroup.Controls.Upload"
Command="UploadDocument"

/>
    </Controls>
  </Group>

</Groups>

As you can see I've added a comment above the group "Test.Ribbon.Tab.NewGroup" and with this I've entered a world of pain. The Ribbon and the tab including all groups and controls were rendered without any issues. I also was able to click on the button "Test.Ribbon.Tab.NewGroup.Controls.Upload" and the "Upload Document"-dialog was displayed as expected, but after clicking on the "OK"-button in the dialog, I ran into this well-known error:

clip_image001[7]

In the SharePoint log you can find the following entry related to this error:

System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Web.CommandUI.Ribbon.CreateRenderContext(CUIDataSource uiproc) at Microsoft.Web.CommandUI.Ribbon.Render(HtmlTextWriter writer) at Microsoft.SharePoint.WebControls.SPRibbon.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) at System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output) at System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) at System.Web.UI.Page.Render(HtmlTextWriter writer) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

The method "Microsoft.Web.CommandUI.Ribbon.CreateRenderContext" throws a "System.NullReferenceException". Whoa! To make a long story short, after digging around for several hours I found the reason for this issue: the comment above the group in the CustomAction-XML. Here is what Reflector tells you about the implementation of "Microsoft.Web.CommandUI.Ribbon.CreateRenderContext":

DataNode node4 = uiproc.GetResultDocument().SelectSingleNode("/spui:CommandUI/spui:Ribbon/spui:Tabs/spui:Tab[@Id='" + this.InitialTabId + "']/spui:Groups");

if (node4 == null)

{

node4 = uiproc.GetResultDocument().SelectSingleNode("/spui:CommandUI/spui:Ribbon/spui:ContextualTabs/spui:ContextualGroup/spui:Tab[@Id='" + this.InitialTabId + "']/spui:Groups");

}

Hashtable hashtable = new Hashtable();

if (node4 != null)

{

foreach (DataNode node5 in node4.ChildNodes)

{

XmlAttribute attribute2 = node5.Attributes["Id"];

if (attribute2 != null)

{

hashtable[attribute2.Value] = node5;

} } }

I will not comment on the quality of this implementation, but if you look at XmlAttribute attribute2 = node5.Attributes["Id"]; it becomes clear: the Attributes-property is the reason why I get the NullReferenceException, because for a System.Xml.XmlNode-Object that is a System.Xml.XmlComment this property is null (http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.attributes.aspx). So if you put a comment above your group in your CustomAction-XML you're doomed. Do yourself a favor and don't do it.

I hope this blog-post will save you save some time and headaches. It took me quite some time to figure out the reason why my button in my custom Ribbon-tab wasn't working.

Reference

Created by Sven Häfker

Không có nhận xét nào:

Đăng nhận xét