Automating business processes in SharePoint: SharePoint Event Receivers (Part 2 of 3)

Right, here is the second part of a three-part series on automating business processes in SharePoint. We will explore three different methods of doing Business Process Management, or BPM, using SharePoint and available tools.

The scenario is a simple helpdesk application in which users should be able to send emails and have an issue be raised and sent to an appropriate agent for resolution. We will use an email enabled list to receive emails and then use automated processes to route that email into the issue tracking system. The system will make sure that the issue is tracked and escalated as appropriate.

Here are the links to the entire series:

Automating business processes in SharePoint: SharePoint Designer Workflows (Part 1 of 3)
Automating business processes in SharePoint: SharePoint Event Receivers (Part 2 of 3)
Automating business processes in SharePoint: Visual Studio Workflows (Part 3 of 3)

Oh, and make sure you subscribe to the feed to make sure you get updates and new articles as they become available.

A few things worth noticing. This series will not result in a production ready system. It is meant to show different aspects of process automation, not to create the best method of doing a specific task such as creating a help desk application. The series is meant to show the entire process of creating the application.

First of all, lets draw a simple diagram to explain how the system is supposed to work.

IssueFlow

So, in a few short sentences:

1. Receive a new email and start a new support issue (handled by SharePoint designer)

2. Escalate issue and find an available operative to handle the case (handled by an event receiver)

3. Update the issue, and if it is resolved, send a message to the customer. If not, go to step 2. (handled by a custom workflow in Visual Studio)

If you are going to do this in a production environment, don’t. Basically what we are doing here is demonstrating different aspects of business process management, not doing a best practice thing. In a production system you would likely want to do all of this in a state machine workflow, or at least not do three different approaches to automation in one single system.

On to lesson two

A recap from lesson one

In the last article we looked at using SharePoint Designer Workflows to route and categorize incoming email to our help desk system. We did this by creating different email enabled lists that had workflows attached. These workflows created new items in our issue list and categorized them by setting a Choice field to the correct value, depending on which list received the email, support or invoice. We should at this point have a simple email receiver and routing system ready for some additional development.

Solution overview

This lesson will focus on developing your very own custom event receiver, specifically List Item Receivers. The audience for this article are developers or aspiring developers.

We will be making code to handle an issue item being created or modified in the issues list we created in part 1. When that happens we will find an available employee to handle the issue, depending on whether the employee handles support or invoice issues.

Note that you will need access to Visual Studio and set up a project according to the method described in the post Basic setup of SharePoint Visual Studio project.

Solution walkthrough

Setup

Ok, as stated you want to start off where we left off in the last article. If you haven’t set up that environment, go ahead and do so now. I will wait. Link right on top. I’ll just sit right here and fiddle with some other important piece of work.

Back so soon? Oh, good, time to move ahead.

For our next step in our helpdesk application we want to implement some method of assigning issues to employees. Each issue will be in one of two categories, namely support or invoice, and as such we need to classify those employees that will handle each category accordingly. To do so we need to make a few adjustments to our users list.

This is the point where you will learn why it was a great idea to make your ‘Issue Type’ field a site column rather than a list column. What you need to do next is to add that field, or create a new one if you didn’t use the site column, to the users column. To do this, go to the People and Groups, likely located at the bottom of your quick launch menu, or at /_layouts/people.aspx. This is the list of users in your site.

Note the use of the word ‘list’ in the last sentence. It is there for a very specific reason. The People and groups list is just like any other SharePoint list and that means you can modify it, just like any other SharePoint list. Go to Settings and List Settings and then add the Issue Type column, either from existing site columns if you took my advice or create a new column.

What this does is allow you to add an issue type to any user on your site. You employees may then be assigned to one of the issue types, depending on who solves what issues.

Genius, eh?

Final task for this article is to modify the Issues list. We need some way of knowing who is assigned to each issue, so we must add a Person field to the Issues list. In real life you would likely create a better filtering mechanism and provide a distinct SharePoint group to contain employees handling issues, but for now we shall just use the Members group. So, create a new field in the Issues list of type Person or group, give it a decent name, and set the ‘Choose from’ property to be ‘Members’. I named my field ‘Assigned to’. See screenshot below for how the field should look.

Step-2

