依赖注入与Ninject,MVC 3并使用服务定位器模式 [英] Dependency Injection with Ninject, MVC 3 and using the Service Locator Pattern

查看:163
本文介绍了依赖注入与Ninject,MVC 3并使用服务定位器模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因为我读了一个关于另一个stackoverflow问题的答案(这个确切的一个我现在不在意),那里的用户说了一些类似如果你打电话给服务定位器,你在做



这是一个声望很高的人(在十万,我认为),所以我倾向于认为这个人可能会知道他们'重新谈论自从我第一次开始学习以及与单元测试相关的程度,我一直在为自己的项目使用DI。这是我现在相当舒服的一件事,我认为我知道我在做什么。



但是,有很多地方我一直在使用服务定位器来解决项目中的依赖关系。一般来说,我的ModelBinder实现是一个主要的例子。



典型模型绑定器的示例。

 code> public class FileModelBinder:IModelBinder {
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext){
ValueProviderResult value = bindingContext.ValueProvider.GetValue(id);

IDataContext db = Services.Current.GetService< IDataContext>();
return db.Files.SingleOrDefault(i => i.Id == id.AttemptValue);
}
}

不是一个真正的实现 - 只是一个快速例如



由于ModelBinder的实现需要一个新的实例,当Binder是第一个请求时,不可能使用依赖注入这个特定实现的构造函数。



我的很多类都是这样的。另一个例子是缓存到期过程,当缓存对象在我的网站中到期时运行方法。我运行一堆数据库调用,而不是。我也在使用服务定位器来获取所需的依赖关系。



最近我发现另一个问题(我在这里发布了一个问题)是我所有的控制器需要使用DI的IDataContext实例 - 但是一个操作方法需要不同的IDataContext实例。幸运的是,Ninject以命名的依赖来救援。但是,这感觉像是一个污泥,而不是一个真正的解决方案。



我以为我至少理解了分离关注的概念,但似乎有一些东西从根本上说,我如何理解依赖注入和服务定位器模式 - 我不知道是什么。



我目前的理解方式 - 这可能是也就是说,至少在MVC中,ControllerFactory会为控制器寻找一个构造函数,并调用服务定位器本身来获取所需的依赖关系,然后将它们传入。但是,我可以理解并不是所有的类和不是有一个工厂来创建它们。所以在我看来,一些服务定位器模式是可以接受的...但是...


  1. 什么时候不能接受? >
  2. 当我应该重新思考我如何使用服务定位器模式时,应该怎样看待什么样的模式?

  3. 我的ModelBinder实现错误?如果是这样,我需要学习如何解决它?

  4. 在另一个问题中,这个用户的一个 Mark Seemann 推荐了一个抽象工厂 - 这如何相关?

我猜是这样 - 我不能真正想到任何其他问题,以帮助我的理解,但任何额外的信息是非常感谢。



我明白DI可能不是一切的答案,我可能会如何实现它,但是,它似乎工作的方式,我期望它与单元测试和什么不。



我不是在寻找代码来修复我的示例实现 - 我正在寻找学习,寻找一个解释来解决我的有缺陷的理解。



我希望stackoverflow.com有能力保存草稿问题。我也希望任何回答这个问题的人得到适当的声誉来回答这个问题,因为我认为我要求很多。谢谢,提前。


解决方案

请考虑以下内容:

  public class MyClass 
{
IMyInterface _myInterface;
IMyOtherInterface _myOtherInterface;

public MyClass(IMyInterface myInterface,IMyOtherInterface myOtherInterface)
{
// Foo

_myInterface = myInterface;
_myOtherInterface = myOtherInterface;
}
}

通过这种设计,我能够表达依赖性要求对于我的类型该类型本身不负责知道如何实例化任何依赖性,它们通过任何使用的解析机制(通常是IoC容器)而被赋予它(注入)。而$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $; $;;;;;;;;;;;;;;;;;;;;;;
IMyOtherInterface _myOtherInterface;

public MyClass()
{
// Bar

_myInterface = ServiceLocator.Resolve< IMyInterface>();
_myOtherInterface = ServiceLocator.Resolve< IMyOtherInterface>();
}
}

我们的课程现在依赖于创建specfic实例,但是通过委派给服务定位器。在这个意义上,服务位置可以被认为是一种反模式,因为你没有暴露依赖关系,而是允许可以通过编译来捕捉到的问题,从而引发到运行时。 (一个很好的阅读是 here )。你隐藏的复杂性。



其中一个选择真的取决于你的建筑物和它提供的服务。通常,如果您从零开始构建应用程序,我会一直选择DI。它提高了可维护性,促进了模块化,使测试类型变得更加容易。但是,以ASP.NET MVC3为例,您可以轻松实现SL,作为其设计的一部分。



您可以随时使用复合设计,您可以在其中使用IoC / DI与SL,很像使用公共服务定位器。您的组件可以通过DI进行连接,但通过SL暴露。您甚至可以将组合投入组合中,并使用像Managed Extensibility Framework(本身支持DI,但也可以连接到其他IoC容器或服务定位器)之类的东西。这是一个很大的设计选择,通常我的建议是可能的IoC / DI。



您的具体设计我不会说是错误的。在这种情况下,您的代码不负责创建模型绑定器本身的实例,这取决于框架,因此您无法控制,您使用服务定位器可能很容易更改访问IoC容器。但是,在IoC容器上调用解决方案的行为你不会考虑该服务位置?



