ASP MVC : IController Dispose ()는 언제 호출됩니까?


83

더 큰 MVC 앱 중 하나를 크게 리팩토링 / 속도 조정 중입니다. 이제 몇 달 동안 프로덕션에 배포되었으며 연결 풀에서 연결을 기다리는 시간 초과가 발생하기 시작했습니다. 제대로 처리되지 않는 연결까지 문제를 추적했습니다.

이를 고려하여 이후 기본 컨트롤러를 다음과 같이 변경했습니다.

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);
    }
}

이제 두 가지 질문이 있습니다.

  1. 경쟁 조건을 도입하고 있습니까? 뷰에 매개 변수를 노출 하는을 configManager관리 하므로 뷰가 렌더링을 완료하기 전에 컨트롤러에서 호출되지 않는지 확인해야합니다 .DataContextIQueryable<>Dispose()
  2. Dispose()뷰가 렌더링되기 전이나 후에 MVC 프레임 워크 가 컨트롤러에서 호출 합니까? 아니면 MVC 프레임 워크가이를 GarbageCollector에 맡깁니까?

2
나는 이것에 대한 답변을 고대하고 있습니다! 좋은 질문입니다!
Daniel Elliott

다른 코드 (귀하의 코드 또는 ASP.NET MVC의 ..)를 보지 않고 정확히 configManager를 무효화해야하는 이유는 무엇입니까? 도움이 되나요? 당신이 "DUH"나 앞에서 철저히 생각하십시오.
Andrei Rînea

경합 상태를 쉽게 제거 할 수있는 일반적인 경우를 의미합니다. 이 특별한 경우에는 컨트롤러 인스턴스가 둘 이상의 스레드에서 사용되므로 경쟁 조건의 위험이 전혀 없습니다.
Andrei Rînea 2010 년

1
@Andrei : 방어적인 코딩 일뿐입니다. 내 dispose 메서드가 두 번 호출되는 경우 데이터베이스 연결을 두 번 폐기하는 것을 방지합니다.
John Gietzen 2010 년

1
@Andrei : 글쎄요, 제 생각에는 "무시하기"와 "어쨌든 자식 개체에 대한 Dispose 호출"은 완전히 다릅니다. 따라서 수표.
John Gietzen 2010 년

답변:


70

Dispose는 뷰가 렌더링 된 후 항상 호출됩니다 .

뷰는에 대한 호출에서 렌더링됩니다 ActionResult.ExecuteResult. 이것은 (간접적으로)에 의해 호출되며 ControllerActionInvoker.InvokeAction, 차례로에 의해 호출됩니다 ControllerBase.ExecuteCore.

뷰가 렌더링 될 때 컨트롤러가 호출 스택에 있기 때문에 폐기 할 수 없습니다.


좋습니다. 문서가 있습니까? 확신하고 싶어요.
John Gietzen

큰! 그것을 설명하는 문서를 찾는 것이 좋을 것입니다. 그러나 확장 된 답변은 정말 위로가되었습니다. 코드는 전혀 더 나은 문서입니다. : D
CSA

37

Craig Stuntz의 답변 을 확장하려면 :

ControllerFactory는 Controller가 삭제 될 때 처리합니다. IControllerFactory 인터페이스를 구현할 때 구현해야하는 메서드 중 하나는 ReleaseController입니다.

자신의 롤링 여부에 관계없이 어떤 ControllerFactory를 사용하고 있는지 확실하지 않지만 Reflector에서 DefaultControllerFactory를 보면 ReleaseController 메서드가 다음과 같이 구현됩니다.

public virtual void ReleaseController(IController controller)
{
    IDisposable disposable = controller as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

해당 컨트롤러가 IDisposable을 구현하는 경우 IController 참조가 전달되면 해당 컨트롤러의 Dispose 메서드가 호출됩니다. 따라서 요청이 완료된 후, 즉 뷰가 렌더링 된 후 처리해야하는 항목이있는 경우. IDisposable을 상속하고 Dispose 메서드에 논리를 넣어 리소스를 해제합니다.

ReleaseController 메서드는 요청을 처리하고 IHttpHandler를 구현하는 System.Web.Mvc.MvcHandler에 의해 호출됩니다. ProcessRequest는 주어진 HttpContext를 받아서 구현 된 ControllerFactory를 호출하여 요청을 처리 할 컨트롤러를 찾는 프로세스를 시작합니다. ProcessRequest 메소드를 살펴보면 ControllerFactory의 ReleaseController를 호출하는 finally 블록을 볼 수 있습니다. Controller가 ViewResult를 반환 한 경우에만 호출됩니다.


멋진 대답입니다. Controller 개체의 직접 인스턴스가 Dispose () 호출을 허용하지 않는 이유를 알 수 없었지만 IDisposable 인터페이스를 사용하여 새 인스턴스를 만들어야하는 것 같습니다. 이것은 나를 위해 일했습니다!
MegaMatt 2012 년

그래서 ... HttpContext남자인가요? 이제 정말 혼란 스럽습니다.
Chef_Code
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.