简体   繁体   English

ViewModel中的MVC4 / AutoFac依赖项注入

[英]MVC4/AutoFac dependency injection in ViewModel

I have DI implemented using the constructor pattern in our MVC4 application, it's been working perfectly for a couple of years now. 我已经在MVC4应用程序中使用构造函数模式实现了DI,它已经运行了好几年了。

Recently, we had a contractor come in the do some work. 最近,我们有一个承包商来做一些工作。 He needed to access our services layer in a view model and hard coded the services (and their repositories) in the constructor of the viewModel, bad, bad, bad. 他需要在视图模型中访问我们的服务层,并在viewModel的构造函数中对服务(及其存储库)进行硬编码,包括坏,坏,坏。

What he did was basically mess up our loose coupling we worked our buts off to implement and maintain. 他所做的基本上是弄乱了我们的松耦合,我们努力实现和维护。

Timing right now prevents us from re-writing his code at this time. 现在的时间阻止了我们此时重新编写他的代码。

Our ViewModels are in a separate assembly/project than the MVC application, as are our services layer and our repository layer. 我们的ViewModel与MVC应用程序位于单独的程序集/项目中,服务层和存储库层也是如此。

So far so good. 到现在为止还挺好。

How can i used dependency injection to resolve my services inside a view model. 我如何使用依赖注入来解析视图模型中的服务。

I say again, INSIDE A VIEW MODEL, NOT INSIDE THE CONTROLLER!! 我再说一遍,在视图模型内,而不在控制器内!! Doesn't matter to me if it uses the property injection model or constructor injection model. 对我来说,不管使用属性注入模型还是构造函数注入模型。

Thanks in advance for any assistance. 在此先感谢您的协助。

This is just plain hard. 这很简单。 As you know, in fact you stated: at the simplest level IoC and DI using something like Autofac is about constructor injection or property injection. 如您所知,您实际上已经说过:在最简单的级别上,IoC和DI使用Autofac之类的东西是关于构造函数注入或属性注入的。 This injection starts at the top of the tree, and happens all the way down the dependency chain through the constructors themselves (C requires V, so IV is injected; V requires R so IR is injected etc.). 这种注入从树的顶部开始,并一直贯穿整个构造函数本身的依赖关系链(C需要V,因此注入IV; V需要R,因此注入IR等)。

Constructor and Property injections are basically the same thing. 构造函数和属性注入基本上是同一件事。 The difference is usually just about parameter bloat in ctors (I say, and emphasise, usually ). 通常,差异仅在于ctor中的参数膨胀(我通常说并强调)。 I also assume you don't want to use a service locator, due to all the hard work you have put in to only use injection. 我还假设您不想使用服务定位器,因为您为了仅使用注入而付出的所有辛苦工作。

The easy part is therefore registering the VM types with Autofac to allow you to inject into the VM ctor or properties. 因此,最简单的部分是使用Autofac注册VM类型,以允许您注入VM ctor或属性。 The hard part is then instantiating VMs in the classes (controllers or otherwise) where you create the VMs, without hardcoding in Autofac references, and in such a way that you maintain your testability. 然后,最困难的部分是实例化创建VM的类(控制器或其他类)中的VM,而无需在Autofac引用中进行硬编码,并以保持可测试性的方式进行。

Can't avoid a change? 无法避免改变吗?

However I therefore can't see how you can get away from doing some minor change to your Controller's constructors (specifically the classes that create the ViewModels if these are not the Controllers): they need either a template ViewModel injected through the constructor (eugh) for you to then pad out with actual values, or they need a "factory" or "generator" injected to allow them to create viewmodels which are in turn injected. 但是,因此我看不到如何摆脱对Controller的构造函数的一些细微改动(特别是如果不是Controller的话,创建ViewModel的类):它们需要通过构造函数注入的模板ViewModel(eugh)然后您可以填充实际值,或者它们需要注入“工厂”或“生成器”,以允许他们创建依次注入的视图模型。 There are other things you would have to do to get this to work: it is just messy. 要使此功能正常工作,您还需要做其他事情:这只是一团糟。

Relationship Types 关系类型

Could you use the "A needs to create instance of B" relationship type , ie inject a Func<TViewModel> into the relevant methods in your instantiators of viewmodels to allow you to create when you have to (also allowing you to create many VMs in the case of a List<TViewModel> ). 您是否可以使用“ A需要创建B的实例” 关系类型Func<TViewModel>注入到视图模型实例化器的相关方法中,以允许您在需要时创建(还可以在其中创建许多VM List<TViewModel> )。 This will inject services into the VM ctor without you knowing about the injection. 这将在不知道注入的情况下将服务注入VM ctor。

The Dynamic Instantiation "Meaning" here would involve minimal changes to the constructors of your actual controllers, and would retain the same lifetime scopes as the services your controller uses. 这里的动态实例化“含义”将对实际控制器的构造函数进行最小的更改,并将保留与控制器使用的服务相同的生存期范围。

Action injection 动作注入

Note also that Autofac lets you inject parameters into Controller Action methods using the ExtensibleActionInvoker as an IActionInvoker so if you end up with nasty Controller ctor bloat with any of this, you could inject the Func<TViewModel> into the Action instead, as a last resort. 还请注意,Autofac允许您使用ExtensibleActionInvoker作为IActionInvoker将参数注入Controller Action方法中,因此,如果您因上述任何一个IActionInvoker讨厌的Controller ctor膨胀最终化,您可以将Func<TViewModel>注入Action中,作为最后的选择。

Or it's a service locator... 还是服务定位器...

It's either this or don't change your controller interface (including the constructor), but resort to a Service Locator using Autofac to create ViewModels with the dependencies injected within the methods where you need to instantiate ViewModels. 要么是此操作,要么不更改您的控制器接口(包括构造函数),而是求助于使用AutofacService Locator来创建ViewModel,并在需要实例化ViewModel的方法中注入依赖项。

What about VMs returned from Views or APIs? 从视图或API返回的VM呢?

None of this answers the other problem: what about a ViewModel that is passed back from the client into the Post Action as a parameter. 这些都不能解决另一个问题:如何将ViewModel作为参数从客户端传递回Post Action。 It is possible that registering your ViewModel types with Autofac will take care of that for you, but I have never had the need to try it and test it. 向Autofac注册您的ViewModel类型可能会为您解决这个问题,但是我从来不需要尝试和测试它。 If it doesn't you will have to use your template VM, or VM Func , with dependencies injected, and then copy the actual VM properties over to the template. 如果不是,则必须使用注入了依赖项的模板VM或VM Func ,然后将实际的VM属性复制到模板上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM