Creating a manual resync context menu for Sitecore's SharePoint Integration Framework

Posted on Oct 07, 2014 in Technical  | No comments

When developing against the SharePoint Integration Framework I have found that waiting for synchronisation events can destroy my development rhythm, so I put together a context menu so that I can run the sync on demand.  This is pretty handy so I thought I’d share.

There are 3 moving parts to this:

  1. A context menu item
  2. A command
  3. Some code

Let’s have a look…

The Context Menu Item

I have had some difficulty getting a completely new Context Menu to work in Sitecore so I tend to augment the “Default” one.  Try out the following:

  1. Log into Sitecore’s Desktop shell
  2. Switch your database to “Core”

  3. Open the Content Editor
  4. Navigate to /sitecore/content/Applications/Content Editor/Context Menues/Default
  5. Create a new item based off the Menu item template (/sitecore/templates/System/Menus/Menu item) and position it wherever you like
  6. Set a cute Icon and the Display name (if different from the item name)
  7. Set the Message – you can mine the system’s various built-in messages here to perform tasks normally found elsewhere (check the \App_Config\Commands.config file for a list of the OOTB messages) for the purposes of this exercise I created a new one: sharepointitem:sync(id=$Target)

    The message name is the sharepointitem:sync part; the remaining part tells Sitecore to set the item context from the click target – we’ll need that later.

The Command

We’re going to use a config file to map the command to a new class with code to handle execution and display duties.

  1. In your VS project navigate to \App_Config\Include
  2. Edit an existing patch file or create a new one called spsync-commands.config
  3. Put the following into it:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    	<sitecore>
    		<commands>
    			<command name="sharepointitem:sync" 
    				type="Demo.SharePoint.SynchroniseSPCommand,Demo" />
    		</commands>
    	</sitecore>
    </configuration>
    
  4. That type attribute is pointing to a class we are going to create in a second. If you don’t recognise the format it’s a fully-qualified type name, including the full namespace and the assembly, in this case Demo.dll
    There’s no special patch attribution required here – the Configuration system will recognise that the command doesn’t exist by trying to match all the attributes with an already existing element at the same element hierarchy; when it fails to find one it will simply add this in at the end of the parent element.

The Code

The code takes the form of a class that inherits from Sitecore.Shell.Framework.Commands.Command and overrides a number of methods:

  • Default constructor – no implementation
  • Execute – respond to the click event
  • GetSubmenuItems – an opportunity to dynamically generate a submenu
  • QueryState – an opportunity to evaluate whether the item is valid in the current context and take appropriate action

I have included the whole class below:

namespace Demo.SharePoint
{
	[Serializable]
	public class SynchroniseSPCommand : Command
	{
		public SynchroniseSPCommand() { }

		public override void Execute( CommandContext context )
		{
			using ( new SecurityDisabler() )
			{
				var options = ProcessIntegrationItemsOptions.DefaultOptions;
				options.Recursive = true; 
				options.AsyncIntegration = false;
				options.Force = true;

				for ( int i = 0; i < context.Items.Length; i++ )
				{
					context.Items[i].DeleteChildren();
					SharepointProvider.ProcessTree( context.Items[i], options );
				}
			}
		}

		public override Sitecore.Web.UI.HtmlControls.Control[] GetSubmenuItems( CommandContext context )
		{
			return null;
		}

		public override CommandState QueryState( CommandContext context )
		{
			var id = ID.Parse( "{E3E23DCC-CA55-4049-BBF0-B503023517C6}" );

			if ( context.Items.All( i => i.TemplateID == id ) )
				return CommandState.Enabled;

			return CommandState.Hidden;
		}
	}
}

Allow me to explain each of the methods briefly:

  • QueryState – this checks all of the potentially selected items (there may be more than one) and makes sure that they are based on the SharePoint Integration Configuration template.  It’s OK, in this case, to hard code the ID but a more dynamic approach may be called for in your scenario.  If all of the context items are of the correct type I return CommandState.Enabled to allow the user to select the action, otherwise I hide my menu item using CommandState.Hidden. There are other options, but they didn’t suit me this time.
  • GetSubmenuItems – I could have simply left this off as I don’t need any submenu.  Simply return null to indicate this or don’t bother with the override.
  • Execute – this is where the party happens, first creating a new options object and setting some values, then clearing out the child nodes and re-populating the tree.

<rant>
I want to mention that ProcessIntegrationItemsOptions.DefaultOptions returns me a new object via the property getter.   I only know this because I looked in reflector to see what was going on here.  This is terribly bad practice and please don’t do that in your code. Plainly, it appears as though we are referencing a static object and then changing its values – we aren’t but that’s what it looks like; which is why you shouldn’t do what this developer did.  This should have been a method.
</rant>

And there you have it!