Now it is time to develop our feature and our event receiver code.

Step 1: Set up Visual Studio and WSPBuilder

Ok, this should be a breeze. Go to the post Basic setup of SharePoint Visual Studio project, but skip down to the bonus feature of that post and install WSPBuilder. You can skip that part if you like, but it will take you a lot longer to write and deploy the files yourself. I use WSPBuilder here because the solution is rather simple in itself, so if I was the explain all the steps of creating and deploying a feature at this point we would spend most of this post doing that. I’ll rather get down to the interesting bits and leave the gritty details to WSPB
uilder.

If you want me to write a separate post on how to create features, let me know, but I am sure smarter people than I have already written far better articles on that which could be found using Google.

Set up and come back. I’ll still wait for you before we move on to…

Step 2: Create the feature files.

In order for our event receiver to be activated and attached to our list we need to deploy it using a SharePoint feature. So, start a new Visual Studio solution, a WSPBuilder Project. Call it whatever you like, I call mine HelpDesk.

Step-1

Next, add a new item to the project by right-clicking the Project in the solution explorer and click Add->New item. Select an Event Handler feature, give it a decent name and description and make sure the scope is set to web.

Voilá, WSPBuilder has set up everything you need to start coding. Or at least, very close.

WSPBuilder will, when creating an EventHandler feature, map only the ItemAdding method by default. We need to specify that we will be using the ItemAdded and ItemUpdated receivers. I will explain why we want to use these methods in step 3.

Luckily, this is a very simple change. If you open the elements.xml file in the 12\Template\Features\YourFeature folder of your solution you will se a Receiver element with a type of ItemAdding. You need to change that element and add another, similar element. Look at the screenshot below for details:

step-2b

Basically we are telling SharePoint that we want to handle ItemAdded and ItemUpdated events for any list of type 100 (custom lists), as well as which assembly and class will handle the events. You assembly strong name may be different from mine, but don’t worry, if you used WSPBuilder it will be correct.

Step 3: Write the ItemAdded and ItemUpdated code.

We want to do something to an item once it has been added or updated. As such we want to override two methods, namely ItemAdded and ItemUpdated.

If you open the .cs file in your FeatureCode folder created by WSPBuilder when adding the EventHandler you will see that by default WSPBuilder adds feature receivers for four receivers, ItemAdded, ItemAdding, ItemUpdated, and ItemUpdating. You can safely delete the -ing receivers as we will not be using those here, but I would still like to take a few short moments to explain the differences.

The -ed receivers (addED and updatED) are asynchronous, meaning they happen after the fact, i.e. after something has been added or updated, or any other event followed by -ed. The -ing receivers (addING and updatING) are synchronous, meaning they happen before the fact, or actually, as part of the fact.

This means there are several distinct tasks that you would want to do with each receiver type. For instance, if you would like to prevent something happening to an item, for instance not update or add it at all or anything else that should happen before the item is actually updated, then you should go for the -ing receivers.

A great example of this is implementing field level security. Let’s say you have a list where you allow people to edit items, but you do not want anyone but managers to alter the ‘approved’ field. To enforce security you would need to implement an ItemUpdating receiver in which you check if there is an attempt to update the ‘approved’ field, and if so you need to check it the user making the attempt is a manager. Any other method, especially modifying the user interface by removing fields from the web form or hiding it using JavaScript or CSS does not actually handle security and anyone, using tools such as SharePoint Manager or other methods that modify items using the SharePoint Object Model, will be able to modify the fields. Security through obscurity is rarely a good idea.

I will write, at a later point in time, a longer article regarding event receivers. For now, back to our task at hand.

What we want to do in our event receivers is to find an available employee to handle an issue. We have already added the Assigned to field, we have made sure each employee can be categorized according to what issues they handle, so all we really need to do is find an available employee and set the ‘Assigned to’ field of the item to that person. We need to use some CAML to filter our results, but hey, you should know your CAML, right? Right. I’ll explain anyway, as well as include some tips on making CAML queries a breeze.

