Asp.net mvc 4 使用Ninject MVC3时出现HttpContextBase.Request异常

Asp.net mvc 4 使用Ninject MVC3时出现HttpContextBase.Request异常,asp.net-mvc-4,ninject,Asp.net Mvc 4,Ninject,我有一个依赖于HttpContextBase的服务 Ninject已经为我注入了这个,因为它在MvcModule中设置为在请求HttpContextBase时返回新的HttpContextWrapper(HttpContext.Current) 我想在Application_AuthenticateRequest中使用此服务,所以我使用属性注入,以便Ninject为我解析它 当我尝试访问HttpContextBase上的Request.UserHostAddress时,我得到一个值不在预期范围内

我有一个依赖于HttpContextBase的服务

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

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

当我尝试访问HttpContextBase上的Request.UserHostAddress时,我得到一个
值不在预期范围内
异常

如果我直接调用
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
    }
}

我在这里遗漏了一些东西,但我看不到注入类的依赖项在注入它们的类中存在多久,因为类持有对它们的引用。这意味着,一般来说,您应该防止注入配置了比包含类的生存期短的依赖项,因为否则它们的生存期会被“提升”,这可能会导致各种(通常难以跟踪)错误

在ASP.NET应用程序的情况下,始终只有一个
HttpApplication
实例与AppDomain的生命周期相同。因此,这里发生的是注入的
ExampleService
被提升为每个appdomain(或单例)一个,并且由于
ExampleService
一直存在,所以它的依赖项
HttpContextBase
也一直存在

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

解决方案是在
HttpApplication
/
mvcapapplication
中注入依赖项。曾经尽管在注入只依赖于单例的递归单例时这样做很好,但很容易出错,而且Ninject中没有向您发出此错误信号的验证机制

相反,每次调用
AuthenticateRequest
时,始终解析
IExampleService
。这样可以确保获得具有正确生存期的
ExampleService
(希望按照web请求或更短的时间进行配置),并防止此类错误。您可以调用
DependencyResolver
类来获取
IExampleService
,也可以直接调用Ninject
内核
。调用
内核
是可以的,因为
应用程序_AuthenticateRequest
可以被视为以下任务的一部分:

public void应用程序\u AuthenticateRequest(){
var service=DependencyResolver.Current.GetService();
服务。DoSomething();
}

我知道有一个HttpApplication实例,当使用
[Inject]
时,我会有一个长时间运行的IExampleService实例,但我认为该服务的唯一依赖项是HttpContextBase(它引用静态HttpContext.Current),Ninject会在每次请求时创建一个新实例,我会没事的。您的答案在每个HTTP请求上都非常有效,
HttpContext.Current
返回一个不同的
HttpContext
实例。您将一个实例(这些实例中的一个)传递到
HttpContextWrapper
中,该包装器在应用程序的生命周期中被重用。
[Inject]
public IExampleService ExampleService { get; set; }

public void Application_AuthenticateRequest() {
    ExampleService.DoSomething();
}
public void Application_AuthenticateRequest() {
    var service = DependencyResolver.Current.GetService<IExampleService>();
    service.DoSomething();
}