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

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

问题描述

我正在尝试建立一个新的项目,并且添加了一个新的class 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.

在上一个项目中,我使用了代码

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 Modules,在StackOverflow和Google上进行一些搜索后,我已经找到了以下代码:
public class 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请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误的更多
信息及其在代码中的位置。

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.ActivationException:激活
字符串时出错没有匹配的绑定可用,并且类型不是
自绑定。激活路径:

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

5)将相关性字符串注入到类型为HttpRequest的
构造函数的参数文件中

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

4)将依赖关系HttpRequest注入到类型为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注入到参数
membershipService中,类型为HomeController的构造函数

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

1)请求家庭控制器

有人可以指出我出错的地方吗?

Can someone point out where I'm going wrong?

谢谢,
John

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.

但是,Steven的解决方案只将问题转移到其他服务。毕竟,实现 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不是抽象的,所以不能交换或嘲笑。为了确保我们处理抽象,Microsoft提供了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.

请参阅这个答案有关如何实现的更多信息。

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

Steven的解决方案还需要创建一个 Facade 围绕 HttpContext 。虽然这并不能帮助您解决现有问题,但我同意,如果您的 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天全站免登陆