Here’s the code, I will explain each step afterwards. Oh, and this goes in the .cs-file in the FeatureCode folder.

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using Microsoft.SharePoint;
 5
 6 namespace HelpDesk
 7 {
 8 class IssuesHandler : SPItemEventReceiver
 9     {
 10 public override void ItemAdded(SPItemEventProperties properties)
 11         {
 12             AssignIssue(properties);
 13         }
 14
 15 public override void ItemUpdated(SPItemEventProperties properties)
 16         {
 17             AssignIssue(properties);
 18         }
 19
 20 private void AssignIssue(SPItemEventProperties properties)
 21         {
 22 try
 23             {
 24 string issueType = properties.ListItem["Issue Type"].ToString();
 25 SPList employeesList = web.Lists["User Information List"];
 26 SPWeb web = properties.ListItem.ParentList.ParentWeb;
 27
 28 SPQuery employeeQuery = new SPQuery();
 29 StringBuilder oSb = new StringBuilder();
 30
 31                 oSb.Append("");
 32                 oSb.Append(" ");
 33                 oSb.Append(" ");
 34                 oSb.Append(" " + issueType + "");
 35                 oSb.Append(" ");
 36                 oSb.Append("");
 37
 38                 employeeQuery.Query = oSb.ToString();
 39
 40 SPListItemCollection availableEmployees = employeesList.GetItems(employeeQuery);
 41
 42 if (availableEmployees.Count > 0)
 43                 {
 44 int randomEmployee = new Random().Next(availableEmployees.Count);
 45                     properties.ListItem["Assigned to"] = web.SiteUsers[availableEmployees[randomEmployee]["Title"].ToString()];
 46
 47 this.DisableEventFiring();
 48                     properties.ListItem.Update();
 49 this.EnableEventFiring();
 50
 51                 }
 52             }
 53 catch
 54             {
 55             }
 56
 57
 58         }
 59
 60
 61     }
 62 }

 

 

Right, not that hard at all.

First of all, notice that we use the same code for both ItemAdded and ItemUpdated. You may want to implement another method, but think of this as an illustration. In our case we reassign the issue every time it is updated. Perhaps you only want to reassign the issue if some specific event occurs, for instance the current employee makes a selection saying they can not handle this issue.

I have created the AssignIssue method to handle all the assignment. It should be straight forward, but let’s go through the code.

Lines 22 and 53 adds basic error handling. You must implement better error handling. These aren’t the droids you’re looking for.

Lines 24-38 sets up some variables and creates a CAML query to find eligible employees from our site users. I will explain the CAML and why I chose to use a StringBuilder object to buld the query in a moment, but let’s just complete the code first.

Line 40 finds the eligible employees and stores them in a SPListItemCollection.

Line 42 checks that we actually have any employees that can handle the issue.

Line 44 finds a random employee from our eligible list of employees. You may want to find a better method of selecting the right employee, but I want to make this simple.

Line 45 sets the Assigned to field we created earlier to the random eligible employee user we found in line 44.

Lines 47-49 may seem a bit strange. First we disable eventfiring, then we call ListItem.Update() and then we re-enable event firing. The reason why we want to disable event firing while we do the ListItem.Update() is to prevent an eternal loop. If we did not disable event firing then ListItem.Update() would fire a new ItemUpdated event, and execute the same code again. Not good.

That is basically it.

Back to the stringbuilder issue. You see, building CAML should be as natural to you as breathing. CAML is really fundamental to developing in SharePoint. Learn CAML, love CAML, or stop developing for SharePoint, you will not get very far or be any good.

That being said, I do take shortcuts, mainly for productive reasons. The query in this instance is very easy and can be created fast, but what happens when you have some intricate queries with multiple levels? It can quickly get frustrating. I will share with you what I do in these cases.

One method of finding a query such as this really fast, if you do not want to build it by hand, is to set up the view in the web UI to work the way you want. Include filters, sorting, grouping, whatever you want. Then, use the wonderful and free Stramit CAML Viewer to find the CAML query that generates just that view. To use it, start the program, connect to your site, find your list and then your view and you will see the CAML in the right hand pane.

And the stringbuilder part? Well, there is a link, right above your CAML, that produces the entire StringBuilder code for you. Just click it and copy+paste the code into your class. Saves a ton of time. I’ve included a screen shot below.

step-3

Note that you may want to modify the stringbuilder a bit to get dynamic values, such as I have done in line 34. You get the point, you’re a smart person 🙂

Step 4: Build and deploy

