30

Can someone explain dependency injection with a basic .NET example and provide a few links to .NET resources to extend on the subject?

This is not a duplicate of What is dependency injection? because I am asking about specific .NET examples and resources.

Community
  • 1
  • 1
JohnIdol
  • 48,899
  • 61
  • 158
  • 242
  • 1
    Martin Fowler has the description covered: http://martinfowler.com/articles/injection.html As far as .NET resources go take a look at: - [Castle Windsor](http://www.castleproject.org/container/index.html) - [Spring.NET](http://www.springframework.net/) - [Autofac](http://code.google.com/p/autofac/) - [Ninject](http://ninject.org/) - [Unity](http://www.codeplex.com/unity) - [Structure Map](http://structuremap.sourceforge.net/) – Codebrain Apr 13 '09 at 14:17
  • Take a look at the following articles that may provide some help on this: * [Windsor IoC Container on a Lunch Break](http://jeremyjarrell.com/archive/2007/07/12/44.aspx) * [MSDN article on Inversion of Control and Dependency Injection](http://msdn.microsoft.com/en-us/library/aa973811.aspx) General link about the container: * [Castle Project](http://www.castleproject.org/container/index.html) Couple of SO links that may help further things on the subject: * [Castle Windsor Questions](http://stackoverflow.com/questions/tagged/castle-windsor) * [IoC questions](http://stackoverflow.com/questions/t – JB King Apr 13 '09 at 14:14

9 Answers9

33

Ninject must have one of the coolest sample out there: (pieced from the sample)

interface IWeapon {
  void Hit(string target);
}
class Sword : IWeapon {
  public void Hit(string target) {
    Console.WriteLine("Chopped {0} clean in half", target);
  }
}
class Shuriken : IWeapon {
  public void Hit(string target) {
    Console.WriteLine("Shuriken tossed on {0}", target);
  }
}
class Samurai {
  private IWeapon _weapon;

  [Inject]
  public Samurai(IWeapon weapon) {
    _weapon = weapon;
  }

  public void Attack(string target) {
    _weapon.Hit(target);
  }
}

class WeaponsModule: NinjectModule {
  private readonly bool _useMeleeWeapons;

  public WeaponsModule(bool useMeleeWeapons) {
    _useMeleeWeapons = useMeleeWeapons;
  }

  public void Load() {
    if (useMeleeWeapons)
      Bind<IWeapon>().To<Sword>();
    else
      Bind<IWeapon>().To<Shuriken>();
  }
}

class Program {
  public static void Main() {
    bool useMeleeWeapons = false;
    IKernel kernel = new StandardKernel(new WeaponsModule(useMeleeWeapons));
    Samurai warrior = kernel.Get<Samurai>();
    warrior.Attack("the evildoers");
  }
}

This, to me, reads very fluently, before you start up your dojo you can decide how to arm your Samurais.

KindDragon
  • 6,558
  • 4
  • 47
  • 75
Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • 2
    I am sorry, I don't get it. Why is this any better than me writing code that does "new Samurai(useMeleeWeapons);"? Wouldn't this be the most fluent? – Nabheet May 17 '13 at 15:37
  • 1
    Let's assume you have an army of 10,000 samurais ... and you write that line 10,000 times ... and you then want to change it, but alas, you can't use the editor's find/replace... in the above example, all you need to do is change the `WeaponsModule` :) – Noctis Nov 09 '13 at 06:09
  • 4
    When and how is `Load()` called in `WeaponsModule`? – GFoley83 May 04 '14 at 00:02
33

Here's a common example. You need to log in your application. But, at design time, you're not sure if the client wants to log to a database, files, or the event log.

So, you want to use DI to defer that choice to one that can be configured by the client.

This is some pseudocode (roughly based on Unity):

You create a logging interface:

public interface ILog
{
  void Log(string text);
}

then use this interface in your classes

public class SomeClass
{
  [Dependency]
  public ILog Log {get;set;}
}

inject those dependencies at runtime

public class SomeClassFactory
{
  public SomeClass Create()
  {
    var result = new SomeClass();
    DependencyInjector.Inject(result);
    return result;
  }
}

and the instance is configured in app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name ="unity"
             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
              Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="singleton"
                 type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,Microsoft.Practices.Unity" />
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="MyAssembly.ILog,MyAssembly"
                mapTo="MyImplementations.SqlLog, MyImplementations">
            <lifetime type="singleton"/>
          </type>
        </types>
      </container>
    </containers>
  </unity>
</configuration>

Now if you want to change the type of logger, you just go into the configuration and specify another type.

  • 1
    Why we cannot use some just custom attribute and define 1 = database, 2 = file and etc? What for we need Unity? – NoWar Aug 06 '13 at 16:18
  • 1
    @ClarkKent: Your suggestion doesn't appear very ... implementable. However, the idea is that you can change things at runtime without recompiling. Simply drop another assembly (with a new implementation) in the bin folder, change your .config file to point to a new type in this new assembly, and restart your application. –  Aug 06 '13 at 17:15
  • 2
    Where is `DependencyInjector` defined? – Vitani Jan 05 '18 at 18:36
3

I think it is important that you first learn DI without IoC Containers. So therefor I've written an example that slowly builts up to an IoC Container. It's a real example from my work, but still made basic enough for novices to grab the essence of DI. You can find it here: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

It's in C#.NET and later on it uses Unity.

Update after comment:

Relevant section of article

"Observe the following changes to the original design:

quick graph of situation

We went for the “Constructor Injection” pattern to implement DI and the refactoring steps were:

  1. Abstract the interface of CardPresenceChecker by creating Interface ICardPresenceChecker;
  2. Make explicit that this CardPresenceChecker only works for the library of Company X, by changing its name to XCardPresenceChecker ;
  3. Have XCardPresenceChecker implement Interface ICardPresenceChecker ;
  4. Abstract the property of LogInService to be of type ICardPresenceChecker instead of ‘knowing’ exactly which implementation is held aboard;
  5. And last but not least, demand from users (other developers) of LogInService that they provide any class that at least implements ICardPresenceChecker so that LogInService can do its thing.

LogInService’s constructor looks like:

this.myCardPresenceChecker = cardPresenceChecker;
this.myCardPresenceChecker.CardIn += MyCardPresenceChecker_CardIn;
this.myCardPresenceChecker.CardOut += MyCardPresenceChecker_CardOut;
this.myCardPresenceChecker.Init();

So where do you provide LogInService with an implementation of ICardPresenceChecker? You usually want this ‘mapping’ (in this example we would ‘map’ ICardPresenceChecker to XCardPresenceChecker) at one central place at the startup of an application, known conceptually as the “Composition Root”. For an ol’ regular Console Application that could be the void Main in the Program class. So for this example, this piece of code would be used at the aformentioned place:

LogInService logInService = new LogInService(new XCardPresenceChecker());"

Danny van der Kraan
  • 5,344
  • 6
  • 31
  • 41
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/11421227) – Nahuel Ianni Feb 27 '16 at 13:41
  • @Nahuel lanni: While I appreciate your comment and I'll try to comply, my point is really that it is important to read the article in full and not just try to learn from some random code snippet. But... See revised answer. Hope this helps. – Danny van der Kraan Feb 29 '16 at 10:20
  • IoC? What is that? :-( – PKCS12 Mar 08 '18 at 12:13
  • @Ichirichi Inversion of Control – Danny van der Kraan Mar 12 '18 at 11:37
1

I've got Dependency Injection with a really simple example like this.

See the class below, you'll get the whole idea. As you see unless you supply file it will use the default one settings file, but you can set a settings file and then the class will use it.

Public Class ProcessFile

Private _SettingsFile As String = "settings.bin"

Public Sub New()
End Sub

Public Sub New(settings As String)
_SettingsFile= settings
End Sub

Public Function ReadFile() As String 
'Do stuff based on the settings stored in the _SettingsFile 
End Function

End Class

Obviously this is the most basic case. In real world you can do the same thing with class types, such as you've got Database Layer and you can switch the underlying database dll by doing dependency injection and you code will work with any database as soon as you can provide the valid class (a class which implements the interface you are using).

After got the basic you can do this on larger scope and totally independent from the application by using DI frameworks like unity.

dr. evil
  • 26,944
  • 33
  • 131
  • 201
1

What is meant by 'dependencies' here?

All the parameters that a class has in its constructor, are the dependencies of that class (well, sometimes properties can be marked as dependencies, but let's ignore that for now). In the following class, the dependencies are ILogger and IDbConnectionFactory:

public class MyHandler
{
    private IConnectionFactory _connectionFactory;
    private ILogger _logger;

    public MyHandler(
        IConnectionFactory connectionFactory,
        ILogger logger)
    {
        _connectionFactory = connectionFactory;
        _logger = logger;
    }
    
    public void Handle(MyRequest request)
    {
        // do stuff with the dependencies.
    }
}

Note that the parameter MyRequest of the Handle method is NOT a dependency of the class, because you don't need it for creating an instance of the class.

What is meant by 'injection' here?

Instead of manually injecting the dependencies:

var myHandler = new MyHandler(new MyConnectionFactory(), new MyLogger());

you could register MyConnectionFactory and MyLogger to a "service collection" and have those dependencies injected automatically.

Registering classes to a service collection

In .NET a service collection implements the IServiceCollection interface. Let's say that you want to have a logger that is the same instance from applicatoin start until shutdown. Then you add it as a "singleton" at startup:

serviceCollection.AddSingleton<ILogger>(new MyLogger());

Now you might think: "But what is that serviceCollection? Is it a List? A Dictionary?". My answer for now: the service collection is a class that might use a List or a Dictionary or something else internally, but you shouldn't worry about that.

Where to find this service collection? It depends on the type of app you're building. On the page about App startup in ASP.NET Core your can see this line of code:

builder.Services.AddTransient<IStartupFilter, RequestSetOptionsStartupFilter>();

The builder has a property Services of the type IServiceCollection and a IStartupFilter has been added to the service collection. So, in an ASP.NET Core app, you find the service collection at builder.Services. Other app types may differ in naming, but you'll probably find it easily in documentation or a sample project.

How to use those services?

At some point during app start, from your the service collection a new class is created that implements the IServiceProvider interface, which has a method GetService. In theory one class could implement both interfaces:

public class MyServices : IServiceCollection, IServiceProvider
{
    // implement all interface members.
}

but in practice this is (often) not the case.

So, how do we find a property of type IServiceProvider? When building an ASP.NET Core app, the page has a HttpContext.RequestServices property that is actually a IServiceProvider. However, you probably don't need to use that, because if you add a dependency to the constructor of a page, it is automatically injected:

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(IMyDependency myDependency)
    {
        _myDependency = myDependency;            
    }

    public void OnGet()
    {
        _myDependency.Use("Hello!");
    }
}

Another way is to use the [FromServices] attribute in a Get or Post method of the page:

public class IndexModel : PageModel
{
    public void OnGet([FromServices] IMyDependency myDependency)
    {
        myDependency.Use("Hello again!");
    }
}

What to register and what not?

  • Very basic and much-used classes, such as a logger, a database connection factory, an email sender, etc. are nice to have in the service collection. Services may depend on other services, and the service provider handles all the injections for you. Also, whenever the constructor arguments of such a class changes, it doesn't matter, because the interface stays the same.
  • High level classes, that are only used on one or two pages, should probably not be added to your service collection. For example, think of a ProductOverviewQueryHandler. However, what if that query handler has dependencies? How do I inject them? Read on...

Injecting dependencies in high level classes

This can be done in multiple ways. One way is to use the ActivatorUtilities class like this anywhere in your page:

ActivatorUtilities.CreateInstance<ProductOverviewQueryHandler>(HttpContext.RequestServices)

...but many people will find that an ugly read.

The way that I find very clean, is to use the NuGet package IGet. Your page class would look like this:

public class IndexModel : PageModel
{
    public void OnGet([FromServices] IGet i)
    {
        var queryHandler = i.Get<ProductOverviewQueryHandler>();
        // do something
    }
}

or like this

public class IndexModel : PageModel
{
    private readonly IGet i;

    public IndexModel(IGet iget)
    {
        i = iget;            
    }

    public void OnGet()
    {
        var queryHandler = i.Get<ProductOverviewQueryHandler>();
        // do something
    }

    public Task<IActionResult> OnPost(FilledOutForm request)
    {
        var result = i.Get<OtherHandler>().Handle(request);
        // return something
    }
}

or create a base class for your pages:

public class PageBase : PageModel
{
    private IGet _iget;
    private IGet i => _iget ??= HttpContext.RequestServices.GetRequiredService<IGet>();
}

and use it like this:

public class IndexModel : PageBase
{
    public void OnGet()
    {
        var queryHandler = i.Get<ProductOverviewQueryHandler>();
        // do something
    }
}

Installing IGet

Install IGet via the NuGet Package Manager in Visual Studio and add to the startup of your app:

serviceCollection.AddIGet();

After that, you can use IGet as shown in the examples above.

Further reading

SymboLinker
  • 884
  • 6
  • 15
0

Install below Nuget packages in main mvc4 project name SampleDependency. Unity.mvc4, unity.webapi and MicrosoftAsp.Net Web API 2.2 Web host

In web project

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();
        container.RegisterType<IUserDetailLogic, UserDetailLogic>();
        container.RegisterType<IUserData, UserData>();

        RegisterTypes(container);

        return container;
    }
    public static void RegisterTypes(IUnityContainer container)
    {

    }
}
MichaelS
  • 3,809
  • 2
  • 26
  • 33
