Suppose that, during the deletion of an item in List A, you want to first check to see if some condition holds true in List B, and if so, perform some action on List B before actually deleting the item in List A. Normally, workflows created in SharePoint Designer would come in very handy here, but unfortunately, you cannot attach a workflow to the deletion of an item in SharePoint. So, we are stuck with creating our own in Visual Studio and attaching it to the list as a feature.
Now, what I wanted to do seemed straight-forward enough. But, I ran into a lot of the very informational ‘object reference not set to an instance of an object’ errors during the process. Frustrated, I stepped through each line, and finally discovered the culprit. And I was surprised, because the code I was using showed up in several places in other blogs, not to mention on MSDN, so I’m still a little curious as to why it was not working for me. But alas, I must move on and so I found another solution which worked like a charm.
First, the piece of code that my event handler did not seem to like was:
SPContext.Current.Site, SPContext.Current.Web, really anything referencing SPContext.
Essentially, I replaced these occurrences with:
properties.ListItem.ParentList.ParentWeb.Site, properties.ListItem.ParentList.ParentWeb, and so on.
Additionally, I learned that you cannot use SPSecurity.RunWithElevatedPriviliges(delegate() { … }); in event handlers. The replacement I found for this is:
Guid siteId = properties.ListItem.ParentList.ParentWeb.Site.ID;
SPUserToken systemAccountToken = properties.ListItem.ParentList.ParentWeb.Site.System.Account.UserToken;
using (SPSite site = new SPSite(siteId, systemAccountToken) { … }
Below is a watered down version of my code, but it should be functionally complete:
public class DeleteHandler : SPItemEventReceiver
{
public override void ItemDeleting(SPItemEventProperties properties)
{
try
{
string error = “”;
SPListItem item = properties.ListItem;
int rid = Convert.ToInt32(item["ID"]);
// just to be on the safe side, let’s make sure we have the right list
if (item.ParentList.Title.Equals(”List Name Here”))
{
string[] authorInfo = item["Author"].ToString().Split(’#');
if (authorInfo.Length == 2)
{
string creator = authorInfo[1].ToString();
// let’s make sure that the current user it the actual creator of the list item
if (creator.Equals(properties.UserDisplayName.ToString()))
{
// delete from Calendar
error = DeleteFromCalendar(properties, rid);
// if there was a problem with the delete, view the error
// and cancel the whole deletion process.
if (error.Length > 0)
{
properties.Cancel = true;
properties.ErrorMessage = error;
}
}
else
{
properties.Cancel = true;
properties.ErrorMessage = “You cannot delete another user's post.”;
}
}
}
else
{
// allow deletion of item
properties.Cancel = false;
}
}
catch (Exception x)
{
properties.Cancel = true;
properties.ErrorMessage = “Unable to delete post: ” + x.Message.ToString();
}
}
private string DeleteFromCalendar(SPItemEventProperties properties, int rid)
{
string error = “”;
try
{
Guid siteId = properties.ListItem.ParentList.ParentWeb.Site.ID;
SPUserToken systemAccountToken = properties.ListItem.ParentList.ParentWeb.Site.SystemAccount.UserToken;
using (SPSite mySite = new SPSite(siteId, systemAccountToken))
{
using (SPWeb web = properties.ListItem.ParentList.ParentWeb)
{
SPList list = web.Lists["Calendar"];
//create the query
SPQuery query = new SPQuery();
//build the query
query.Query = “<Where><Eq><FieldRef Name=’Description’/><Value Type=’Note’>” + rid.ToString() + “</Value></Eq></Where>”;
SPListItemCollection items = list.GetItems(query);
int count = items.Count;
for (int i = 0; i < count; i++)
tems.Delete(i);
}
}
}
catch (Exception x)
{
error = ” Delete from calendar: ” + x.Message.ToString();
}
return error;
}
}