Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I've got my event receiver (itemdeleting) working almost exactly the way I'd like it to.

Upon certain conditions in the itemdeleting event, I am setting the status to CancelWithRedirectUrl and setting the redirect URL like so:

properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
properties.RedirectUrl = "/_layouts/AppPage.aspx";

The only problem I'm experiencing now is that if a user selects and deletes more than 1 item at a time. The event receiver apparently tries to redirect twice and I get an error stating the following (twice as you see):

The server has encountered the following error(s):
The request was redirected to ...

The server has encountered the following error(s):
The request was redirected to ...

If I debug I can see my event receiver is actually executing twice. Is there some graceful way to handle this?

share|improve this question

2 Answers 2

I am not certain this will work but I believe that if you disable event firing it does so for the EventReceiver. Try wrapping your code in a disable event firing scope.

http://adrianhenke.wordpress.com/2010/01/29/disable-item-events-firing-during-item-update/ Using this class:

/// <summary>
/// Disabled item events scope
/// </summary>
/// <see cref="http://adrianhenke.wordpress.com/2010/01/29/disable-item-events-firing-during-item-update/"/>
class DisabledItemEventsScope : SPItemEventReceiver, IDisposable
{
    bool oldValue;

    public DisabledItemEventsScope()
    {
        this.oldValue = base.EventFiringEnabled;
        base.EventFiringEnabled = false;
    }

    #region IDisposable Members

    public void Dispose()
    {
        base.EventFiringEnabled = oldValue;
    }

    #endregion
}

And call it like this:

using (DisabledItemEventsScope scope = new DisabledItemEventsScope())
{
    //Redirect and any other code.
}
share|improve this answer
    
Thanks Robert, I am using a similar approach to your recommendation in other areas of the application and it works great. I don't think it would be helpful in this case because the events are being fired due to user action and not being fired by a server-side call to item.Update(). If I can't come up with a clean way to handle multiple items, I am considering client side preventative measures like: a) Preventing users from being able to check more than 1 list item checkbox at a time. b) Disabling the "Delete Item" action if more than 1 list item is checked. –  mikey Nov 8 '12 at 0:51

EventFiringEnabled is not the answer as it prevents firing new events as the result of updates done by my code.

The cause of the error is that ItemDeleting event is synchronous. It means that its receivers are executed in the same thread as original operation and moreover all other sync event receivers. And only one redirect is OK. The 2nd one causes error you mention (because it tries to do 2nd redirect in single thread).

I deployed following sample you can use:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;

namespace LongOperationlWebPart.EventReceiver1
{
    /// <summary>
    /// List Item Events
    /// </summary>
    public class EventReceiver1 : SPItemEventReceiver
    {
        private static SortedDictionary<DateTime, Guid> transactions;
        /// <summary>
        /// An item is being deleted.
        /// </summary>
        public override void ItemDeleting(SPItemEventProperties properties)
        {
            if (transactions == null) transactions = new SortedDictionary<DateTime, Guid>();
            Guid currentCorrelationId = CorrelationId.GetCurrentCorrelationToken();
            if (!transactions.ContainsValue(currentCorrelationId))
            {
                CleanIds(60);
                transactions.Add(DateTime.Now, currentCorrelationId);
                properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
                properties.RedirectUrl = "Default.aspx";
            }
            else base.ItemDeleting(properties);
        }

        private void CleanIds(double delay)
        {
            foreach (DateTime dt in transactions.Where(t => t.Key < DateTime.Now.AddSeconds(-1.0*delay)).Select(t => t.Key))
            {
                transactions.Remove(dt);
            }
        }

        public class CorrelationId
        {
            [DllImport("advapi32.dll")]
            public static extern uint EventActivityIdControl(uint controlCode, ref  Guid activityId);
            public const uint EVENT_ACTIVITY_CTRL_GET_ID = 1;

            public static Guid GetCurrentCorrelationToken()
            {
                Guid g = Guid.Empty;
                EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, ref  g);
                return g;
            }
        }
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.