2009-11-30 31 views
12

Tôi có một số dịch vụ tiêm phụ thuộc phụ thuộc vào nội dung như ngữ cảnh HTTP. Ngay bây giờ tôi đang cấu hình chúng là singletons thùng chứa Windsor trong trình xử lý Application_Start, đây rõ ràng là một vấn đề đối với các dịch vụ đó.ASP.NET MVC & Windsor.Castle: làm việc với các dịch vụ phụ thuộc vào HttpContext

Cách tốt nhất để xử lý việc này là gì? Tôi đang xem xét làm cho chúng thoáng qua và sau đó phát hành chúng sau mỗi yêu cầu HTTP. Nhưng cách tốt nhất/nơi để tiêm bối cảnh HTTP vào chúng là gì? Nhà máy điều khiển hoặc ở nơi khác?

Trả lời

5

Với Castle Windsor, bạn có thể sử dụng thời gian PerWebRequest - điều đó phải phù hợp với yêu cầu của bạn.

Điều đó có nghĩa là bạn chỉ có thể đưa nội dung HTTP vào dịch vụ của mình và vùng chứa sẽ quản lý việc quản lý lâu dài phù hợp. Tuy nhiên, điều này yêu cầu bạn cũng phải đăng ký tất cả các dịch vụ này (và tất cả người tiêu dùng của các dịch vụ đó và vân vân) như PerWebRequest (hoặc Transient) bởi vì nếu bạn đăng ký chúng như là Singletons, chúng sẽ giữ các ngữ cảnh cũ (và có thể xử lý).

+0

Đánh dấu, cảm ơn thông tin - Tôi không biết về PerWebRequest. Tôi sẽ kiểm tra. –

+0

Đánh dấu, tôi đã xem xét PerWebRequest, nhưng tôi vẫn không thấy các dịch vụ có thể lấy HttpContext như thế nào. Khi tôi cố gắng để đăng ký một thể hiện của HttpContextBase nó trong container bản thân mình, nó không thành công sau khi yêu cầu thứ hai (kể từ khi một cá thể đã được đăng ký trong yêu cầu trước đó). Tôi không thể tìm thấy bất cứ điều gì trên Google cho đến nay ... –

+0

Tôi có thể đã hiểu lầm những gì bạn đang cố gắng làm, nhưng bạn không thể sử dụng HttpContext từ Application_Start vì tại thời điểm này có * là * không HttpContext (PerWebRequest hoặc không PerWebRequest). Bây giờ tôi nghĩ về nó, nó không có ý nghĩa để cố gắng kiểm soát tuổi thọ của HttpContext từ DI Container, vì cuộc đời này đã được quản lý bởi framework ASP.NET MVC.Những gì bạn có thể làm là móc vào một IControllerFactory tùy chỉnh và lấy HttpContext được phục vụ cho bạn tại thời điểm đó, và sau đó sử dụng một phương thức factory để kết nối mọi thứ khác phụ thuộc vào nó. –

24

Giống như Mark đã nói, bạn cần phải đăng ký các dịch vụ phụ thuộc http này dưới dạng PerWebRequest hoặc Tạm thời. Dưới đây là một ví dụ cho thấy làm thế nào để đăng ký và tiêm một HttpRequest hoặc HttpContext:

public class Service { 
    private readonly HttpRequestBase request; 

    public Service(HttpRequestBase request) { 
     this.request = request; 
    } 

    public string RawUrl { 
     get { 
      return request.RawUrl; 
     } 
    } 
} 

... 

protected void Application_Start(object sender, EventArgs e) { 
    IWindsorContainer container = new WindsorContainer(); 
    container.AddFacility<FactorySupportFacility>(); 
    container.AddComponentLifeStyle<Service>(LifestyleType.Transient); 

    container.Register(Component.For<HttpRequestBase>() 
     .LifeStyle.PerWebRequest 
     .UsingFactoryMethod(() => new HttpRequestWrapper(HttpContext.Current.Request))); 

    container.Register(Component.For<HttpContextBase>() 
     .LifeStyle.PerWebRequest 
     .UsingFactoryMethod(() => new HttpContextWrapper(HttpContext.Current))); 
} 

Bằng cách sử dụng HttpRequestBase thay vì HttpRequest bạn có thể dễ dàng thử nó ra để thử nghiệm. Ngoài ra, đừng quên đăng ký PerWebRequestLifestyleModule trong web.config của bạn.

+0

Cảm ơn Mauricio, đây là điều tôi đang tìm kiếm. –

+0

Có thể đáng nhắc lại rằng bạn cần phải thêm dòng: container.AddFacility (); Đây là một hình ảnh nhỏ cho tôi mà tôi đã bỏ lỡ ví dụ của bạn khi đọc lần đầu tiên. Cảm ơn sự giúp đỡ, rất hữu ích! – ArtificialGold

+0

Vì Windsor 2.5, 'FactorySupportFacility' không cần thiết nữa cho trường hợp này. –

4

Tôi chỉ gặp vấn đề tương tự, nhưng giải pháp của tôi hơi khác.

Interface:

public interface IHttpContextProvider 
{ 
    /// <summary> 
    /// Gets the current HTTP context. 
    /// </summary> 
    /// <value>The current HTTP context.</value> 
    HttpContextBase Current { get; } 
} 

Thực hiện:

/// <summary> 
/// A default HTTP context provider, returning a <see cref="HttpContextWrapper"/> from <see cref="HttpContext.Current"/>. 
/// </summary> 
public class DefaultHttpContextProvider : IHttpContextProvider 
{ 
    public HttpContextBase Current 
    { 
     get { return new HttpContextWrapper(HttpContext.Current); } 
    } 
} 

sau đó tôi đăng ký IHttpContextProvider như một singleton trong container. Tôi vẫn là một chút của một newbie khi nói đến DI, vì vậy có lẽ tôi là hơn những điều phức tạp, nhưng từ những gì tôi có thể hiểu, tôi không thể có bất kỳ thành phần singleton phụ thuộc vào các thành phần lối sống PerWebRequest, có ý nghĩa (nhưng đó là những gì tất cả các ví dụ làm). Trong giải pháp của tôi, tôi phụ thuộc vào HttpContext.Current trong một thành phần bị cô lập và tôi không quan tâm đến việc kiểm tra điều đó. Nhưng mọi thành phần cần truy cập vào ngữ cảnh HTTP có thể nhận được điều đó bằng cách tùy thuộc vào IHttpContextProvider và dễ dàng giả thiết khi cần.

Tôi có thực sự quá phức tạp hoặc có bất kỳ cảnh báo nào trong giải pháp của mình không?

+1

Tôi nên đề cập, theo cách này, không có dịch vụ nào của tôi phụ thuộc vào ngữ cảnh HTTP hiện tại cần phải được đăng ký là PerWebRequest/Transient. – Siewers

+0

Nó hoạt động tốt, cảm ơn. –

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