ASP MVC: Khi nào thì IController Dispose () được gọi?


83

Tôi đang thực hiện một cuộc tái cấu trúc / điều chỉnh tốc độ lớn của một trong những ứng dụng MVC lớn hơn của tôi. Nó đã được triển khai cho sản xuất trong vài tháng nay và tôi bắt đầu hết thời gian chờ kết nối trong nhóm kết nối. Tôi đã theo dõi vấn đề do các kết nối không được xử lý đúng cách.

Do đó, tôi đã thực hiện thay đổi này đối với bộ điều khiển cơ sở của mình:

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

Bây giờ, tôi có hai câu hỏi:

  1. Tôi có đang giới thiệu một điều kiện chủng tộc không? Vì trình configManagerquản lý DataContexthiển thị IQueryable<>các tham số cho các khung nhìn, tôi cần đảm bảo rằng điều đó Dispose()sẽ không được gọi trên bộ điều khiển trước khi khung nhìn kết thúc hiển thị.
  2. Khung MVC có gọi Dispose()Bộ điều khiển trước hoặc sau khi khung nhìn được hiển thị không? Hoặc, khuôn khổ MVC có để lại điều đó cho GarbageCollector không?

2
Tôi rất mong chờ câu trả lời cho câu hỏi này! Câu hỏi tuyệt vời!
Daniel Elliott

Mà không cần xem mã khác (của bạn hoặc ASP.NET MVC của ..) tại sao chính xác bạn cần phải hủy bỏ configManager? Điều đó có giúp được gì không? Suy nghĩ thấu đáo trước khi bất kỳ của bạn "DUH" tôi ..
Andrei Rînea

Ý tôi là trong trường hợp chung như vậy, điều kiện chủng tộc có thể dễ dàng bị loại bỏ như vậy. Trong trường hợp cụ thể này, tôi nghi ngờ rằng một cá thể bộ điều khiển sẽ được sử dụng bởi nhiều hơn một luồng và do đó không có rủi ro nào về điều kiện chủng tộc.
Andrei Rînea 11/10/10

1
@Andrei: Đó chỉ là một chút mã hóa phòng thủ. Nó ngăn tôi vứt bỏ Kết nối Cơ sở dữ liệu hai lần, nếu phương thức hủy của tôi được gọi hai lần.
John Gietzen 11/10/10

1
@Andrei: Chà, theo tôi thì "Bỏ qua" và "Gọi là vứt bỏ đối tượng con" là hoàn toàn khác nhau. Do đó kiểm tra.
John Gietzen 11/10/10

Câu trả lời:


70

Loại bỏ được gọi sau khi chế độ xem được hiển thị, luôn .

Chế độ xem được hiển thị trong lệnh gọi tới ActionResult.ExecuteResult. Điều đó được gọi (gián tiếp) bởi ControllerActionInvoker.InvokeAction, lần lượt được gọi bởiControllerBase.ExecuteCore .

Vì bộ điều khiển nằm trong ngăn xếp cuộc gọi khi chế độ xem được hiển thị, nó không thể được xử lý khi đó.


Tuyệt vời, bạn có tài liệu không? Tôi chỉ muốn chắc chắn.
John Gietzen

Tuyệt quá! Thật tuyệt nếu tìm được một tài liệu giải thích về nó. Nhưng câu trả lời mở rộng thực sự an ủi. Mã là tài liệu tốt hơn ở tất cả. : D
CSA

37

Chỉ để mở rộng Câu trả lời của Craig Stuntz :

ControllerFactory xử lý khi Bộ điều khiển bị loại bỏ. Khi triển khai giao diện IControllerFactory, một trong những phương thức cần được thực hiện là ReleaseController.

Tôi không chắc bạn đang sử dụng ControllerFactory nào, liệu bạn có tự cuộn hay không, nhưng trong Reflector nhìn vào DefaultControllerFactory, phương thức ReleaseController được triển khai như vậy:

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

Một tham chiếu IController được chuyển vào, nếu bộ điều khiển đó triển khai IDisposable, thì phương thức Dispose của bộ điều khiển đó được gọi. Vì vậy, nếu bạn có bất cứ thứ gì bạn cần, hãy xử lý sau khi yêu cầu kết thúc, tức là sau khi chế độ xem được hiển thị. Kế thừa IDisposable và đưa logic của bạn vào phương thức Dispose để giải phóng bất kỳ tài nguyên nào.

Phương thức ReleaseController được gọi bởi System.Web.Mvc.MvcHandler xử lý yêu cầu và nó thực hiện IHttpHandler. ProcessRequest lấy HttpContext được cung cấp cho nó và bắt đầu quá trình tìm kiếm bộ điều khiển để xử lý yêu cầu, bằng cách gọi vào ControllerFactory đã triển khai. Nếu bạn nhìn vào phương thức ProcessRequest, bạn sẽ thấy khối cuối cùng gọi ReleaseController của ControllerFactory. Điều này chỉ được gọi khi Bộ điều khiển đã trả về một ViewResult.


Câu trả lời tuyệt vời. Tôi không thể tìm ra lý do tại sao một phiên bản trực tiếp của đối tượng Controller không cho phép tôi gọi Dispose () trên nó, nhưng có vẻ như tôi cần tạo một phiên bản mới của nó bằng giao diện IDisposable. Điều này đã làm việc cho tôi!
MegaMatt

Vậy ... HttpContextlà nam à? Bây giờ tôi thực sự bối rối.
Chef_Code
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.