ASP.NET MVC& Windsor.Castle:使用依赖于HttpContext的服务

时间:2009-11-30 10:01:39

标签: asp.net-mvc inversion-of-control castle-windsor

我有几个依赖注入服务,这些服务依赖于HTTP上下文之类的东西。现在我在Application_Start处理程序中将它们配置为单例 Windsor容器,这显然是此类服务的问题。

处理此问题的最佳方法是什么?我正在考虑将它们设置为 transient ,然后在每次HTTP请求后释放它们。但是将HTTP上下文注入其中的最佳方式/地点是什么?控制器工厂或其他地方?

3 个答案:

答案 0 :(得分:24)

就像Mark说的那样,你需要将这些依赖于http的服务注册为PerWebRequest或Transient。这是一个示例,说明如何注册和注入HttpRequest或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)));  
}

使用HttpRequestBase代替HttpRequest,您可以轻松地将其模拟出来进行测试。 另外,不要忘记在web.config中注册PerWebRequestLifestyleModule

答案 1 :(得分:5)

使用Castle Windsor,您可以使用PerWebRequest生命周期 - 这应该与您的要求非常吻合。

这意味着您可以将HTTP内容注入您的服务,容器将负责适当的生命周期管理。但是,这需要您将所有这些服务(以及这些服务的所有使用者等)注册为PerWebRequest(或Transient),因为如果您将它们注册为Singletons,它们将保持陈旧(并且可能处置)的上下文。 / p>

答案 2 :(得分:4)

我刚遇到了同样的问题,但我的解决方案有所不同。

界面:

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

实现:

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

然后我将IHttpContextProvider注册为容器中的单身人士。 对于DI来说,我仍然是一个新手,所以也许我过于复杂化,但从我能理解的,我不能有任何单件组件取决于PerWebRequest生活方式组件,这是有道理的(但是这就是所有例子的作用)。在我的解决方案中,我依赖HttpContext.Current在一个孤立的组件中,我对测试它不感兴趣。但是,每个需要访问HTTP上下文的组件都可以通过依赖IHttpContextProvider来获取它,并根据需要轻松模拟它。

我真的过于复杂化,或者我的解决方案有什么警告吗?