Social Icons

miércoles, 3 de octubre de 2012

Un Thread.Sleep que no cuelga el hilo

He estado añadiendo tests unitarios a mi código de SharePoint y no es una tarea facil.

Una de las cosas más importantes que quería probar eran unos ItemEventReceivers de una lista. Esto funciona sin problemas cuando pruebas los eventos síncronos como el ItemAdding o el ItemUpdating pero cuando se trata de probar los eventos asíncronos es necesario esperar...

Si pones el hilo del test a dormir los eventos asíncronos no se ejecutarán ya que es el mismo en el que se ejecuta el código de SharePoint y aunque tu código funcione cuando lo ejecutas a mano los tests fallarán.

Es por esto que he creado una clase basada en timers que no cuelga el hilo dejando ejecutarse los eventos asíncronos.
public class Waiter : IDisposable
{
    public enum WaiterState
    {
        Waiting,
        TimedOut,
        Success,
        Error
    };

    System.Timers.Timer WaitTimer;
    ManualResetEvent manualResetEvent;
    int WaitCounter;

    private Waiter(int interval)
    {
        WaitCounter = 0;

        manualResetEvent = new ManualResetEvent(true);
        WaitTimer = new System.Timers.Timer() { AutoReset = false, Interval = interval };
        WaitTimer.Elapsed += new ElapsedEventHandler(WaitTimer_Elapsed);
    }

    void WaitTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        WaitCounter++;
        manualResetEvent.Set();
    }

    /// 
    /// Waits for the interval in milliseconds times number of times or once by default.
    /// 
    public static WaiterState Wait(int interval, int times)
    {
        try
        {
            using (Waiter WaiterClass = new Waiter(interval))
            {
                while (WaiterClass.WaitCounter <= times)
                {
                    WaiterClass.WaitTimer.Start();
                    WaiterClass.manualResetEvent.WaitOne();
                }
            }
        }
        catch
        {
            return WaiterState.Error;
        }

        return WaiterState.Success;
    }

    /// 
    /// Waits for the interval in milliseconds once.
    /// 
    public static WaiterState Wait(int interval)
    {
        return Wait(interval, 0);
    }

    void Dispose()
    {
        WaitTimer.Dispose();
    }
}
Pruébala.

No hay comentarios: