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

发布于 2024-08-12 15:51:39 字数 234 浏览 7 评论 0原文

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

处理这个问题的最佳方法是什么?我正在考虑让它们暂时,然后在每个 HTTP 请求后释放它们。但是将 HTTP 上下文注入其中的最佳方式/位置是什么?控制器工厂还是其他地方?

I have several dependency injection services which are dependent on stuff like HTTP context. Right now I'm configuring them as singletons the Windsor container in the Application_Start handler, which is obviously a problem for such services.

What is the best way to handle this? I'm considering making them transient and then releasing them after each HTTP request. But what is the best way/place to inject the HTTP context into them? Controller factory or somewhere else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

随波逐流 2024-08-19 15:51:39

正如 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

Just like Mark said, you need to register these http-dependent services either as PerWebRequest or Transient. Here's a sample that shows how to register and inject a HttpRequest or 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)));  
}

By using HttpRequestBase instead of HttpRequest you can easily mock it out for testing.
Also, don't forget to register PerWebRequestLifestyleModule in your web.config.

那小子欠揍 2024-08-19 15:51:39

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

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

With Castle Windsor you can use the PerWebRequest lifetime - that should fit pretty well with your requirements.

That means you can just inject the HTTP stuff into your services, and the container will take care of the proper lifetime management. However, this requires you to also register all these services (and all consumers of those services and so on) as PerWebRequest (or Transient) because if you register them as Singletons, they will hold on to stale (and possibly disposed) contexts.

天煞孤星 2024-08-19 15:51:39

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

接口:

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 来获取它,并根据需要轻松模拟它。

我真的让事情变得过于复杂了吗?还是我的解决方案中有任何警告?

I just ran into this exact same problem, but my solution is somewhat different.

Interface:

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

Implementation:

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

I then register the IHttpContextProvider as a singleton in the container.
I'm still a bit of a newbie when it comes to DI, so maybe I'm over complicating things, but from what I can understand, I can't have any singleton components depend on PerWebRequest lifestyle components, which makes sense (but that's what all examples do). In my solution, I depend on HttpContext.Current in an isolated component and I'm not interested in testing that. But every component that needs access to the HTTP context can get that by depending on IHttpContextProvider and easily mock that as needed.

Am I really over complicating things or are there any caveats in my solution?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文