0

我有一个依赖于 HttpContextBase 的服务。

Ninject 已经为我注入了它,因为它在 MvcModule 中设置为在new HttpContextWrapper(HttpContext.Current)请求 HttpContextBase 时返回

我想在 Application_AuthenticateRequest 中使用此服务,所以我使用属性注入,以便 Ninject 为我解决它

当我尝试访问 HttpContextBase 上的 Request.UserHostAddress 时,出现Value does not fall within the expected range异常

如果我HttpContext.Current.Request.UserHostAddress直接打电话,它可以正常工作

示例服务.cs

public class ExampleService : IExampleService {
    HttpContextBase _contextBase;

    public ExampleService(HttpContextBase contextBase) {
        _contextBase = contextBase;
    }

    public void DoSomething() {
        var ip = HttpContext.Current.Request.UserHostAddress;  <== this works
        ip = _contextBase.Request.UserHostAddress;  <== this fails
    }
}

全球.asax

[Inject]
public IExampleService ExampleService { get; set; }

public void Application_AuthenticateRequest() {
    ExampleService.DoSomething();
}

我在这里遗漏了一些东西,但我看不到什么

4

1 回答 1

1

注入到类中的依赖项与它们注入的类一样长,因为该类包含对它们的引用。这意味着通常您应该防止注入生命周期短于包含类的依赖项,否则它们的生命周期会被“提升”,这可能会导致各种(通常难以跟踪)错误。

对于 ASP.NET 应用程序,始终只有一个HttpApplication实例与 AppDomain 一样长。所以这里发生的是注入ExampleService被提升为每个应用程序域一个(或单例),并且由于ExampleService存在,它的依赖项也是如此,HttpContextBase.

这里的问题当然是 HTTP 上下文 - 每个定义 - 不能超过 HTTP 请求。因此,您只存储HttpContextBase一次,但它会被所有其他请求重用。幸运的是 ASP.NET 会引发异常,否则您可能会遇到更多麻烦。不幸的是,这个例外不是很有表现力。在这种情况下,他们本可以做得更好。

解决方案是不要HttpApplication在/中注入依赖项MvcApplication。曾经!尽管当您递归地注入仅依赖于单例的单例时这样做很好,但很容易犯错,并且 Ninject 中没有验证机制会向您发出有关此错误的信号。

相反,总是IExampleService在每次调用时解决AuthenticateRequest. 这可确保您获得ExampleService正确的生命周期(希望配置为每个网络请求或更短)并防止此类错误。您可以调用DependencyResolver类来获取一个IExampleService或直接调用 Ninject Kernel。调用Kernel很好,因为Application_AuthenticateRequest可以被认为是Composition Root的一部分:

public void Application_AuthenticateRequest() {
    var service = DependencyResolver.Current.GetService<IExampleService>();
    service.DoSomething();
}
于 2013-08-21T07:38:44.640 回答