Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 4 de marzo de 2025
Persona liberando pajarillos encerrados en una caja llamada ASP.NET Core

Normalmente los servicios usados por nuestra aplicación ASP.NET Core los registraremos en el contenedor de dependencias, para luego ir satisfaciendo los requisitos de los distintos componentes gracias a los mecanismos de inyección de dependencias que nos proporciona el framework. De estos servicios, aquellos que se registran como scoped se liberarán automáticamente al finalizar el proceso de la petición.

Sin embargo, si instanciamos manualmente un servicio durante el proceso de la petición, tendremos que encargarnos nosotros mismos de liberarlo cuando ya no sea necesario. Los que tengan un ámbito de vida corto, normalmente los crearemos y destruiremos utilizando using en algunos de sus sabores (como bloque o con ámbito local implícito), pero cuando queremos que pueda ser compartido entre varios componentes, no es sería tan sencillo... si no fuera porque el framework ya lo ha tenido en cuenta 🙂

Para estos casos, ASP.NET Core proporciona el extensor RegisterForDispose(), que nos permite registrar un servicio para que se libere automáticamente al finalizar la petición.

Liberando servicios al finalizar la petición

Para registrar un servicio para que se libere automáticamente al finalizar la petición, simplemente tenemos que llamar al método RegisterForDispose() del objeto HttpResponse de la petición HTTP actual, pasándole el servicio que queremos liberar.

Por ejemplo, si en el interior del manejador de una minimal API tenemos un servicio MyService que queremos liberar al finalizar la petición, simplemente tenemos que hacer lo siguiente:

app.MapGet("/", (HttpContext ctx) =>
{
    var myService = new MyService();
    ctx.Response.RegisterForDispose(myService);
    ... // Hacer algo con el servicio
    return "Hello World!";
});

public class MyService: IDisposable
{
    public void Dispose()
    {
        // TODO release managed resources here
    }
}

De esta forma, el servicio se liberará automáticamente al finalizar la petición HTTP, una vez que se haya enviado la respuesta al cliente.

Si en lugar del manejador de una minimal API estamos en una acción de un controlador MVC, podemos acceder directamente al objeto HttpContext:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        var myService = new MyService();
        HttpContext.Response.RegisterForDisposeAsync(myService);
        ... // Hacer algo con el servicio
        return Ok();
    }
}

Como se puede intuir, para que la llamada a RegisterForDispose() compile, el servicio que estamos registrando debe implementar la interfaz IDisposable. Tiene sentido que sea así, puesto que el método Dispose() de la interfaz es el que se invoca al finalizar la petición, al igual que sucede con los servicios scoped.

Si, en cambio, se trata de una clase que implementa IAsyncDisposable y, por tanto, tiene un método de liberación asíncrono, el método al que debemos llamar es RegisterForDisposeAsync():

app.MapGet("/", (HttpContext ctx) =>
{
    var myService = new MyService();
    ctx.Response.RegisterForDisposeAsync(myService);
    ... // Hacer algo con el servicio
    return "Hello World!";
});

app.Run();

public class MyService: IAsyncDisposable
{
    public async ValueTask DisposeAsync()
    {
        // TODO release managed resources here
    }
}

¡Espero que os resulte de utilidad!

Publicado en: www.variablenotfound.com.

Aún no hay comentarios, ¡sé el primero!