Thursday, November 24, 2011

Redirect to custom error page from event handler

I’ve seen a lot of posts saying you can’t redirect to a custom error page from a SPItemEventReceiver in SharePoint 2007.

In 2010, you can use Properties.RedirectUrl which will send you to a custom error page, instead of the OOB error page that displays your properties.ErrorMessage. this is simple enough, all you have to do is set properties.Cancel = true – and the custom redirect Url kicks in.

But still, in 2007 this property does not exist, and in 2010 – you might want to have a custom redirect page and not cancel the event.

Good news – it is all possible!

Redirecting

The way to do it, is to add some code to a sync event. Async events can’t help you since they are not guaranteed to run immediately, and they don’t have any user context when they execute…

You can use the SPUtility.Redirect(PageUrl, SPRedirectFlags, HTTPContext); within your ItemAdding, ItemUpdating or ItemDeleting event handler to redirect your user to a custom page.

This redirection kicks in and throws the “ThreadAbortException”, stopping the rest of your code from running and redirecting the user to your custom page.

Few things to know:

1. ThreadAbortException is a “catch me if you can” exception. you can put it in try…catch… block, but this exception will always bubble up and be thrown again and again. essentially, only the catch and finally code blocks will run after this exception is thrown. you can set “SPRedirectFlags.DoNotEndResponse” if you don’t want this exception to be thrown and it should still redirect at the end, but using SPRedirectFlags.Default will throw it.

2. You may notice, that if you try using HTTPContext.Current in your event handler method – you will get a null context. So, the only way to get the HTTPContext.Current is in your event handler class constructor. save it as a member, and use it in your event handlers. DONT SAVE IT AS A STATIC MEMBER! Use any instance member (private/public/protected…) but don’t use a static member as you may run into unexpected trouble.

Cancelling the event

Now, we took care of redirecting, but it is good to remember that this on its own will not cancel the item event and it will still be updated/added/deleted.

If you want to cancel the item event, you still have to do that using properties.Cancel = true.

Since we talked about ThreadAbortException – now you know you have to put the SPUtility.Redirect code in a try block, and set the properties.Cancel in the catch block.

Code Example:

Your code should look like this:

try
{
SPUtility.Redirect("/_layouts/KWizCom/AppError.aspx?ErMsg=" + errMessage, SPRedirectFlags.DoNotEndResponse, currentContext);
}
catch
{
properties.ErrorMessage = errMessage;
properties.Cancel = true;
}

Good luck!

4 comments:

Anonymous said...

I want to show just an alert with error message and want to give them a back button. so that user can edit the item once again re submit the same for the list

how to do that?
guruprasadmarathe@gmail.com

Shai Petel said...

You can build your own AppError.aspx page with a button that uses the javascript "back" function.
Note that not all browsers will keep the form information that the user entered.

A better way to do it perhaps, is to create a new item in the event handler, set it's properties to the ones that were OK, and show an error page wiht 2 buttons and this message:
"Some of the properties in your item were incorrect [explain, which fields were not valid...]. Click "Try again" to edit the item, or "Cancel" to remove the item.

perhaps this will be what you are looking for? This way you can make sure that the item was craeted wiht the valid values.

Anonymous said...

Hey,

I tried this with Doucment Library and this doesn't work. Have you tested this with doclib?

Shai Petel said...

Make sense, since document library adding event is for the file upload, and not for the meta data update.

The first meta data update in document library is wierd, perhaps you could catch it by attaching to the "ItemUpdating" event and not "ItemAdding" ? but it will run every update not just for new files.