MVC5 Ninject绑定和HttpContext的 [英] MVC5 Ninject binding and HttpContext

查看:311
本文介绍了MVC5 Ninject绑定和HttpContext的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想建立一个新的项目,我添加了一个新的类的 MembershipService 的是需要的的HttpContext 的在它的构造函数传递。

I am trying to set up a new project and I've added a new class MembershipService that requires the HttpContext to be passed in it's constructor.

在我用code一previous项目

In a previous project I used the code

    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IMembershipService>()
            .To<MembershipService>()
            .InRequestScope()
            .WithConstructorArgument("context", HttpContext.Current);
       ....
    }

然而,在新的项目中,我使用Ninject模块,后在计算器上和谷歌一些搜索,我拿出code如下:
    公共类ServiceHandlerModule:NinjectModule
    {

However in the new project I'm using Ninject Modules, and after some searching on StackOverflow and Google, I've come up with the code below: public class 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();
        });

    }
}

不过,我得到以下错误:

However, I get the error below:

说明:在执行过程中发生未处理的异常
  当前Web请求。有关详情,请堆栈跟踪
  有关错误的信息以及它起源于code。

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.

异常详细信息:Ninject.Activati​​onException:错误激活
  字符串匹配没有绑定可用,类型不
  自绑定。激活路径:

Exception Details: Ninject.ActivationException: Error activating string No matching bindings are available, and the type is not self-bindable. Activation path:

5)的依赖字符串注入的参数文件名
  类型的构造型Htt prequest

5) Injection of dependency string into parameter filename of constructor of type HttpRequest

4)依赖型Htt prequest的注入的参数要求
  类型的构造函数的HttpContext

4) Injection of dependency HttpRequest into parameter request of constructor of type HttpContext

3)依赖的HttpContext的注入参数的HttpContext的
  类型MembershipService的构造

3) Injection of dependency HttpContext into parameter httpContext of constructor of type MembershipService

2)的依赖IMembershipService的注入参数
  类型的HomeController的构造membershipService

2) Injection of dependency IMembershipService into parameter membershipService of constructor of type HomeController

1)申请的HomeController

1) Request for HomeController

有人能指出我要去哪里错了吗?

Can someone point out where I'm going wrong?

谢谢,
约翰·

Thanks, John

推荐答案

史蒂芬是对有关的HttpContext 是一个运行值。它的价值甚至不填充的应用程序是由时间。

Steven was right about the HttpContext being a runtime value. Its values are not even populated at the time the application is composed.

这是有道理的,如果你仔细想想,因为应用程序应任何个人用户上下文之外进行初始化。

This makes sense if you think about it because the application should be initialized outside of any individual user context.

不过,史蒂芬的解决方案只提出问题,以不同的服务。毕竟,实现 IUserContext 仍然需要走班的HttpContext 作为一个依赖。

However, Steven's solution only moved the problem to a different service. After all, the class that implements IUserContext will still need to take HttpContext as a dependency.

解决方案是使用抽象工厂,以允许的HttpContext 实例在运行时访问,而不是当工厂接线。

The solution is to use an Abstract Factory to allow the HttpContext instance to be accessed at runtime instead of when the factory is wired up.

重要:的HttpContext是不是一种抽象,因此它不能被交换或嘲笑。为了确保我们正在处理的一个抽象,微软已经提供了HttpContextBase抽象类和默认的具体类型HttpContextWrapper。 HttpContextBase具有完全相同的接口的HttpContext。你应该总是使用HttpContextBase作为抽象的引用类型的服务中,而不是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 ,如下:

With those 2 things in mind, you can create a factory for your HttpContext, as follows:

public interface IHttpContextFactory
{
    HttpContextBase Create();
}

public class HttpContextFactory
    : IHttpContextFactory
{
    public HttpContextBase Create()
    {
        return new HttpContextWrapper(HttpContext.Current);
    }
}

MembershipService 然后可以修改以接受 IHttpContextFactory 在其构造:

Your MembershipService can then be modified to accept an IHttpContextFactory in its constructor:

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)
    }
}

而你只需要注入 HttpContextFactory 在合成时间。

kernel.Bind<IHttpContextFactory>()
    .To<HttpContextFactory>();

kernel.Bind<IMembershipService>()
    .To<MembershipService>();

这可能独自解决不了整个问题,虽然。您需要确保您的应用程序的其他部分不会尝试使用的HttpContext 之前它已准备就绪。在DI而言,这意味着你不能使用的HttpContext 中被应用由任何类型构造或启动任何服务会员,这些构造函数调用之一。为了解决这个问题,您可能需要创建额外的抽象工厂,以确保这些服务不叫 IMembershipService 成员,直至的HttpContext 就绪。

This alone might not solve the entire issue, though. You need to ensure that the rest of your application does not try to use HttpContext before it is ready. In terms of DI, it means you can't use HttpContext in any constructor of types that are composed in application start or any service members that one of those constructors calls. To solve that, you may need to create additional abstract factories to ensure those services don't call members of IMembershipService until HttpContext is ready.

请参阅this回答有关如何实现这一目标的详细信息。

See this answer for more information about how to accomplish that.

史蒂芬的解决方案还entailed左右的HttpContext 门面 C>。虽然这并不能真正帮助解决手头的问题,我认为,这可能是一个好主意,如果你的 MembershipService (也许还有其他服务)只使用少数成员的的HttpContext 。一般情况下,这种模式是让一个复杂的对象,用更简单的工作(如压扁下来到可能深其层次结构内嵌套的几个成员)。但你真的需要权衡增加另一个类型与使用的复杂的额外的维护的HttpContext 您的应用程序(或换出它的一个部分的值)内使该决定。

Steven's solution also entailed creating a Facade around HttpContext. While this does not really help solve the problem at hand, I agree that this might be a good idea if your MembershipService (and perhaps other services) only uses a small number of members of HttpContext. Generally, this pattern is to make a complex object simpler to work with (such as flattening it down to a few members that may be nested deep within its hierarchy). But you really need to weigh the extra maintenance of adding another type against the complexity of using HttpContext within your application (or the value of swapping out a section of it) to make that decision.

这篇关于MVC5 Ninject绑定和HttpContext的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