我有一个依赖于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();
}
我在这里遗漏了一些东西,但我看不清楚
答案 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();
}