Using Dependency Injection without any DI Library
Asked Answered
S

4

11

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;
}

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

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

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

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

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

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

Sudbury answered 16/8, 2015 at 7:20 Comment(3)
I would recommend SimpleInjector as it validates the configuration before starting up. Very few containers do that. So any problem would typically be found and solved in the beginning.Fled
If at some point you are planing to upgrade you project to ASP.NET vNext, It is worth mentioning that is going to include some basic implementation of DI container that can fit your needs(blogs.msdn.com/b/webdev/archive/2014/06/17/…)Penult
I think that it would be much better to start with Pure DI instead of using ASP.NET vNext's built-in DI library. The built-in DI library is useless when you are writing SOLID applications.Antiar
A
19

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.

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.

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;
    }
}

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
    }
}

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.

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.

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.

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.

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.

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. For a detailed discussion on the two composition models to choose from and their downsides and advantages, take a look at this serie of blog posts.

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).

Antiar answered 16/8, 2015 at 9:35 Comment(0)
D
12

The simplest and sanest solution is to use Pure DI. With ASP.NET MVC, this is most easily done by deriving from DefaultControllerFactory and overriding GetControllerInstance:

protected override IController GetControllerInstance(
    RequestContext requestContext, Type controllerType)
{
    if (controllerType == typeof(Test))
        return new Test(new Book());

    return base.GetControllerInstance(requestContext, controllerType);
}

Then register your new Controller Factory in your Global.asax like this:

ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());

Unfortunately, much documentation will tell you to use IDependencyResolver, or Bastard Injection to deal with Dependency Injection, but these will not make your code more maintainable.

There are lots of more details, including examples of how to properly use Dependency Injection with ASP.NET MVC, in my book.

Dysphonia answered 16/8, 2015 at 8:44 Comment(1)
Thanks Mark. Your book is in my Amazon wishlist:) .Sudbury
F
2

If you're only interested in Dependency Injection to achieve some level of abstraction, you're definitely not required to use any IoC framework.

If you don't care about scope, lifetime and nested dependencies, you may end up with something as primitive as this:

internal class MyBasicResolver : IDependencyResolver
{
    private readonly Dictionary<Type, Type> _services = new Dictionary<Type, Type>()
    {
        { typeof(IBook), typeof(Book) }
        // more services registrations
    };


    public object GetService(Type serviceType)
    {
        return _services.ContainsKey(serviceType) ? Activator.CreateInstance(_services[serviceType]) : null;
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        yield return GetService(serviceType);
    }
}

Then register it as the current Dependency Resolver for MVC:

DependencyResolver.SetResolver(new MyBasicResolver());

See MSDN

Frodine answered 16/8, 2015 at 8:17 Comment(0)
L
0

Ninject and unity provide object container, which contains object wich you have register at startup of the application,

But why you need to use di, Di states that two objects should not depend upon its concreation it should depend upon its abstraction, so if suppose in futere you need to replace Book class to eBook, here both the class has same function but it has diffrunt concreation at that time you need to just your di configuration you dont need to recode the controller for eBook.

I am using unity di in my most projects I didt face any issue which I cant resolve its easy and make practice to use that, dont be afraid for that.

Laliberte answered 16/8, 2015 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.