Letztes Jahr: Ich sitze bei einem Maschinenbauer, 180 Mitarbeitende, irgendwo zwischen Bielefeld und Hannover. Die Eigenentwicklung — ein ASP.NET-Core-Backend, das Fertigungsaufträge verwaltet — läuft seit vier Jahren. Zwei Entwickler haben das gebaut, einer ist inzwischen weg. Der verbliebene Entwickler erklärt mir, warum das Deployment immer freitags um 17 Uhr stattfindet: "Weil wir dann das Wochenende haben, wenn was schiefläuft." Unit-Tests gibt es keine. Als ich frage warum, kommt: "Wir können die Datenbankzugriffe nicht mocken, alles hängt direkt zusammen."
Ich schaue in den Code. new SqlConnection(...) direkt im Controller. new EmailService() direkt in der Geschäftslogik. Dependency Injection — Fehlanzeige. Das war kein Versagen des Entwicklers. Das war ein Projekt, das ohne Architekturbegleitung gewachsen ist, bis es niemand mehr anfassen wollte.
Genau für solche Situationen ist der Artikel von Nick Chapsas wertvoll.
Was Nick Chapsas erklärt
Chapsas liefert eine saubere, technisch korrekte Einführung in Dependency Injection für .NET-Entwickler. Er beginnt beim Dependency Inversion Principle aus den SOLID-Regeln — high-level Module sollen von Abstraktionen abhängen, nicht von konkreten Implementierungen — und erklärt dann Inversion of Control als das breitere Prinzip dahinter. Der Kern: Nicht das Objekt selbst erzeugt seine Abhängigkeiten, sondern eine externe Instanz stellt sie bereit. Das ASP.NET-Core-DI-Framework macht das mit services.AddScoped<>(), AddTransient<>() und AddSingleton<>() praktisch umsetzbar. Chapsas geht auch auf Lifetime Scopes ein — der häufigste Fallstrick in der Praxis — und erwähnt Scrutor für komplexere Registrierungsszenarien sowie Keyed Services für den Fall, dass mehrere Implementierungen desselben Interfaces im Container leben sollen.
Technisch: alles richtig. Gut geschrieben. Klares Beispiel mit ICarEngine, PetrolEngine, DieselEngine. Wer .NET entwickelt, sollte das kennen.
Wie das im KMU wirklich landet
Hier kommt meine Ergänzung — nicht als Kritik an Chapsas, der schreibt für .NET-Entwickler, die das Handwerk lernen wollen. Sondern als Kontext für den Mittelstand, wo die Ausgangslage oft eine andere ist.
Das Lifetime-Problem ist in KMU-Projekten der häufigste echte Schmerz. Chapsas nennt die drei Scopes korrekt, aber in meinen Mandaten sehe ich immer wieder dasselbe Muster: Ein Service wird als Singleton registriert, bekommt aber intern einen Scoped-Service injiziert — zum Beispiel den DbContext. Resultat: Race Conditions unter Last, Daten aus dem falschen Request-Kontext, Fehler die sich nur in Produktion zeigen und im Entwicklungsrechner nie reproduzieren lassen. ASP.NET Core wirft dafür zur Laufzeit eine Exception — aber nur, wenn Scope Validation aktiv ist, was in Production-Builds standardmäßig deaktiviert war (seit .NET 6 ist das besser, aber die Konfiguration ist nicht trivial). Wer das nicht weiß, sucht Stunden. In einem meiner Mandate waren es zwei Tage.
Scrutor: nützlich, aber nicht für jeden. Chapsas erwähnt Scrutor als Ergänzung für Assembly Scanning und automatische Registrierung. Ich nutze Scrutor selbst gern — aber ich empfehle es KMU-Teams erst, wenn die Basis sitzt. Automatische Registrierung nach Konvention ist elegant, bis jemand nicht versteht warum ein Service plötzlich nicht mehr im Container ist, weil er die Namenskonvention gebrochen hat. In kleinen Teams mit viel Fluktuation ist explizite Registrierung debuggbarer als Magie.
Was im Artikel fehlt: die Testbarkeit als Argument verkaufen. Chapsas erwähnt Testbarkeit mehrfach, aber für KMU-Teams die noch nie Unit-Tests geschrieben haben, ist das abstrakt. Mein konkretes Verkaufsargument in Mandaten lautet so: "Ihr könnt freitagnachmittag deployen, ohne Angst zu haben — weil ihr vorher automatisch testen könnt, ob die Kernlogik noch funktioniert, ohne eine echte Datenbank zu brauchen." Das ist der Satz, der bei Entscheidern ankommt. Dependency Injection ist nicht der Selbstzweck — sie ist die Voraussetzung dafür, dass automatisiertes Testen überhaupt möglich wird.
Die ehrliche Einschätzung für 30-300 Mitarbeitende: Wenn ihr eine Neuentwicklung startet oder ein bestehendes System ernsthaft modernisiert, dann ist DI mit dem eingebauten ASP.NET-Core-Container der richtige Weg. Kein Drittanbieter-Container nötig — Autofac, Ninject, Castle Windsor haben ihre Zeit gehabt, heute reicht Microsoft.Extensions.DependencyInjection für 95% der KMU-Szenarien. Was ihr braucht: klare Konvention, welcher Scope für welchen Servicetyp gilt, und Scope Validation auch in Production aktivieren, damit Fehler früh auffliegen.
Konkrete Empfehlung
Drei Dinge, die ich in jedem KMU-.NET-Projekt als erstes prüfe:
1. Scope Validation aktivieren. In Program.cs beim Builder: builder.Host.UseDefaultServiceProvider(options => { options.ValidateScopes = true; options.ValidateOnBuild = true; });. Das kostet nichts und fängt die häufigsten Lifetime-Fehler beim Start der Anwendung ab — nicht erst in Produktion unter Last.
2. Interfaces nur dort, wo sie Sinn ergeben. Chapsas zeigt das ICarEngine-Beispiel — gut für das Verständnis. Aber ich sehe in KMU-Projekten regelmäßig, dass jede Klasse ein Interface bekommt, das exakt dieselben Methoden hat, nie ausgetauscht wird und nur den Code aufbläht. Interface einführen, wenn: ihr mocken wollt (Testbarkeit), wenn es mehrere Implementierungen gibt (wie PetrolEngine/DieselEngine), oder wenn ihr eine externe Abhängigkeit kapselt (Datenbankzugriff, HTTP-Client, Mailversand). Sonst: direkte Klasse injizieren ist legitim und ehrlicher.
3. Den DbContext niemals als Singleton. Klingt trivial, passiert aber. DbContext ist Scoped — ein Scope pro HTTP-Request. Das ist das Design von Entity Framework Core, und wer davon abweicht, kauft sich Probleme, die erst nach Monaten sichtbar werden.
Für das Team beim Maschinenbauer: Wir haben die kritischen Services Schritt für Schritt hinter Interfaces gezogen, den DbContext sauber als Scoped registriert, und drei Monate später hatten sie ihre ersten automatisierten Tests. Das Freitagabend-Deployment ist Geschichte — sie deployen jetzt dienstags nach der Mittagspause.
Der vollständige Original-Beitrag von Nick Chapsas: Dependency Injection in .NET
Wenn dein .NET-Projekt gerade nicht anfassbar ist — oder du wissen willst, ob DI bei euch das richtige nächste Thema ist — komm in ein kurzes Gespräch.
— Bernhard