Asp.net mvc 4 使用Ninject MVC3时出现HttpContextBase.Request异常
我有一个依赖于HttpContextBase的服务 Ninject已经为我注入了这个,因为它在MvcModule中设置为在请求HttpContextBase时返回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时,我得到一个值不在预期范围内
新的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();
}