Middleware en ASP.NET 6 - Orden de Operaciones

Estrada Web Group
Estrada Web Group
Middleware en ASP.NET 6 - Orden de Operaciones

Esta publicación es la Parte 3 de una serie de cuatro partes. Es posible que desee leer la Parte 1 y la Parte 2 primero o ir directo a la Parte 4.

Continuemos con nuestra serie sobre Middleware en .NET 6 discutiendo la canalización (pipeline) creada por Middleware y, específicamente, por qué es muy importante el orden en que se agregan los middlewares a la canalización.

Orden de operaciones

Recuerda de la Parte 1 de esta serie que el middleware forma una tubería, y el middleware en esa tubería se ejecuta en un orden determinado, un ejemplo de lo cual se muestra en esta imagen:

Middleware en ASP.NET 6 - Orden de Operaciones

Las solicitudes fluyen a través del middleware en orden y las respuestas surgen a través del middleware en orden inverso.

En este punto de esta serie, hemos definido dos clases de middleware: LoggingMiddleware para el registro de solicitudes/respuestas y SimpleResponseMiddleware que puede provocar un cortocircuito en la canalización para devolver una respuesta.

En esta publicación, comenzaremos solo con LoggingMiddleware:

//...Rest of Program.cs

app.UseLoggingMiddleware();

//...Rest of Program.cs

Agregar un retraso (Delay)

Imaginemos que ahora tenemos una nueva clase middleware, llamada IntentionalDelayMiddleware, que se parece a esto:

namespace MiddlewareNET6Demo.Middleware
{
    public class IntentionalDelayMiddleware
    {
        private readonly RequestDelegate _next;

        public IntentionalDelayMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            await Task.Delay(100);

            await _next(context);

            await Task.Delay(100);
        }
    }
}

Como puedes ver, esta clase middleware espera 100 milisegundos tanto cuando procesa la solicitud entrante como cuando procesa la respuesta saliente, para un tiempo de espera total de 200 milisegundos.

Claramente, esto no es algo que nos gustaría hacer en el mundo real. Para esta publicación, no estamos operando en el mundo real. Aquí, IntentionalDelayMiddleware representa algún tipo de middleware indefinido que requiere una cantidad predecible de tiempo para ejecutarse.

Necesitamos agregar una instancia de IntentionalDelayMiddleware a la canalización. La pregunta es: ¿lo agregamos antes o después del LoggingMiddleware?

En este caso, lo más probable es que no importe, ya que las dos clases de middleware no interactúan y no procesan lo mismo. Para esta demostración, agreguemos el IntentionalDelayMiddleware DESPUÉS del LoggingMiddleware:

//...Rest of Program.cs

app.UseLoggingMiddleware();
app.UseIntentionalDelayMiddleware();

//...Rest of Program.cs

Si ejecutamos la aplicación ahora, realmente no notaremos una diferencia significativa; 200ms es bastante rápido.

Adición de un middleware de tiempo de ejecución

Supongamos que recibimos un nuevo requisito de nuestro gerente. Dice que necesitamos registrar el tiempo de ejecución de cada solicitud en nuestro sistema.

En realidad, esto es bastante sencillo de hacer con el middleware; utiliza la clase Stopwatch proporcionada por .NET y la clase LoggingService que creamos en la Parte 2 de esta serie. Aquí está la clase de middleware, llamada TimeLoggingMiddleware:

using MiddlewareNET6Demo.Logging;
using System.Diagnostics;

namespace MiddlewareNET6Demo.Middleware
{
    public class TimeLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILoggingService _logger;

        public TimeLoggingMiddleware(RequestDelegate next,
                                     ILoggingService logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();

            await _next(context);

            watch.Stop();
            _logger.Log(LogLevel.Information, "Time to execute: " + watch.ElapsedMilliseconds + " milliseconds.");
        }
    }
}

Necesitamos agregar esto a la canalización. Pero nuevamente, esa pregunta permanece: ¿exactamente dónde deberíamos hacerlo?

Si añadimos el TimeLoggingMiddleware al pipeline ANTES del IntentionalDelayMiddleware, el retraso causado por este último se incluirá en las medidas tomadas por el primero. Si lo agregamos DESPUÉS, la demora no se incluirá, pero ¿es una medida precisa, especialmente si la demora en IntentionalDelayMiddleware cambia?

De hecho, ampliemos nuestra mirada a la canalización:

//...Rest of Program.cs

app.UseHttpsRedirection();
app.UseStaticFiles();

//We can also use custom extensions to add middleware to the pipeline.
//Note that if this middleware causes any delay, that delay is
//NOT included in the time logs.
app.UseLoggingMiddleware();

//Here's the time logging middleware
app.UseTimeLoggingMiddleware();

//Here's the delay. At the moment, the delay is INCLUDED in the time logs.
app.UseIntentionalDelayMiddleware();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();


Dado este archivo Program.cs, ¿dónde podría ser un lugar más apropiado para colocar el TimeLoggingMiddleware? Esa respuesta depende de varias preguntas, tales como:

  • ¿Los registros de tiempo deben incluir el tiempo de ejecución para cosas como autorizaciones no válidas? Si es así, el TimeLoggingMiddleware debe incluirse ANTES de la llamada a app.UseAuthorization().
  • Enrutar una llamada toma una cantidad de tiempo muy pequeña, pero medible. ¿Queremos incluir eso? Si es así, el TimeLoggingMiddleware debe incluirse ANTES de la llamada a app.UseRouting().

Como la mayoría de los problemas del mundo real, aquí no hay una respuesta clara. Si no hay otra dirección, personalmente cometerías el error de NO incluir el retraso conocido en la medición, pero en última instancia, esta es una decisión que deben tomar los desarrolladores individuales utilizando las peculiaridades, reglas y pautas conocidas de su sistema.

La parte clave que debe recordar es que ESTO:

//...Rest of Program.cs

app.UseIntentionalDelayMiddleware();
app.UseTimeLoggingMiddleware();

//...Rest of Program.cs

es potencialmente muy diferente de ESTO:

//...Rest of Program.cs

app.UseTimeLoggingMiddleware();
app.UseIntentionalDelayMiddleware();

//...Rest of Program.cs


Este es un ejemplo de por qué es importante el orden del middleware en la canalización.

¡A continuación!

En la cuarta y última parte de esta serie, demostraremos algunas formas en que puedes agregar o ejecutar condicionalmente middleware en la canalización.

¡Feliz codificación!

 

 

Compartir artículo:

Más artículos geniales

¿Cómo especificar grupos de validación con jQuery y ASP.NET?

¿Cómo especificar grupos de validación con jQuery y ASP.NET?

Los grupos de validación permiten organizar los controles de validación de una página como un conjunto. Cada grupo de validación puede realizar la validación independientemente de otros grupos de validación de la página.

Ver artículo completo
Avances del desarrollo del proyecto de sistema de inventarios

Avances del desarrollo del proyecto de sistema de inventarios

Si quieres aprender a programar un sistema de inventarios desde cero este es el lugar correcto. Aquí puedes descargar los avances del proyecto y te describo las funcionalidades desarrolladas

Ver artículo completo

Manténgase actualizado

Obtenga excelente contenido en su bandeja de entrada todas las semanas.
Solo contenido excelente, no compartimos su correo electrónico con terceros.
Subir al inicio de la pantalla