将依赖项注入自定义模型绑定器并使用 Ninject 使用 InRequestScope [英] Inject a dependency into a custom model binder and using InRequestScope using Ninject

查看:35
本文介绍了将依赖项注入自定义模型绑定器并使用 Ninject 使用 InRequestScope的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将 NInject 与 NInject.Web.Mvc 一起使用.

I'm using NInject with NInject.Web.Mvc.

首先,我创建了一个简单的测试项目,在该项目中,我希望在同一 Web 请求期间在控制器和自定义模型绑定器之间共享 IPostRepository 的实例.在我的实际项目中,我需要这个,因为我遇到了 IEntityChangeTracker 问题,我实际上有两个存储库访问同一个对象图.所以为了让我的测试项目保持简单,我只是想分享一个虚拟存储库.

To start with, I've created a simple test project in which I want an instance of IPostRepository to be shared between a controller and a custom model binder during the same web request. In my real project, I need this because I'm getting IEntityChangeTracker problems where I effectively have two repositories accessing the same object graph. So to keep my test project simple, I'm just trying to share a dummy repository.

我遇到的问题是它适用于第一个请求,仅此而已.相关代码如下.

The problem I'm having is that it works on the first request and that's it. The relevant code is below.

NInjectModule:

NInjectModule:

public class PostRepositoryModule : NinjectModule
{
    public override void Load()
    {
        this.Bind<IPostRepository>().To<PostRepository>().InRequestScope();
    }
}

自定义模型绑定器:

public class CustomModelBinder : DefaultModelBinder
{
    [Inject]
    public IPostRepository repository { get; set; }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        repository.Add("Model binder...");

        return base.BindModel(controllerContext, bindingContext);
    }
}

public class HomeController : Controller
{
    private IPostRepository repository;

    public HomeController(IPostRepository repository)
    {
        this.repository = repository;
    }

    public ActionResult Index(string whatever)
    {
        repository.Add("Action...");

        return View(repository.GetList());
    }
}

Global.asax:

Global.asax:

protected override void OnApplicationStarted()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders.Add(typeof(string), kernel.Get<CustomModelBinder>());
}

这样做实际上是创建 IPostRepository 的 2 个单独实例而不是共享实例.关于将依赖项注入我的模型绑定器,我在这里缺少一些东西.我上面的代码基于 NInject.Web.Mvc wiki 但我都试过了.

Doing it this way is actually creating 2 separate instances of IPostRepository rather than the shared instance. There's something here that I'm missing with regards to injecting a dependency into my model binder. My code above is based on the first setup method described in the NInject.Web.Mvc wiki but I have tried both.

当我确实使用第二种方法时,IPostRepository 只会在第一个 Web 请求中共享,之后它会默认不共享实例.然而,当我开始工作时,我使用了默认的 DependencyResolver 因为我一生都无法弄清楚如何使用 NInject 做同样的事情(因为内核被隐藏在NInjectMVC3 类).我是这样做的:

When I did use the second method, IPostRepository would be shared only for the very first web request, after which it would default to not sharing the instance. However, when I did get that working, I was using the default DependencyResolver as I couldn't for the life of me figure out how to do the same with NInject (being as the kernel is tucked away in the NInjectMVC3 class). I did that like so:

ModelBinders.Binders.Add(typeof(string),
    DependencyResolver.Current.GetService<CustomModelBinder>());

我怀疑这只是第一次起作用的原因是因为这不是通过 NInject 解决的,所以生命周期实际上是由 MVC 直接处理的(尽管这意味着我不知道它是如何解决依赖关系的).

I suspect the reason this worked the first time only is because this isn't resolving it via NInject, so the lifecycle is really being handled by MVC directly (although that means I have no idea how it's resolving the dependency).

那么我该如何正确注册我的模型绑定器并让 NInject 注入依赖项?

So how do I go about properly registering my model binder and getting NInject to inject the dependency?

推荐答案

我最终按照建议通过工厂解决了这个问题.但是,我只是不知道如何使用 Ninject.Extensions.Factory 来实现这一点,这是我的首选.这是我最后的结果:

I eventually managed to solve it with a factory as suggested. However, I just could not figure out how to accomplish this with Ninject.Extensions.Factory which is what I would've preferred. Here is what I ended up with:

工厂界面:

public interface IPostRepositoryFactory
{
    IPostRepository CreatePostRepository();
}

工厂实现:

public class PostRepositoryFactory : IPostRepositoryFactory
{
    private readonly string key = "PostRepository";

    public IPostRepository CreatePostRepository()
    {
        IPostRepository repository;

        if (HttpContext.Current.Items[key] == null)
        {
            repository = new PostRepository();
            HttpContext.Current.Items.Add(key, repository);
        }
        else
        {
            repository = HttpContext.Current.Items[key] as PostRepository;
        }

        return repository;
    }
}

工厂的 Ninject 模块:

The Ninject module for the factory:

public class PostRepositoryFactoryModule : NinjectModule
{
    public override void Load()
    {
        this.Bind<IPostRepositoryFactory>().To<PostRepositoryFactory>();
    }
}

自定义模型绑定器:

public class CustomModelBinder : DefaultModelBinder
{
    private IPostRepositoryFactory factory;

    public CustomModelBinder(IPostRepositoryFactory factory)
    {
        this.factory = factory;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        IPostRepository repository = factory.CreatePostRepository();

        repository.Add("Model binder");

        return base.BindModel(controllerContext, bindingContext);
    }
}

控制器:

public class HomeController : Controller
{
    private IPostRepository repository;

    public HomeController(IPostRepositoryFactory factory)
    {
        this.repository = factory.CreatePostRepository();
    }

    public ActionResult Index(string whatever)
    {
        repository.Add("Action method");

        return View(repository.GetList());
    }
}

Global.asax 连接自定义模型绑定器:

Global.asax to wire up the custom model binder:

protected override void OnApplicationStarted()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders.Add(typeof(string), kernel.Get<CustomModelBinder>());
}

在我看来,这给了我想要的输出:

Which in my view, gave me the desired output of:

模型绑定
动作方法

这篇关于将依赖项注入自定义模型绑定器并使用 Ninject 使用 InRequestScope的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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