我正在尝试建立一个新项目,我添加了一个新类 MembershipService,它需要在其构造函数中传递 HttpContext。
在之前的项目中我使用了代码
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMembershipService>()
.To<MembershipService>()
.InRequestScope()
.WithConstructorArgument("context", HttpContext.Current);
....
}
但是在我使用 Ninject 模块的新项目中,在 StackOverflow 和 Google 上进行了一些搜索之后,我得出了以下代码: 公共(public)类 ServiceHandlerModule : NinjectModule {
public override void Load()
{
Bind<IMembershipService>()
.To<MembershipService>()
.WithConstructorArgument("context", ninjectContext=> HttpContext.Current);
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining(typeof(NinjectWebCommon))
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining<BrandServiceHandler>()
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
}
}
但是,我得到以下错误:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: Ninject.ActivationException: Error activating string No matching bindings are available, and the type is not self-bindable. Activation path:
5) Injection of dependency string into parameter filename of constructor of type HttpRequest
4) Injection of dependency HttpRequest into parameter request of constructor of type HttpContext
3) Injection of dependency HttpContext into parameter httpContext of constructor of type MembershipService
2) Injection of dependency IMembershipService into parameter membershipService of constructor of type HomeController
1) Request for HomeController
有人能指出我哪里错了吗?
谢谢, 约翰
最佳答案
Steven 关于 HttpContext
是运行时值的说法是正确的。它的值甚至在应用程序编写时都没有填充。
如果您考虑一下,这是有道理的,因为应用程序应该在任何单个用户上下文之外进行初始化。
但是,Steven 的解决方案只是将问题转移到了不同的服务上。毕竟,实现 IUserContext
的类仍然需要将 HttpContext
作为依赖。
解决方案是使用 Abstract Factory允许在运行时而不是在工厂连接时访问 HttpContext
实例。
Important: HttpContext is not an abstraction, so it cannot be swapped or mocked. To ensure we are dealing with an abstraction, Microsoft has provided the HttpContextBase abstract class and the default concrete type HttpContextWrapper. HttpContextBase has exactly the same interface as HttpContext. You should always use HttpContextBase as the abstract reference type within your services, not HttpContext.
考虑到这两点,您可以为您的 HttpContext
创建一个工厂,如下所示:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
然后可以修改您的 MembershipService
以在其构造函数中接受 IHttpContextFactory
:
public class MembershipService : IMembershipService
{
private readonly IHttpContextFactory httpContextFactory;
// This is called at application startup, but note that it
// does nothing except get our service(s) ready for runtime.
// It does not actually use the service.
public MembershipService(IHttpContextFactory httpContextFactory)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
// Make sure this is not called from any service constructor
// that is called at application startup.
public void DoSomething()
{
HttpContextBase httpContext = this.httpContextFactory.Create();
// Do something with HttpContext (at runtime)
}
}
并且您只需要在组合时注入(inject) HttpContextFactory
。
kernel.Bind<IHttpContextFactory>()
.To<HttpContextFactory>();
kernel.Bind<IMembershipService>()
.To<MembershipService>();
不过,仅此一项可能无法解决整个问题。您需要确保应用程序的其余部分在准备就绪之前不会尝试使用 HttpContext
。就 DI 而言,这意味着您不能在应用程序启动中组成的任何类型的构造函数或其中一个构造函数调用的任何服务成员中使用 HttpContext
。要解决这个问题,您可能需要创建额外的抽象工厂,以确保这些服务在 HttpContext
准备就绪之前不会调用 IMembershipService
的成员。
参见 this answer有关如何实现该目标的更多信息。
Steven 的解决方案还需要创建一个 Facade围绕 HttpContext
。虽然这并不能真正帮助解决手头的问题,但我同意,如果您的 MembershipService
(可能还有其他服务)仅使用 HttpContext< 的少量成员,这可能是个好主意
。通常,此模式旨在使复杂对象更易于使用(例如将其扁平化为可能嵌套在其层次结构深处的几个成员)。但是您确实需要权衡添加另一种类型的额外维护与在您的应用程序中使用 HttpContext
的复杂性(或换出其中一部分的值(value))来做出该决定。
关于c# - MVC5 Ninject 绑定(bind)和 HttpContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28254247/