Estou passando por uma grande refatoração / ajuste de velocidade de um dos meus aplicativos MVC maiores. Ele foi implantado em produção há alguns meses e eu estava começando a obter tempos limite de espera por conexões no pool de conexão. Eu rastreei o problema até as conexões não serem descartadas corretamente.
À luz disso, fiz esta alteração no meu controlador de base:
public class MyBaseController : Controller
{
private ConfigurationManager configManager; // Manages the data context.
public MyBaseController()
{
configManager = new ConfigurationManager();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.configManager != null)
{
this.configManager.Dispose();
this.configManager = null;
}
}
base.Dispose(disposing);
}
}
Agora, tenho duas perguntas:
- Estou introduzindo uma condição de corrida? Como o
configManager
gerencia oDataContext
que expõe osIQueryable<>
parâmetros às visualizações, preciso ter certeza de queDispose()
não será chamado no controlador antes que a visualização termine a renderização. - A estrutura MVC chama
Dispose()
o controlador antes ou depois que a visualização é renderizada? Ou a estrutura MVC deixa isso para o GarbageCollector?
asp.net-mvc
linq-to-sql
garbage-collection
idisposable
John Gietzen
fonte
fonte
Respostas:
Dispose é chamado após a exibição é processado, sempre .
A visualização é renderizada na chamada para
ActionResult.ExecuteResult
. Isso é chamado (indiretamente) porControllerActionInvoker.InvokeAction
, que por sua vez é chamado porControllerBase.ExecuteCore
.Como o controlador está na pilha de chamadas quando a visualização é renderizada, ele não pode ser descartado.
fonte
Apenas para expandir a resposta de Craig Stuntz :
O ControllerFactory trata quando um Controlador é descartado. Ao implementar a interface IControllerFactory, um dos métodos que precisa ser implementado é ReleaseController.
Não tenho certeza de qual ControllerFactory você está usando, se você lançou o seu próprio, mas no Reflector, olhando para DefaultControllerFactory, o método ReleaseController é implementado assim:
public virtual void ReleaseController(IController controller) { IDisposable disposable = controller as IDisposable; if (disposable != null) { disposable.Dispose(); } }
Uma referência IController é passada, se aquele controlador implementa IDisposable, então o método Dispose desse controlador é chamado. Portanto, se você tiver algo que precise ser descartado após a conclusão da solicitação, ou seja, após a exibição da exibição. Herdar de IDisposable e colocar sua lógica no método Dispose para liberar quaisquer recursos.
O método ReleaseController é chamado pelo System.Web.Mvc.MvcHandler, que lida com a solicitação e implementa IHttpHandler. O ProcessRequest pega o HttpContext fornecido a ele e inicia o processo de localização do controlador para lidar com a solicitação, chamando o ControllerFactory implementado. Se você olhar no método ProcessRequest, verá o bloco finally que chama o ReleaseController do ControllerFactory. Isso só é chamado quando o Controller retorna um ViewResult.
fonte
HttpContext
é um homem? Agora estou realmente confuso.