使用Ninject MVC3时的HttpContextBase.Request异常

时间:2013-08-20 22:06:09

标签: asp.net-mvc-4 ninject

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

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

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

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

如果我直接致电HttpContext.Current.Request.UserHostAddress,它可以正常运行

ExampleService.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
    }
}

Global.asax中

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

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

我在这里遗漏了一些东西,但我看不清楚

1 个答案:

答案 0 :(得分:1)

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

对于ASP.NET应用程序,只要AppDomain存在,就只有一个HttpApplication实例存在。所以这里发生的是注入的ExampleService被提升为每个应用程序域一个(或单个),并且由于ExampleService坚持,所以它的依赖性HttpContextBase

这里的问题当然是HTTP上下文-per定义 - 不能超过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();
}