Saltar al contenido

¿Cómo bloquear una acción asp.net mvc?

Solución:

¿Estás buscando algo así?

public MyController : Controller
{
    private static object Lock = new object();

    public ActionResult MyAction()
    {
        lock (Lock)
        {
            // do your costly action here
        }    
    }
}

Lo anterior evitará que otros subprocesos ejecuten la acción si un subproceso actualmente está procesando código dentro del lock cuadra.

Actualización: así es como funciona esto

El código del método siempre se ejecuta mediante un hilo. En un servidor muy cargado, es posible que entren 2 o más subprocesos diferentes y comiencen a ejecutar un método en paralelo. Según la pregunta, esto es lo que quieres prevenir.

Note como el private Lock el objeto es static. Esto significa que se comparte en todas las instancias de su controlador. Entonces, incluso si hay 2 instancias de este controlador construidas en el montón, ambas comparten el mismo objeto Lock. (El objeto ni siquiera tiene que llamarse Lock, podría llamarlo Jerry o Samantha y aún tendría el mismo propósito).

Esto es lo que sucede. Su procesador solo puede permitir que 1 hilo ingrese una sección de código a la vez. En circunstancias normales, el subproceso A podría comenzar a ejecutar un bloque de código y luego el subproceso B podría comenzar a ejecutarlo. Entonces, en teoría, puede tener 2 subprocesos ejecutando el mismo método (o cualquier bloque de código) al mismo tiempo.

los lock La palabra clave se puede utilizar para evitar esto. Cuando un hilo ingresa a un bloque de código envuelto en un lock sección, “recoge” el objeto de bloqueo (lo que está entre paréntesis después de la lock palabra clave, también conocida como Lock, Jerry, o Samantha, que debe marcarse como static campo). Durante el tiempo en que se ejecuta la sección bloqueada, “se aferra” al objeto de bloqueo. Cuando el hilo sale de la sección bloqueada, “abandona” el objeto de bloqueo. Desde el momento en que el hilo toma el objeto de bloqueo, hasta que abandona el objeto de bloqueo, todos los demás hilos no pueden ingresar a la sección bloqueada del código. En efecto, están “pausados” hasta que el hilo que se está ejecutando abandona el objeto de bloqueo.

Entonces, el hilo A recoge el objeto de bloqueo al comienzo de su método MyAction. Antes de que abandone el objeto de bloqueo, el hilo B también intenta ejecutar este método. Sin embargo, no puede recoger el objeto de bloqueo porque ya está retenido por el subproceso A. Por lo tanto, espera a que el subproceso A abandone el objeto de bloqueo. Cuando lo hace, el hilo B toma el objeto de bloqueo y comienza a ejecutar el bloque de código. Cuando el subproceso B termina de ejecutar el bloque, cede el objeto de bloqueo para el siguiente subproceso que se delega para manejar este método.

… pero no estoy seguro de si esto es lo que estás buscando …

El uso de este enfoque no necesariamente hará que su código se ejecute más rápido. Solo asegura que un bloque de código solo pueda ser ejecutado por 1 subproceso a la vez. Normalmente se utiliza por motivos de simultaneidad, no por motivos de rendimiento. Si puede proporcionar más información sobre su problema específico en la pregunta, puede haber una mejor respuesta que esta.

Recuerde que el código que presenté anteriormente hará que otros subprocesos esperen antes de ejecutar el bloque. Si esto no es lo que desea, y desea que se “omita” toda la acción si ya está siendo ejecutada por otro hilo, entonces use algo más parecido a la respuesta de Oshry. Puede almacenar esta información en caché, sesión o cualquier otro mecanismo de almacenamiento de datos.

Después de leer y estar de acuerdo con la respuesta anterior, quería una solución ligeramente diferente: si desea detectar una segunda llamada a una acción, use Monitor.TryEnter:

if (!Monitor.TryEnter(Lock, new TimeSpan(0)))
{
    throw new ServiceBusyException("Locked!");
}
try
{
...
}
finally {
    Monitor.Exit(Lock);
}

Utilice el mismo objeto de bloqueo estático que se detalla en @danludwig

Prefiero usar SemaphoreSlim porque admite operaciones asíncronas.

Si necesita controlar la lectura / escritura, puede usar ReaderWriterLockSlim.

El siguiente fragmento de código utiliza la SemaphoreSlim:

public class DemoController : Controller
{
    private static readonly SemaphoreSlim ProtectedActionSemaphore =
        new SemaphoreSlim(1);

    [HttpGet("paction")] //--or post, put, delete...
    public IActionResult ProtectedAction()
    {
        ProtectedActionSemaphore.Wait();
        try
        {
            //--call your protected action here
        }
        finally
        {
            ProtectedActionSemaphore.Release();
        }

        return Ok(); //--or any other response
    }

    [HttpGet("paction2")] //--or post, put, delete...
    public async Task<IActionResult> ProtectedActionAsync()
    {
        await ProtectedActionSemaphore.WaitAsync();
        try
        {
            //--call your protected action here
        }
        finally
        {
            ProtectedActionSemaphore.Release();
        }

        return Ok(); //--or any other response
    }
}

Espero que ayude.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *