Tuesday, December 8, 2009

Starting SharePoint 2010 Site Workflows from code

Background

One of the cool new features of  SharePoint 2010 is Site Workflows. As you probably know, in SharePoint 2007 a workflow can only be associated with a list or a document library. While this functionality is useful, sometimes a “site wide” workflow is called for. This leads to us developers getting creative and producing  approaches such as creating a list called “Site Workflows” and creating items in it that have “start on create” workflows attached to them. In SharePoint 2010 Site Workflows provide an elegant solution for this common scenario.

The Code

 using (SPSite site = new SPSite("http://moss2010beta")) //get the site
     {

           using (SPWeb web = site.OpenWeb()) // get the web
                  {
                        //find workflow to start
                        var assoc = web.WorkflowAssociations.GetAssociationByName("Demo Site Workflow", CultureInfo.InvariantCulture);

                        //this is the call to start the workflow
                        var result = site.WorkflowManager.StartWorkflow(null, assoc, string.Empty, SPWorkflowRunOptions.Synchronous);

                 }
    }    


As you probably have noticed, the API call to start a site workflow is not much different form the call to start a list workflow. A new overload was added to SPWorkflowManager.StartWorkflow() method. This is the method we call to programmatically start our site workflow. One new parameter of this overloaded method which deserves a mention is the runOptions parameter, which expects a SPWorkflowRunOptions enumerator. See MSDN page for details.


Possible uses of the code



I believe that Site Workflows in SharePoint 2010 bring even more flexibility to an already powerful workflow infrastructure that the platform currently offers. There are many examples I can think of where one would use site workflows, but one specific one is on the top of my list. Say you have an application built on top of SharePoint 2010, which, when installed, adds whole bunch of custom lists, event handlers and workflows to the site. Now imagine if some of the major “events” or “states” of that application are implemented as site workflows created in SharePoint Designer 2010, which at any given point are started from event handlers or other custom code. Say that one such site workflow is run by the application when a document of a specific content type is checked in to the system by a user in a specific SharePoint group. The default site workflow is set to notify the content steward by email. If one of the SharePoint Designer 2010 savvy users wants to change that to create a whole review process or create a task or a list item in another list, they can. The point is,  Site Workflows can be used to add extensibility points to an application build on top of SharePoint, which require only SharePoint Designer power user to take advantage of.  In conclusion, I hope that this article will help someone out there build smarter solutions to common business problems on top of the upcoming  SharePoint release.


Sample Code Download: SiteWorkflowStarter.zip

Tuesday, November 17, 2009

Useful SharePoint Designer Activities and SharePoint Designer 2010

It did not come as a surprise that Microsoft has added functionality into SPD 2010 that some of the activities created as a part of my open source project on CodePlex accomplished. At this year’s SharePoint Conference in Las Vegas I made it a point to go and check out some of the SPD 2010 sessions. I was pleasantly surprised by the new functionality that was added to SPD and you got to love the ribbon interface. On a sad note the most popular set of activities on the CodePlex project, the Permission Activities, are now available out of the box. There was a moment during one of the SPD 2010 demos when the guy said “and now we are going to set permissions on this item” I thought to myself “Oh, well, I’m just going to have to find another niche for the open source project”. From what I saw not all of the functionality provided by my project is in SPD 2010. For instance, “Start another workflow” is not part of the new functionality. Once I get my hands on a stable Beta of WSS and SPD 2010 I will create a roadmap for the still needed custom activities that may be implemented in the next version of the Useful SharePoint Designer Activities Project. Stay Tuned.

Tuesday, September 22, 2009

SharePoint List Query performance gotcha