ACE
  • 1
0

Add bussiness logic project of type class library and add below code in it. public class UserDetailLogic : IUserDetailLogic { private IUserData _userData = null;

    public UserDetailLogic(IUserData userData)
    {
        _userData = userData;
    }
    public string getUserDetails()
    {
        return _userData.getUserDetails();
    }
}

public interface IUserDetailLogic
{
    string getUserDetails();
}

In you main project add below code in home controller.

public class HomeController : Controller { private readonly IUserDetailLogic _userDetailLogic;

    public HomeController(IUserDetailLogic userDetailLogic)
    {
        _userDetailLogic = userDetailLogic;
    }

    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
        string str = _userDetailLogic.getUserDetails();
        return View();
    }

    public ActionResult About()
    {
        ViewBag.Message = "Your app description page.";

        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";

        return View();
    }
}
Ace
  • 1
  • Good post but it gets a bit unclear (for me at least) when I noticed userData uses interface IUserData (Rather than IUserDetailLogic maybe?). Also HomeController expects IUserDetailLogic userDetailLogic which, in my experience/knowledge, do not know where that will come from. – PKCS12 Mar 08 '18 at 12:13
0

You essentially pass in all necessary objects in the constructor. Alternatively, you can resolve them at runtime using an interface resolver (although this is less typesafe). You can find excellent examples at the Ninject website for the first approach, and good examples at the Unity website for the second approach. This avoid the need for singletons and allows you to easily drop in a replacement object that conforms to the desired interface

Steve
  • 11,763
  • 15
  • 70
  • 103
-1

Create DB layer project(class library) and add below code in it.

public class UserData : IUserData
{
    public string getUserDetails()
    {
        return "Asif";
    }
}

public interface IUserData
{
    string getUserDetails();
}
Ace
  • 1