WSPBuilder, being the fantastic tool it is, will handle all the build and deploy you need, most of the time. To test your masterpiece, right-click your project in the Visual Studio solution explorer and choose WSPBuilder->Build WSP and then WSPBuilder->Deploy. the only thing you need to do now to test is to go to your chose site and activate the feature. Since the feature is web scoped, you will need to activate it from the Site settings->Site Administration pane. Link is called Site features. You should find your event handler feature there.

Congratulations, you have created an ItemEventReceiver that will find an eligible employee and assign the issue to that employee.

Registering event receivers on a more granular level

Ok, so our feature maps to any custom list we make, which is a problem. First of all, every custom list we make will fire the events we handle, meaning we get a ton of exceptions if we add multiple custom lists to our site. Not good.

Unfortunately, short of creating our list as a list template, SharePoint provides not way of connecting our event handlers to only certain lists of the ‘Custom list’ type. We really only want our Issues list to have the events handled so we need another approach.

Fortunately, adding event handlers to a certain list is quite easy using code even though it is not possible using the UI or even feature files alone.

What we want is to add event receivers directly to a certain lists. To do this, start by creating a console application and add references and using statements to Microsoft.SharePoint. Next, add the following code but substitite the site URL and the assembly strong name for your own:

 6 namespace RegisterEventReceiver
 7 {
 8 class Program
 9     {
 10 static void Main(string[] args)
 11         {
 12 using (SPSite site = new SPSite(http://lab-s02:5000/))
 13             {
 14 using (SPWeb web = site.OpenWeb())
 15                 {
 16 SPList issuesList = web.Lists["Issues"];
 17 int receiverCount = issuesList.EventReceivers.Count;
 18 for(int i=0; i
 19                     {
 20                         issuesList.EventReceivers[0].Delete();
 21                     }
 22
 23                     issuesList.EventReceivers.Add(SPEventReceiverType.ItemAdded, "HelpDesk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5056669089ea637d", "HelpDesk.IssuesHandler");
 24                     issuesList.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "HelpDesk, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5056669089ea637d", "HelpDesk.IssuesHandler");
 25
 26                 }
 27             }
 28         }
 29     }
 30 }

You might want to comment out or remove lines 17-21 as these basically remove any ‘old’ event handlers attached to the list. If you have event handlers you want to remain, don’t remove them 🙂

Compile, run, and you should have your new event handlers attached to only your Issues list rather than any custom list in the site. Of course, you want to deactivate your feature at this point if you register the events using the console application.

Conclusion so far

Right, so far we have covered, in some detail, two methods of automating business processes. First, in the last article, we looked at creating SharePoint Designer workflows to receive and categorize incoming email. Then, in this article, we looked at using SharePoint event receivers to hav something happen when an item had been added or updated.

Next week we will look at creating a full fledged Visual Studio SharePoint workflow. Your price, however, will be to give me a slight bit of feedback. Don’t worry, I won’t hold it to you if you cheat and don’t answer the poll 🙂

How did you like the second part of the ‘Automating business processes’ series?

 

Here are the links to the entire series:

Automating business processes in SharePoint: SharePoint Designer Workflows (Part 1 of 3)
Automating business processes in SharePoint: SharePoint Event Receivers (Part 2 of 3)
Automating business processes in SharePoint: Visual Studio Workflows (Part 3 of 3)

Oh, and make sure you subscribe to the feed to make sure you get updates and new articles as they become available.

See you in the next article!

Found this article valuable? Want to show your appreciation? Here are some options:

a) Click on the banners anywhere on the site to visit my blog's sponsors. They are all hand-picked and are selected based on providing great products and services to the SharePoint community.

b) Donate Bitcoins! I love Bitcoins, and you can donate if you'd like by clicking the button below.

c) Spread the word! Below, you should find links to sharing this article on your favorite social media sites. I'm an attention junkie, so sharing is caring in my book!

Pin It

Published by

Bjørn Furuknap

I previously did SharePoint. These days, I try new things to see where I can find the passion. If you have great ideas, cool projects, or is in general an awesome person, get in touch and we might find out together.

2 thoughts on “Automating business processes in SharePoint: SharePoint Event Receivers (Part 2 of 3)”

Leave a Reply

Your email address will not be published.