将依赖项注入自定义模型绑定器并使用 Ninject 使用 InRequestScope [英] Inject a dependency into a custom model binder and using InRequestScope using Ninject
问题描述
我将 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屋!