Terug naar lijst

Dependency Injection is een simpele manier om je applicatie naar een hoger technisch niveau te tillen. Door het hoogste niveau van je applicatie afhankelijk te maken van abstracties, in plaats van concrete implementaties, kun je de classes binnen je applicatie vanaf een centraal, laag niveau, beheren. Het design waarbij je een hoger niveau onafhankelijk maakt van een lager niveau en beide afhankelijk maakt van abstracties staat ook wel bekend als Dependency Inversion.

In deze blog leg ik uit hoe je gebruik kan maken van Autofac om Dependency Injection binnen een .NET Framework Console Application te implementeren:
Begin met het opzetten van een .NET Framework Console Application. Maak vervolgens direct een App class aan met daarin een Run method. Binnen deze applicatie maken we gebruik van Dependency Injection via constructor. We kunnen het niet direct vanuit Program.Main laten werken, omdat dat een static class is, zonder constructor dus. Initialiseer een instantie van App in je Main method en roep daar de Run method van aan. Binnen de Run method zal je je algemene code gaan schrijven.

class Program
{
    static void Main(string[] args)
    {
        App app = new App();

        app.Run();

        Console.ReadLine();
    }
}

public class App
{
    public void Run()
    {
    }
}

Maak ook een class die je wilt gaan injecteren in je App. In dit voorbeeld maak ik een class Repository. Hierbinnen definieer ik een aantal properties en een method. Ik laat Repository IRepository implementeren die dezelfde properties en method bevat. Het gebruik van een interface is niet vereist voor Dependency Injection maar is wel aan te raden. Binnen de Write methode van Repository schrijf ik wat weg op het console, dit is voor test redenen. Initialiseer nu een instantie van Repository binnen je App en roep daar de Write method aan. Start vervolgens je applicatie om te bevestigen dat alles werkt. Als het goed is zie je ‘Writing…’ in je console staan.

public class Repository : IRepository
{
    public string Name { get; set; }

    public string Version { get; set; }

    public void Write()
    {
        Console.WriteLine("Writing...");
    }
}

public interface IRepository
{
    string Name { get; set; }

    string Version { get; set; }

    void Write();
}

De code die nu staat werkt prima, alleen je bent nu al op verschillende plaatsen van concrete implementaties af. Om dit te verhelpen kun je Dependency Injection toepassen. Een goede manier om dit te doen is met behulp van Autofac. Installeer Autofac via NuGet. Maak vervolgens een static Autofac class aan met daarin een static Configure method. Hierin wordt de container opgebouwd die de classen gaat injecteren. Maak een instantie van ContainerBuilder uit de Autofac namespace. Roep vervolgens de RegisterType method van de builder aan van type App. Ter demonstratie zal ik voor App geen Interface aangeven. Doe hetzelfde voor Repository, maar koppel deze wel aan een Interface door middel van de As method. Return tot slot de Build method.

public static class AutofacConfig
{
    public static IContainer Configure()
    {
        ContainerBuilder builder = new ContainerBuilder();

        builder.RegisterType<App>();
        builder.RegisterType<Repository>().As<IRepository>();

        return builder.Build();
    }
}

Ga nu terug naar Program.Main, maak daar een instantie van IContainer door de Configure method van de AutofacConfig aan te roepen. Maak direct daaronder een scope aan met behulp van container.BeginLifetimeScope. Deze scope kan nu gebruikt worden om Dependency Injection toe te passen. Om App ook uit de container te halen, in plaats van een concrete implementatie, kun je de Resolve method van de scope met type App aanroepen om een instantie op te halen.

class Program
{
    static void Main(string[] args)
    {
        IContainer container = AutofacConfig.Configure();

        ILifetimeScope scope = container.BeginLifetimeScope();

        App app = scope.Resolve<App>();

        app.Run();

        Console.ReadLine();
    }
}

Nu is het tijd om een instantie van Repository in je App class te injecteren. De bestaande instantie van Repository gaan we nu vanuit de constructor initialiseren, omdat hij daar geïnjecteerd wordt. Maak een constructor binnen de App class en maak een parameter aan van het type IRepository. Maak daarnaast ook een field aan van het type IRepository binnen App, vul die vervolgens op in je constructor met de geïnjecteerde Repository. Je kunt nu in de Run method de Write method aanroepen. Wanneer je de applicatie draait zal je precies hetzelfde resultaat zien als voorheen.

public class App
{
    private IRepository _repository;

    public App(IRepository repository)
    {
        _repository = repository;
    }

    public void Run()
    {
        _repository.Write();
    }
}

Over het algemeen in Dependency Injection een niet heel complex concept. Het gaat de scope van deze applicatie wel een beetje voorbij, maar wanneer je een grotere applicatie aan het ontwikkelen bent zul je snel de voordelen er van inzien. Al helemaal wanneer je bijv. Unit Testing gaat toepassen, waarbij het dan simpel wordt om door heel je applicatie mock classes te injecteren.

De initiële opzet zal iets langer duren dan concrete classes implementeren, maar wanneer het eenmaal staat is het zeker de moeite waard!