Apesar do ASP.NET Web API possui um mecanismo que nos permite estender e acoplar algum gerenciador de dependências, temos a possibilidade de registrar um determinado objeto para que ele seja descartado quando a requisição for completamente atendida.
É muito comum em aplicações Web criar um determinado objeto e querer mante-lo por toda a requisição, e em vários momentos e locais por onde a requisição trafega, podemos recuperar o referido objeto e reutiliza-lo para fazer alguma atividade complementar. Bancos de dados, loggers, entre outros, são exemplos de recursos que são úteis durante a vida da requisição dentro do pipeline onde ela está sendo processada.
A classe HttpRequestMessage possui uma propriedade chamada Properties (IDictionary<string, object>) que permite catalogarmos diversas informações inerentes à requisição, bem como recursos que podem ser (re)utilizados durante todas as etapas da execução. Uma vez adicionados, eles podem ser extraídos em qualquer momento no futuro que venha a precisar deles, mesmo que seja em outras camadas.
A dificuldade não é adicionar, mas saber o momento certo de descarta-lo. Simplesmente adicionar o recurso no dicionário não é suficiente para o ASP.NET Web API fazer a eliminação correta do mesmo. A Microsoft disponibilizou um método de extensão chamado RegisterForDispose, exposto pela classe HttpRequestMessageExtensions. Devemos utilizar este método para indicar explicitamente ao ASP.NET Web API que aquele objeto deve ser descartado no final da requisição. E, como era de se esperar, este método recebe objetos que implementam obrigatoriamente a interface IDisposable.
public class LoggerHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var logger = new TextLogger(@”C:TempLog.txt”);
request.RegisterForDispose(logger);
request.Properties.Add(“TextLogger”, logger);
return base.SendAsync(request, cancellationToken).ContinueWith(tr =>
{
var response = tr.Result;
logger.Write(“Request: ” + request.ToString()).ContinueWith(_ =>
logger.Write(“Response: ” + response.ToString())).Wait();
return response;
}, cancellationToken);
}
}
Curiosamente o método RegisterForDispose também recorre a propriedade Properties da classe HttpRequestMessage para acomodar os objetos que serão descartados quando a mesma também for removida. Caso encontre um momento mais oportuno para fazer o descarte, podemos recorrer ao método (também de extensão) chamado DisposeRequestResources para antecipar essa rotina, ou ainda, se preferir inspecionar os objetos marcados, pode-se utilizar o método GetResourcesForDisposal para isso.
Outro uso para o que vimos aqui é quando você opta por interceptar a criação do controller (através da implementação da interface IHttpControllerActivator), onde o mesmo pode necessitar de recursos em seu construtor e que sejam necessários serem marcados para descarte no término da requisição.