My career in technology

Not long ago I completed some work for a client that had some interesting things about it, including some mysterious errors, one of which remains unresolved. Maybe you can help solve the mystery!

Requirements:

The client has an existing workflow for creating project-based document collaboration sites.

  1. Users fill out a form (create a new item in a custom SharePoint list).
  2. Once they have completed filling out the details of the project authorization request, the user manually starts a workflow on the request. (This allows users to start working on a request, save the incomplete request, and return to the request with additional details until all the relevant information is added to the form.)
  3. The workflow (created in SharePoint Designer) alerts the relevant manager to review the request, and either kick the request back to the user (denied, requires more information, and so forth), or approve the request.
  4. The workflow then alerts the department’s SharePoint power user that a site request has been approved.
  5. The power user then creates the site from a template, placing the site in the site structure under the appropriate line-of-business site, based on the information provided in the form.
  6. The power user then has to make a large number of manual changes to the site so that all of the users, lists, and web parts are properly configured.

The client wants to continue to be able to edit the workflow as business requirements change, and to modify the site template as needed, but wants as many as possible of steps 4-6 to be automated.

So let’s see what I came up with…

Note: I hate revisionism in blogs, but my first attempt to post the first section of code came in at over 2000 words, just too darned big. Plus, I’ve been monkeying with the code to improve its efficiency, readability, and adherence to “Single Responsibility”. So I’ve broken my original Part one post into two parts and I’m using the revised code, to give readers a better experience and to provide better code.  Links to the other parts in the series are at the bottom of the post!

Since the client needed to be able to modify the workflow in SPD, creating a new workflow in Visual Studio was out of the question. But SPD doesn’t have the tools to perform the tasks that were needed to meet the requirements.

Enter the Event Handler.

namespace MyEventHandlerName
{
    public class ItemUpdatedEventHandler : SPItemEventReceiver
    {

What event should the event handler programmatically handle? Well, I want things to happen only after the request (the SPListItem) is approved. Looks like I want to handle the ItemUpdated event.

        public override void ItemUpdated(SPItemEventProperties EventProperties)
        {
            SetInitialClassLevelVariables(EventProperties);
            try
            {
                //If it is passes all checks, run applicable commands
                if (CheckRequirements())
                {
                    DoAllSiteCreationSteps();
                }

                if (NeedToUpdateSubsites)
                {
                    DoUpdateItemInSubsiteLists();
                    DoChangeFactorFilters();
                }
                if (NeedToModifyExistingSite)
                {
                    //Run a few commands to prepare it for new data
                    //ToDo#1 set indicators back to not completed.
                    //Requirements and errorhandling for this not defined so this is not implemented.
                    //DoModifyExistingSite();

                    //ADD WEB SITE ADDRESS TO THE FORM
                    DoUpdateFormWithWebsiteAddress();
                }
            }
            catch
            {
            }
            finally
            {
                //Regardless, run the basic ItemUpdated commands
                base.ItemUpdated(properties);
            }
        }

And I’m going to need references to the various methods and objects in other namespaces, so it all starts here:

using System;
using System.Data;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.IO;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Portal.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;

My first call in the ItemUpdated() override is SetInitialClassLevelVariables(EventProperties), which sets some class-level variables, a few items I’ll need to have available throughout the event handler.

        private void SetInitialClassLevelVariables(SPItemEventProperties EventProperties)
        {
            try
            {
                if (EventProperties.WebUrl.IndexOf("http://DevelopmentServer") == 0)
                {
                    //Dev
                    SiteserverURL = "http://DevelopmentServer";
                }
                if (EventProperties.WebUrl.IndexOf("http://StagingServer") == 0)
                {
                    //Staging
                    SiteserverURL = "http://StagingServer";
                }
                if (EventProperties.WebUrl.IndexOf("http://LiveServer") == 0)
                {
                    //Live
                    SiteserverURL = "http://LiveServer";
                }
                properties = EventProperties;
            }
            catch
            {
            }
        }

I want to be able to deploy the same code on the Development, Staging and Live servers without having to make manual changes, and the code needs to be able to tell which server it is on all by itself. I also want the contents of the SPItemEventProperties available to a lot of parts of my code without having to pass copies of the properties around.

Since one of the coding principles I try to code by is SRP, the “Single Responsibility Principle”, I make each method do as few things as possible, so many methods are called during the event handler’s steps, and they need access to a consistent set of data. Unlike local variables created within the methods which are only available within the method, the class-level variables are available anywhere in the class.

namespace MyEventHandlerName
{
    public class ItemUpdatedEventHandler : SPItemEventReceiver
    {
        //Set up Class-scoped variables
        string serverURL;
        SPItemEventProperties properties;

Now that the code is aware of where it resides, and has access to the event properties it needs, The next step is to validate that the code actually needs to do something.

We’ll walk through CheckRequirements() in Part Two.

I’d love your feedback. Is there something you think I could be doing better? Are there questions about the code I haven’t answered? Am I full of it? Let me know! Feel free to use these code samples in accordance with my usage policy.

You are reading Part One.
Check out Part Two here (The Decision).
Check out Part Three here (If You Built It…).
Check out Part Four here (…They Will Come).
Check out Part Five here (Bring ‘Em All In).
Check out Part Six here (Ride the CAML!).
Check out Part Seven here (Pointing The Way).
Check out Part Eight here (Taking Part!).
Check out Part Nine here (Deconfigured).
Part Ten (The Log Blog) is coming!

More posts about SharePoint.

Comments on: "Automated SharePoint Site Provisioning Solution – Act One (The Setup)" (7)

  1. Hi D.,
    Excellent article series. I would have one question though: Considering that you would need to be able to change the WF via SPD, have you considered defining a custom activity that could be reused, instead of the handler?

    Regards,
    C. Marius

    • Thanks!

      Given the very specific nature of the site template and the changes needed for each project, we don’t forsee the need to reuse the what the event handler does. I could have built a more generic approach as a custom activity, but I suspect it would have meant more upfront work and additional time for a possible reuse which so far has not shown any hint of being needed.

      Of course, if you had a need for reusable code including some of the functions I describe in the series, these code examples could certainly be used in a custom activity.

  2. […] Automated SharePoint Site Provisioning Solution – Act One (The Setup) April 20102 comments […]

  3. […] Automated SharePoint Site Provisioning Solution – Act One (The Setup) […]

  4. […] Automated SharePoint Site Provisioning Solution – Act One (The Setup) […]

  5. […] Automated SharePoint Site Provisioning Solution – Act One (The Setup) […]

Leave a comment