SharePoint Event Receivers + ItemAdded + Null Columns fun
Event receivers enable you to run some action when a particular event occurs. For example, every time a new item is added to a list, you may want to run some code, or start a workflow. This is really handy - but be aware of some gotchas. SharePoint event receivers will generally be one of two types - an “-ing” event or an “-ed” event, such as ItemAdding or ItemAdded. As their name suggests, an -ing event runs whilst the the event is happening (and might therefore give you the option to cancel it) and -ed events occur after the event has occurred. You need to be aware of how these events run. Generally, the -ing events run synchronously, that is, they are blocking and run in the same thread/cycle that they were generated in, and -ed events run asynchronously, meaning the opposite - they are not blocking - they will be run in a separate thread and not block the execution of the main thread. You therefore need to be aware of what info may, or may not, be available to you when you run code in an event receiver.
One thing you may encounter, then, is during an ItemAdded event, you rely on some data being set on an e.g., SPListItem.
public override void ItemAdded(SPItemEventProperties properties) { string myFieldValue = (string)properties.ListItem["MyField"]; DoSomething(myFieldValue); }
However, because your code is running asynchronously, it’s possible that the base event (ie. the main ItemAdded) hasn’t finished yet. So in some cases, “myFieldValue” may be null. This is dependent on numerous things, like the size of your farm, the number of other events going on, and the task (e.g., uploading a big document.) If all you need is the value of the field, then you could look in the “properties.AfterProperties” collection -it might be in there. But in my testing, I found that anything that was created in the OWSTIMER / Timer Service, e.g., a list item created by the Content Organiser, for example, this collection was empty, and the same in the ItemAdding event.
The option for me, therefore, was to, well… wait. You can queue up another thread, pause it for an amount of time, and then run your code:
private Guid listID; private Guid itemID; private Guid siteID; public override void ItemAdded(SPItemEventProperties properties) { listID = properties.ListId; itemID = properties.ListItem.UniqueId; siteID = properties.SiteId; // bang it out in a new thread to give it a chance to finish. Poor thing is overworked. System.Threading.Thread otherThread = new System.Threading.Thread(QueueUpdate); otherThread.Start(); } private void QueueUpdate() { // zzzzzzzzzzzz - wait for 10 seconds System.Threading.Thread.Sleep(10000); using (SPSite site = new SPSite(siteID)) { using (SPWeb web = site.OpenWeb()) { SPList list = web.Lists[listID]; SPListItem item = list.Items[itemID]; string myFieldValue = (string)properties.ListItem["MyField"]; DoSomething(myFieldValue); } } }
You will need to adjust the amount of time you pause for to suit your requirements.