以抽象的工厂模式出厂专门制作特定类型。您不注册解析类型,您实际上注册一个抽象工厂,并构建您可能需要的任何类型。使用服务定位器,它旨在定位服务并返回这些实例。从公约的角度来看,但是行为方式却非常不同。


Something that has been bugging me since I read an answer on another stackoverflow question (the precise one eludes me now) where a user stated something like "If you're calling the Service Locator, you're doing it wrong."

It was someone with a high reputation (in the hundred thousands, I think) so I tend to think this person might know what they're talking about. I've been using DI for my projects since I first started learning about it and how well it relates to Unit Testing and what not. It's something I'm fairly comfortable with now and I think I know what I'm doing.

However, there are a lot of places where I've been using the Service Locator to resolve dependencies in my project. Once prime example comes from my ModelBinder implementations.

Example of a typical model binder.

public class FileModelBinder : IModelBinder {
    public object BindModel(ControllerContext controllerContext,
                            ModelBindingContext bindingContext) {
        ValueProviderResult value = bindingContext.ValueProvider.GetValue("id");

        IDataContext db = Services.Current.GetService<IDataContext>();
        return db.Files.SingleOrDefault(i => i.Id == id.AttemptedValue);
    }
}

not a real implementation - just a quick example

Since the ModelBinder implementation requires a new instance when a Binder is first requested, it's impossible to use Dependency Injection on the constructor for this particular implementation.

It's this way in a lot of my classes. Another example is that of a Cache Expiration process that runs a method whenever a cache object expires in my website. I run a bunch of database calls and what not. There too I'm using a Service Locator to get the required dependency.

Another issue I had recently (that I posted a question on here about) was that all my controllers required an instance of IDataContext which I used DI for - but one action method required a different instance of IDataContext. Luckily Ninject came to the rescue with a named dependency. However, this felt like a kludge and not a real solution.

I thought I, at least, understood the concept of Separation of Concerns reasonably well but there seems to be something fundamentally wrong with how I understand Dependency Injection and the Service Locator Pattern - and I don't know what that is.

The way I currently understand it - and this could be wrong as well - is that, at least in MVC, the ControllerFactory looks for a Constructor for a Controller and calls the Service Locator itself to get the required dependencies and then passes them in. However, I can understand that not all classes and what not have a Factory to create them. So it seems to me that some Service Locator pattern is acceptable...but...

  1. When is it not acceptable?
  2. What sort of pattern should I be on the look out for when I should rethink how I'm using the Service Locator Pattern?
  3. Is my ModelBinder implementation wrong? If so, what do I need to learn to fix it?
  4. In another question along the lines of this one user Mark Seemann recommended an Abstract Factory - How does this relate?

I guess that's it - I can't really think of any other question to help my understanding but any extra information is greatly appreciated.

I understand that DI might not be the answer to everything and I might be going overboard in how I implement it, however, it seems to work the way I expect it to with Unit Testing and what not.

I'm not looking for code to fix my example implementation - I'm looking to learn, looking for an explanation to fix my flawed understanding.

I wish stackoverflow.com had the ability to save draft questions. I also hope whoever answers this question gets the appropriate amount of reputation for answering this question as I think I'm asking for a lot. Thanks, in advance.

解决方案

Consider the following:

public class MyClass
{
  IMyInterface _myInterface;
  IMyOtherInterface _myOtherInterface;

  public MyClass(IMyInterface myInterface, IMyOtherInterface myOtherInterface)
  {
    // Foo

    _myInterface = myInterface;
    _myOtherInterface = myOtherInterface;
  }
}

With this design I am able to express the dependency requirements for my type. The type itself isn't responsible for knowing how to instantiate any of the dependencies, they are given to it (injected) by whatever resolving mechanism is used [typically an IoC container]. Whereas:

public class MyClass
{
  IMyInterface _myInterface;
  IMyOtherInterface _myOtherInterface;

  public MyClass()
  {
    // Bar

    _myInterface = ServiceLocator.Resolve<IMyInterface>();
    _myOtherInterface = ServiceLocator.Resolve<IMyOtherInterface>();
  }
}

Our class is now dependent on creating the specfic instances, but via delegation to a service locator. In this sense, Service Location can be considered an anti-pattern because you're not exposing dependencies, but you are allowing problems which can be caught through compilation to bubble up into runtime. (A good read is here). You hiding complexities.

The choice between one or the other really depends on what your building on top of and the services it provides. Typically if you are building an application from scratch, I would choose DI all the time. It improves maintainability, promotes modularity and makes testing types a whole lot easier. But, taking ASP.NET MVC3 as an example, you could easily implement SL as its baked into the design.

You can always go for a composite design where you could use IoC/DI with SL, much like using the Common Services Locator. You component parts could be wired up through DI, but exposed through SL. You could even throw composition into the mix and use something like the Managed Extensibility Framework (which itself supports DI, but can also be wired to other IoC containers or service locators). It's a big design choice to make, generally my recommendation would be for IoC/DI where possible.

Your specific design I wouldn't say is wrong. In this instance, your code is not responsible for creating an instance of the model binder itself, that's up to the framework so you have no control over that but your use of the service locator could probably be easily changed to access an IoC container. But the action of calling resolve on the IoC container...would you not consider that service location?

With an abstract factory pattern the factory is specialised at creating specific types. You don't register types for resolution, you essentially register an abstract factory and that builds any types that you may require. With a Service Locator it is designed to locate services and return those instances. Similar from an convention point of view, but very different in behaviour.

这篇关于依赖注入与Ninject,MVC 3并使用服务定位器模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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