I’ve been doing some work with List Item Event Receivers and thought I’d share my experiences.

First there are a bunch of events that can be raised, I won’t list all but here are some of the good ones

ItemAdding /  ItemAdded
ItemUpdating / ItemUpdated

There are also specific ways of dealing with the data in each of these events, those that are “ing” events then the changes have not been applied yet so you get the change values from the AfterProperties passed in, those ending in “ed” you can grab the List Item directly as changes have already happened.

My experiences have been problematic so here is a few points that may help you when using these events.

Attachments

If you want to get hold of the attachments being added to a List, you can’t. (This may differ for doc libraries I have not inspected this).  Attachments are not on the list item as it does not exist yet and they are not in the Properties either.  Anything you want to do regarding attachments you have to do in “ed” events.

ID’s

When in the “Adding” event the one thing you have not got is the List.ID value.  If you were hoping to create entries in another list that has a lookup field of this list, your out of luck. There is no ID available to you, neither is there an @@IDENTITY equivalent.

Synchronous/Asynchronous Calls

The different types of events run in different contexts. In an Adding event this runs in the context of the Add from the page itself, after hitting Add in NewForm.aspx it will execute this Adding event code under the w3wp.exe process.  This is very handy when debugging as you can attach to the w3wp process and just debug.

**I have found that Added/Updated events are not called like this they are executed, I believe, I can’t be sure, by OWSTIMER, but regardless of the process, they are not executed immediately after the Adding events.  This can be witnessed by debugging the process and placing a breakpoint on the first line of Added code, After you hit “Add” the page refreshes and shows the list, however your breakpoint code is still waiting so this is on another thread of execution to your Adding code.

**Absolute nonsense.  The Added events also fire on the w3wp process but they do fire on a separate thread.  I have had problems in the past where the Added/Updated events do not stop on my breakpoints but it is not because they happen in the timer service, it’s some other reason.  I tried it just and it breaks on both adding and added.

This sounds like no big deal, in my example I needed to format the Title field to be the ID + “Mask”.  I did not have access to the ID until Added event.  After adding the list item the list view would re-appear with a blank title.  This was unacceptable to the client so I had to populate the field with some text “to be assigned”.  Later the Adding event kicks in has access to the ID and sets the Title to the Masked value I need.  The users on refresh of the list got what they wanted.

I know its a fudge, but you can’t do it in the event you cant use calculated fields or any of those tools this is what I had, but it’s worth knowing your “ed” events happen on a separate thread.

Enable/DisableFiring

In the “ing” events above, your receiver may need to alter the data, However you will be altering the data on the List.  If in the Adding event you set a field and update the list item then it will call the Updating/Updated events.  This is not normally what you want to happen as you might get into an endless update loop.

For this very purpose the SPItemEventReceiver Class you inherited can turn off this event firing. So in your event handler you can execute

this.DisableEventFiring();

This will stop all further event firing on this thread.

this.DisableEventFiring();
listItem.Update();
this.EnableEventFiring();

Really BIG HINT, always turn it back on again immediately.

Exception Handling

If you have code that MUST execute, like setting security, and other code that must also execute but if it broke you can live with it then organise the order of execution and consider multiple update() calls.  This is not a transaction, you have no rollback if your event fails, you just have a fail. This is also not exactly efficient either.

Consider the example where you set item level security based on a fields value, then emailing the customer or whoever.

Normally you might

SPSecurity.RunWithElevatedPrivileges(delegate() { ItemAddedElevated(properties.ListItem); });
private void ItemAddedElevated(SPListItem ListItem){
    this.DisableEventFiring();    SendEmails(ListItem);

    SetSecurity(ListItem);    ListItem["Sent"] = "Yes";    this.EnableEventFiring();

}

Obviously Bad Code. No exception handling, email servers go wrong, the SMTP format may not have been validated causing exceptions in the Sendmail bit, this will error, write to the log and never be heard of again, meanwhile you have bad security in your application. Also look at all that code being executed with events turned off, and what happens if an exception occurs before event firing is turned on, I don’t know, might not be good though.

Rewrite this code

SPSecurity.RunWithElevatedPrivileges(delegate() { ItemAddedElevated(properties.ListItem); });
private void ItemAddedElevated(SPListItem ListItem){
    SetSecurity(ListItem);
    ListItem["Sent"] = "Yes";
    this.DisableEventFiring();
    ListItem.Update();    

    this.EnableEventFiring();
    SendEmails(ListItem)

}

This slight change is less likely to go wrong but it’s still not brilliant is it, a bunch of try catch finally’s would be good here, but I’ll let you figure that out.

That’s all I can think of for now.

Advertisements