As i recently discovered, there is BIG difference between calling SPList.GetItemById() and SPList.Items.GetItemById(). The latter causes all items to be loaded into memory and then filtered. This can cause severe performance issues for lists with large number of items.
Below is the code that takes 5 hours to run on a dual core box when run against a list with 5500 items.

   1:  SPList theList = GetList(); 
   2:   
   3:  List<int> itemIds = new List<int>();  
   4:   
   5:  foreach(SPListItem item in theList.Items)   
   6:  {  
   7:   itemIds.Add(item.ID);
   8:  } 
   9:   
  10:  foreach(int itemId in itemIds)  
  11:  { 
  12:   
  13:    SPListItem theItem =  theList.Items.GetItemById(itemId); //this will cause severe performance issues for large lists
  14:   
  15:  }

To fix this issue we need to change the code in line 13 to:


  13:  SPListItem theItem =  theList.GetItemById(itemId);

Now the above code will run in minutes.

I wish MSDN documentation on this topic was more clear. That would save me from putting in a couple of late nights at the office.


Monday, December 3, 2007

Disable event firing in SharePoint when updating a list item outside of an event handler

As you probably know, when developing Event Handlers for SharePoint you have the option turning off event firing. This functionality is exposed through SPEventReceiverBase.DisableEventFiring() Method . This is very useful when you are updating the item from within the event handler and do not want an infinite loop to occur.


During my last project i discovered that you cannot disable event firing from code that is not part of an event handler, because DisableEventFiring() is an internal instance method. Still, i was determined to find a solution. So i whipped out Reflector and started investigating. Upon disassembling Microsoft.Sharepoint.dll, I discovered that the above mentioned method actually sets a static, thread-specific, property of SPEventManager class called EventFiringDisabled. SPEventManager class is responsible for instantiating event handlers and delivering events to them. Because this class is marked "internal", it is not intended for use by SharePoint API consumers . But what is a good solution without some HACKS? :) I used reflection to set EventFiringDisabled property.


Below, you will find my solution neatly wrapped in a class. Please use at your own risk.



using System;

using
System.Collections.Generic
;

using
System.Text
;

using
System.Reflection
;

using
Microsoft.SharePoint
;


/// provides access to the internal Microsoft.SharePoint.SPEventManager class by using reflection

/// sample usage:

/// SPEventManagerWrapper.DisableEventFiring();

/// SPList myList = SPContext.Current.Web.Lists["Shared Documents"];
/// myList.Items[0].Update();

/// SPEventManagerWrapper.EnableEventFiring();

public static class SPEventManagerWrapper

{

private static readonly string _className = "Microsoft.SharePoint.SPEventManager"
;

private static readonly string
_eventFiringSwitchName = "EventFiringDisabled"
;

private static
Type _eventManagerType
;




/// gets the status of event firing on the current thread

public static bool
EventFiringDisabled

{

get { return GetEventFiringSwitchValue();
}

}


private static
Type EventManagerType

{

get

{



if (_eventManagerType == null
)

GetEventManagerType()
;



return
_eventManagerType
;



}

}



/// enables event firing on the current thread

public static void
EnableEventFiring()

{

SetEventFiringSwitch(
false)
;



}



/// disables sharepoint event firing on the current thread

public static void
DisableEventFiring()

{

SetEventFiringSwitch(
true)
;



}





/// sets the event firing switch on Microsoft.SharePoint.SPEventManager class using reflection

private static void SetEventFiringSwitch(bool value
)

{

PropertyInfo pi
= EventManagerType.GetProperty(_eventFiringSwitchName, System.Reflection.BindingFlags.Static System.Reflection.BindingFlags.NonPublic)
;



pi.SetValue(null, value, null)
;



}



private static bool
GetEventFiringSwitchValue()

{

PropertyInfo pi
= EventManagerType.GetProperty(_eventFiringSwitchName, System.Reflection.BindingFlags.Static System.Reflection.BindingFlags.NonPublic)
;



object
val = pi.GetValue(null, null)
;



return
(bool)val
;



}



private static
Type GetEventManagerType()

{

_eventManagerType
= typeof(SPList).Assembly.GetType(_className, true)
;



return
_eventManagerType
;

}

}