Inversion of Control in MVC 6

ASP.NET Core bevat een eigen Inversion of Control container. Microsoft noemt het een Service Container en een Dependency noemen ze een Service. In deze blogpost laat ik zien hoe deze Service Container werkt. Hiervoor gebruik ik een MVC 6 webapplicatie. Ik ga ervan uit dat je weet wat Dependency Injection is en hoe het werkt. Als je dat niet weet raad ik je aan om dit te lezen.

In deze blogpost zijn een aantal codevoorbeelden verwerkt. De volledige applicatie is hier te vinden.

Net zoals in MVC 5 heeft MVC 6 een klasse met de naam ‘Startup’. Hierin kunnen services geregistreerd worden. Dit kan via verschillende ‘lifetimes’. Deze lifetimes heten Transient, Scoped, Singleton en Instance. Het registreren van de services gaat als volgt:

Transient
Er wordt een nieuwe instantie van de service gemaakt bij iedere aanroep. In de HomeController zal de TransientDependencyExample van de HomeController dus een ander ID hebben dan de TransientDependencyExample in de DemoService.

Scoped
Per request wordt er één instantie van de service gemaakt. Als er een request binnenkomt in de HomeController zal de ScopedDependencyExample van de HomeController hetzelfde ID hebben als de ScopedDependencyExample in de DemoService. Bij een nieuwe request zullen deze services weer een nieuw ID krijgen.

Singleton
Singleton services worden bij de eerste aanroep geïnstantieerd. Elke volgende request gebruikt deze instantie. Als er een request binnenkomt in de HomeController zal de SingletonDependencyExample van de HomeController hetzelfde ID hebben als de SingletonDependencyExample in de demoservice. Bij een nieuwe request zullen beide ID’s exact hetzelfde blijven.

Instance
Werkt hetzelfde als de singleton lifetime. Het enige verschil is dat er hierbij direct een instantie van de service geïnjecteerd wordt. De service wordt dus geïnstantieerd bij het starten van de applicatie.

Alle geregistreerde klassen uit het bovenstaande voorbeeld, behalve de DemoService, hebben allemaal een Guid property met de naam ID. Het ID wordt gegenereerd in de constructor.

In het volgende codevoorbeeld zie je dat alle services door middel van constructor injectie worden geïnjecteerd in de HomeController en de DemoService. Ook DemoService wordt geïnjecteerd in de HomeController.

Het resultaat van deze code is als volgt:
Request 1

Request 2

Ik heb tot nu toe alleen nog services geïnjecteerd via de constructor. Het is ook mogelijk om services te injecteren met methode parameters en dat werkt met het FromServices attribuut.

Services zijn ook te injecteren in een Razor-view en dat gaat als volgt:

Zie Github voor een volledig voorbeeld. Het gaat om het volgende bestand: Views\Home\About.cshtml.

De servicecontainer wordt ook gebruikt voor de injectie van frameworkservices. Hiervoor wordt de volgende conventie gebruikt: AddService. Hierbij is Service de naam van de service. Voorbeelden van frameworkservices zijn AddEntityFramework, AddIdentity, AddCors en AddCaching.

Bij een MVC-applicatie moet altijd de MVC-service geregistreerd worden door services.AddMvc() aan te roepen. Als je die methode niet aanroept zal je zien dat er een InvalidOperationException wordt gegooid bij het configureren van de routes.

Het is ook mogelijk om een andere container te gebruiken en dat is erg eenvoudig. Hier laat ik zien hoe je de service container vervangt door Autofac. Eerst moeten er twee packages geïnstalleerd worden via NuGet:

Install-Package Autofac -pre

Install-Package Autofac.Extensions.DependencyInjection -pre

In het vorige voorbeeld waarin services geregistreerd werden gaf de ConfigureServices methode void terug. Om een andere container te ondersteunen moet deze methode een IServiceProvider teruggeven. Hieronder is hier een voorbeeld van te zien. Het werkt hetzelfde als het vorige voorbeeld, maar nu wordt er gebruik gemaakt van Autofac.

Tot slot wil ik nog melden dat deze service container maar een minimale set aan features bevat. Het is niet te gebruiken in non-webprojecten. Het is ook niet de bedoeling dat het andere containers zoals Autofac of Unity vervangt.

Tweet about this on TwitterShare on LinkedIn

Reacties

Het e-mailadres wordt niet gepubliceerd.

*