2009-05-15 33 views
6

Tôi đang sử dụng mẫu lưu trữ chung để lưu giữ dữ liệu của mình. Trên PageLoad, tôi đang tạo một Repository mới (từ IRepository), và trên PageUnload, tôi vứt bỏ nó.Mẫu MVP sử dụng biểu mẫu web và phân giải đối tượng DI

MasterPage/Trang có nên phụ trách việc khởi tạo các đối tượng để chuyển đến người trình bày hay người thuyết trình chịu trách nhiệm về điều này không? Tôi quan tâm nhiều hơn đến việc kiểm tra người trình bày so với trang (View) vì nó dễ dàng hơn để giả lập các giao diện được truyền cho người trình bày.

Ví dụ trang

public partial class _Default : System.Web.UI.Page 
{ 
    private IRepository _repo; 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (_repo == null) 
      _repo = new Repository(); 
     ConnectPresenter(); 
    } 

    private void ConnectPresenter() 
    { 
     _DefaultPresenter presenter = new _DefaultPresenter(_repo); 
    } 

    private void Page_Unload(object sender, EventArgs e) 
    { 
     if (_repo != null) 
      _repo.Dispose(); 
    } 
} 

Sẽ là một khung DI như StructureMap hoặc Ninject giúp đỡ trong trường hợp này? Nó sẽ được phụ trách xử lý các đối tượng như thế này?

Trả lời

6

Cả lớp trang và người thuyết trình cũng không phải xử lý trực tiếp với việc quản lý xây dựng hoặc vòng đời của bất kỳ phụ thuộc nào của nó - tất cả phải được xử lý bởi vùng chứa của bạn. Kể từ khi constructor injection không làm việc với WebForms, bạn sẽ cần phải phơi bày bất kỳ phụ thuộc cần thiết nào như các thuộc tính trong lớp. Ví dụ: bạn có thể thay đổi lớp học của mình thành:

public partial class _Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
    } 

    public _DefaultPresenter Presenter { get; set; } 
} 

Trang này không cần tham chiếu đến kho lưu trữ vì nó sẽ được đưa vào trình bày.

Phần còn lại của câu trả lời này dành riêng cho StructureMap - chi tiết có thể khác nhau đối với các vùng chứa khác.

Để kích hoạt tính năng tiêm setter, bạn cần phải cho StructureMap biết các thuộc tính cần điền. Một cách là áp dụng thuộc tính [SetterProperty] cho chính thuộc tính đó. Tuy nhiên, điều này có thể cảm thấy một chút xâm lấn để có chi tiết StructureMap trong các lớp học của bạn. Một cách khác là cấu hình StructureMap để nó biết loại thuộc tính nào cần tiêm. Ví dụ:

protected void Application_Start(object sender, EventArgs e) 
{ 
    ObjectFactory.Initialize(x => 
    { 
     x.Scan(scan => 
     { 
      scan.TheCallingAssembly(); 
      scan.WithDefaultConventions(); 
     }); 
     x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid); 
     x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>()); 
    }); 
} 

Phương thức SetAllProperties cho phép bạn nói Sơ đồ cấu trúc cách nhận biết các thuộc tính cần điền. Trong trường hợp này, tôi đang nói StructureMap để tiêm tất cả các trình diễn (giả sử chúng là tất cả trong cùng một không gian tên).

Bạn vẫn cần phải thực hiện tiêm setter trên mỗi yêu cầu.Với StructureMap, bạn sử dụng phương thức BuildUp() để chèn các phụ thuộc vào một cá thể hiện có. Bạn có thể làm điều đó trong Init hoặc Load sự kiện của mỗi trang hoặc một lớp cơ sở trang, nhưng một lần nữa, mà cảm thấy xâm lấn. Để giữ container ra khỏi lớp trang của bạn hoàn toàn, bạn có thể sử dụng các sự kiện PreRequestHandlerExecute của ứng dụng (trong global.asax hoặc một IHttpModule):

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e) 
{ 
    var application = (HttpApplication)sender; 
    var page = application.Context.CurrentHandler as Page; 
    if (page == null) return; 
    ObjectFactory.BuildUp(page); 
} 

Cuối cùng, nếu bạn muốn một cách rõ ràng Vứt bỏ IRepository, bạn có thể xử lý rằng trong trường hợp EndRequest:

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable; 
    if (disposable != null) disposable.Dispose(); 
} 

Lưu ý rằng điều này hoạt động đúng bởi vì trong khởi tạo chúng tôi nói với StructureMap để cache IRepository bởi hybrid, có nghĩa là "cho tôi cùng một ví dụ cho mỗi yêu cầu HTTP (hoặc chủ đề, nếu không chạy trong một trang web) ". Khi bạn truy xuất IRepository trong EndRequest, bạn sẽ nhận được cùng một tài khoản được sử dụng trong suốt yêu cầu và bạn có thể hủy bỏ nó.

2

Có, bạn cũng nên kiểm tra one of the walkthroughs out there of using DI with ASP.NET.

Có, việc hủy bỏ đối tượng Hành vi theo yêu cầu tại điểm thích hợp thường được quản lý bằng cách tích hợp Vùng chứa với ASP.NET.

Cách sắp xếp điển hình là tạo đối tượng sẽ chuyển từ từ Trang và Application/Module giây vào trong. Nói chung, bạn đánh dấu các thuộc tính [Inject] trên lớp học Page của mình, nhưng tùy thuộc vào cách bạn đã sắp xếp bộ ba của mình. Người trình bày nói chung có thể sử dụng Constructo Injection để khai báo những gì nó cần bất kể thử nghiệm của nó hay ASP.NET cotext. Sau đó, khi chạy, các phụ thuộc sẽ được thỏa mãn bởi DI. Tại thời điểm thử nghiệm, bạn vẫn có thể sử dụng DI, mặc dù trong các trường hợp khác, có thể tự nhiên hơn khi tạo một nhóm Hàng giả cùng với SUT và chuyển cho người trình bày.

Về việc sắp xếp triead wrt testing, tôi thấy this MSDN Mag article on using Ninject with xUnit.net by Justin Etheredge rất hữu ích, mặc dù được nhắm mục tiêu ở ASP.NET MVC.

+0

Xin lỗi vì không xem mã hoặc thẻ trong câu hỏi của bạn! Đã làm lại nó ngay bây giờ - hy vọng rằng cải thiện vấn đề! Sẽ xóa điều này nếu bạn xóa của bạn ... –

Các vấn đề liên quan