Do long running operations on SPListItem creation
Events on SPListItems like ItemAdding or ItemAdded are nothing new. Many of you have already used them. Recently I had a requirement to create a new SPSite, when an item in a list has been created. So an ItemReceiver was my choice.
But the customer wants something special 🙂 During the creation process, which takes some seconds, the user should see a loading animation.
Here comes the problem. The ItemEventReceiver is running in the background, and has no knowledge about the GUI process. Well, at least if it is running asynchronous. A very good explanation can be found here: Using synchronous “after” events (e.g. ItemUpdated) in SharePoint 2010.
The short summary: If you use synchronous events, they get executed in the same thread and you have the HttpContext and SPContext!
You already tried this and didn’t have the context objects?
Here comes the trick…
Grab the objects in the constructor, store them and use later when you need them.
private SPContext _spContext; private HttpContext _httpContext; public EventReceiver() { _spContext = SPContext.Current; _httpContext = HttpContext.Current; } public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); try { if (_spContext == null) { // item has been created via code from timerjob. no context and no need to redirect return; } string url = SPUrlUtility.CombineUrl(_spContext.Web.ServerRelativeUrl, "_layouts...") + properties.ListItemId; _httpContext.Response.Redirect(url); } catch (ThreadAbortException e) { // occures if redirected } }
Ok. We’ve successfully redirected to another page in our creation page, which can be a modal dialog or full frame page. I’ve not been able to use the Page to start a SPLongOperation with. A NullReference Exception has been thrown. So my solution was another Layouts-Page, which then starts the SPLongOperation. When it is done, the Layouts-Page is closed. By closing it, the modal dialog from the Item Creation process also vanishes.
I’ve chosen the ItemAdded and not ItemAdding event, because ItemAdding did not like the redirect. The item did not get created.
The Layouts-Page uses SPLongOperation e.g. in CreateChildControls.
using (var longRunning = new SPLongOperation(Page)) { longRunning.Begin(); // do your long running operation here longRunning.End(null, SPRedirectFlags.Default, Context, null, "window.frameElement.commonModalDialogClose(1, null);"); }
After the operation has been executed, the SPLongOperation is ended and a script passed as last parameter in the End() method is executed. You don’t need script tags here.
To register the ItemEventReceiver to execute synchronously, use the following code.
SPList list = ... // attach EventReceiver var receiverDefinition = list.EventReceivers.Add(); receiverDefinition.Type = SPEventReceiverType.ItemAdded; receiverDefinition.Assembly = "yourAssemblyFullName"; receiverDefinition.Class = "Your EventReceiver class (incl. namespace)"; receiverDefinition.Synchronization = SPEventReceiverSynchronization.Synchronous; receiverDefinition.Update(); list.Update();
Basically that’s it. A combination of known tasks to create a new solution.
Summary
You can show a work-in-progress dialog to a user, when a new SPListItem is created. Here are the steps:
- Use a synchronous asynchronous event 🙂
- Redirect to a Layouts-Page
- Use the SPLongOperation class to do your work
- Have fun and happy customers