TransWikia.com

Event Receiver CancelWithRedirectUrl issue with multiple selected list items

SharePoint Asked by mikey on February 6, 2021

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?

2 Answers

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;
            }
        }
    }
}

Answered by Jan Vanek on February 6, 2021

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.
}

Answered by Robert Kaucher on February 6, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP