使用依赖注入没有任何DI框架 [英] Using Dependency Injection without any DI Framework

查看:129
本文介绍了使用依赖注入没有任何DI框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的仓库,DI,并试图在我的MVC 5项目来落实。

I am new to Repository and DI and trying to implement in my MVC 5 project.

我实现构造器注入凡在我控制器具有这样的构造:

I implemented Constructor Injection where in my controller has a constructor like this:

IBook _ibook;
public Test(IBook ibook)
{
   _ibook = ibook;
}

在没有任何DI框架,它抛出一个错误:没有空的构造

Without any DI framework, it throws an error: There is no empty constructor.

要避免这种情况,我加了下面多了一个构造函数:

To avoid this, I added one more constructor as below:

public Test ():this(new Book())
{

}

由于我是新来的DI,我不想用DI框架,它可以在以后抛出一些错误,我可能无法化解的风险我的项目。

Since I am new to DI, I don't want to risk my project by using DI framework which can later throw some error that I may not be able to resolve.

我想知道我可能会遇到什么问题,如果我不使用DI框架。

I want to know what issues I might encounter if I am not using DI Framework.

在情况下,建议,这DI框架是初学者的好?我见过NInject和统一几个视频。

In case it is recommended, which DI Framework is good for beginners? I have seen few videos of NInject and Unity.

推荐答案

有延缓的任何决定使用某种工具或图书馆,直到最后一刻负责一个好主意。凭借良好的设计,则可以在以后上添加DI库。这意味着,你的做法纯DI

It is a good idea to delay any decision to use some kind of tool or library until the last responsible moment. With a good design you can add a DI library later on. This means that you practice Pure DI.

MVC中的preferred拦截点是 IControllerFactory 抽象,因为它可以让你拦截MVC控制器的创造,这样做prevents你不必实现第二构造方法(是一个反模式)。尽管有可能使用的IDependencyResolver ,使用该抽象方便得多,因为它也通过MVC的调用来解决的东西,你通常不感兴趣的

The preferred interception point in MVC is the IControllerFactory abstraction since it allows you to intercept the creation of MVC controllers, and doing so prevents you from having to implement a second constructor (which is an anti-pattern). Although it is possible to use IDependencyResolver, the use of that abstraction is much less convenient because it is also called by MVC to resolve things you are typically not interested in.

自定义 IControllerFactory ,将作为您的成分根可以实现如下:

A custom IControllerFactory that will act as your composition root can be implemented as follows:

public sealed class CompositionRoot : DefaultControllerFactory
{
    private static string connectionString = 
        ConfigurationManager.ConnectionStrings["app"].ConnectionString;
    private static Func<BooksContext> bookContextProvider = GetCurrentBooksContext;
    private static IBookRepository bookRepo = new BookRepository(bookContextProvider);
    private static IOrderBookHandler orderBookHandler = new OrderBookHandler(bookRepo);

    protected override IController GetControllerInstance(RequestContext _, Type type) {
        // Unfortunately, because of MVC's design, controllers are not stateless, and 
        // you will have to create them per request.

        if (type == typeof(OrderBookController))
            return new HomeController(orderBookHandler);

        if (type == typeof(BooksController))
            return new BooksController(bookRepo);

        // [other controllers here]

        return base.GetControllerInstance(_, type);
    }

    private static BooksContext GetCurrentBooksContext() {
        return GetRequestItem<BooksContext>(() => new BooksContext(connectionString));
    }

    private static T GetRequestItem<T>(Func<T> valueFactory) where T : class {
        var context = HttpContext.Current;
        if (context == null) throw new InvalidOperationException("No web request.");
        var val = (T)context.Items[typeof(T).Name];
        if (val == null) context.Items[typeof(T).Name] = val = valueFactory();
        return val;
    }
}

您新的控制器工厂可以挂接到MVC如下:

Your new controller factory can be hooked into MVC as follows:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start() {
        ControllerBuilder.Current.SetControllerFactory(new CompositionRoot());

        // the usual stuff here
    }
}

当你练习纯DI,你通常会看到你的作文根是由,如果语句的大名单中。每根对象的一个​​声明您的应用程序。

When you practice Pure DI, you will typically see your composition root consist of a big list of if statements. One statement per root object in your application.

与纯DI出发有一些有趣的优势。最突出的一个是编译时支持的,因为这是后话,当你开始使用DI库会立即丧失。一些图书馆尝试让你验证的方式,编译器会做你的配置这种损耗降至最低;但这种验证在运行时完成和反馈周期是永远不会短,因为这其中的编译器可以给你。

Starting off with Pure DI has some interesting advantages. The most prominent one is compile time support, because this is something you will lose immediately when you start using a DI library. Some libraries try minimize this loss by allowing you to verify your configuration in a way that the compiler would do; but this verification is done at runtime and the feedback cycle is never as short as that which the compiler can give you.

请不要试图通过实施某种机制,使创建使用反射类型来简化开发,因为这样做你建立自己的DI库。有很多缺点这一点,例如你失去编译时支持,而没有得到任何回的好处现有的DI库可以给你。

Please don't be tempted to simplify development by implementing some mechanism that allows creating types using reflection, because in doing so you are building your own DI library. There are many downsides to this, e.g. you lose compile time support while not getting back any of the benefits that an existing DI library can give you.

当你的作文根开始变得难以维持,这是你应该考虑从单纯的DI切换到DI库的时刻。

When your composition root is starting to get hard to maintain, that is the moment you should consider switching from Pure DI to a DI library.

请注意,在我的例子组成的根,所有应用程序组件(除控制器)被定义为。单身意味着应用程序将仅具有每个组件的一个实例。这样的设计需要您的组件是无状态的(因此线程安全的),任何有状态(如 BooksContext )的不应该通过构造函数注入。在这个例子中我使用了 Func键&LT; T&GT; 作为提供者的 BooksContext 是存储每个请求

Do note that in my example composition root, all application components (except for the controllers) are defined as singleton. Singleton means that the application will only have one instance of each component. This design needs your components to be stateless (and thus thread-safe), anything that has state (such as the BooksContext) should not be injected through the constructor. In the example I used a Func<T> as the provider of the BooksContext which is stored per request.

让您的对象图,单身有很多有趣的优势。例如,它美元,使常见的配置错误,如圈养依赖p $ pvents你这迫使你成为一个更坚实的设计。除此之外,一些DI库很慢,使一切切换到DI库后来当一个单身可能prevent性能问题。在另一方面,这种设计的缺点是,每个人都对球队应该明白,所有组件都必须是无状态的。在组件存储状态会造成不必要的悲伤和恶化。我的经验是有状态的组件更容易比大多数DI配置错误检测。我也注意到,有单组分的东西,感觉自然大多数开发人员,特别是那些谁不与DI经验。

Making your object graphs singletons has many interesting advantages. For instance, it prevents you from making common configuration errors such as Captive Dependencies and it forces you into a more SOLID design. And besides, some DI libraries are very slow, and making everything a singleton might prevent performance problems when switching to a DI library later on. On the other hand, the downside of this design is that everybody on the team should understand that all components must be stateless. Storing state in components will cause needless grief and aggravation. My experience is that stateful components are much easier to detect than most DI configuration errors. I have also noticed that having singleton components is something that feels natural to most developers, especially those who aren't experienced with DI.

请注意,在例子中,我手动实现每个请求的生活方式为 BooksContext 。尽管所有的DI图书馆都有外的现成支持范围的生活方式,如每个请求的生活方式,我会反对使用这些范围内的生活方式(也许除了当库担保抛出一个异常,而不是默默不及格)。当你解决范围的情况下主动范围的上下文之外(比如在后台线程解析每个请求的实例)大多数图书馆不向您发出警告。一些容器将返回一个单独的实例,每次别人问你时你返回一个新的实例。这实在是麻烦,因为它隐藏的错误,并可能导致你很多时间试图调试应用程序(我说自己的经历)。

Note that in the example I manually implemented a per-request lifestyle for the BooksContext. Although all DI libraries have out-of-the-box support for scoped lifestyles such as per-request lifestyles, I would argue against using those scoped lifestyles (except perhaps when the library guarantees to throw an exception instead of failing silently). Most libraries do not warn you when you resolve a scoped instance outside the context of an active scope (for instance resolving a per-request instance on a background thread). Some containers will return you a singleton instance, others return you a new instance each time you ask. This is really troublesome because it hides bugs and can cause you many hours trying to debug your application (I speak from experience here).

这篇关于使用依赖注入没有任何DI框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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