paint-brush
3 einfache Tipps für die Abhängigkeitsinjektion mit Scrutor in C#von@devleader
430 Lesungen
430 Lesungen

3 einfache Tipps für die Abhängigkeitsinjektion mit Scrutor in C#

von Dev Leader7m2024/03/04
Read on Terminal Reader

Zu lang; Lesen

Entdecken Sie erweiterte Abhängigkeitsinjektionstechniken mit Scrutor in C#. Erfahren Sie, wie Sie die Registrierung und Auflösung optimieren, die Protokollierung mit dem Decorator-Muster implementieren und Funktionsumschaltungen für dynamische Serviceimplementierungen nutzen. Werten Sie Ihre ASP.NET Core-Anwendungen mit Expertenstrategien für eine effiziente Codeorganisation und -verwaltung auf!
featured image - 3 einfache Tipps für die Abhängigkeitsinjektion mit Scrutor in C#
Dev Leader HackerNoon profile picture
0-item

Die Abhängigkeitsinjektion in C# ist ein Lebensretter beim Organisieren von Abhängigkeiten – insbesondere in komplexeren ASP.NET Core-Anwendungen. Und wenn Sie bereits mit IServiceCollection vertraut sind oder sich einfach so nah wie möglich an die bereits bereitgestellten DI-Angebote halten möchten, ist Scrutor in C# eine großartige Erweiterung.


In diesem Artikel gebe ich Ihnen einen allgemeinen Überblick über Dependency Injection und Scrutor in C#. Aber von dort aus kommen wir direkt zu drei Tipps, die Sie mit Scrutor verwenden können und die sich bei Ihrer Bewerbung als sehr hilfreich erweisen könnten!


Was ist Scrutor in C#?

Scrutor ist ein leistungsstarkes NuGet-Paket in C#, das die Abhängigkeitsinjektion verbessert. Es vereinfacht die Registrierung und Auflösung von Abhängigkeiten und erleichtert Ihnen die Verwaltung und Organisation Ihres Codes.


Abhängigkeitsinjektion ist ein beliebter Ansatz zur Konfiguration von Anwendungen, der eine lose Kopplung fördert und die Testbarkeit und Wartbarkeit verbessert. Dabei werden Abhängigkeiten in eine Klasse eingefügt, anstatt sie direkt innerhalb der Klasse zu erstellen. Dies bedeutet, dass die Verantwortung für die Erstellung der Abhängigkeit nicht bei der Klasse liegt, die sie benötigt, sondern bei jemandem in der Aufrufliste. Letztendlich wird dadurch fast die gesamte Abhängigkeitserstellung an den Einstiegspunkt einer Anwendung verlagert, was diese unhandlich macht. Dependency-Injection-Frameworks helfen jedoch dabei , die gesamte Logik zu bereinigen und zu organisieren .


Scrutor führt dieses Konzept noch einen Schritt weiter, indem es eine einfache und intuitive Möglichkeit bietet, Abhängigkeiten zu registrieren und aufzulösen. Mit Scrutor müssen Sie nicht mehr jede Abhängigkeit einzeln manuell registrieren. Stattdessen können Sie Konventionen und Attribute verwenden, um den Prozess zu automatisieren.

1 – Verwendung von Scrutor zur Registrierung und Lösung

Um zu veranschaulichen, wie Scrutor in C# zur Registrierung und Auflösung verwendet wird, betrachten wir ein einfaches Szenario. Stellen Sie sich vor, wir haben eine Anwendung, die die Verwendung verschiedener Datenrepositorys erfordert, wie z. B. UserRepository und ProductRepostiory.


Zuerst müssen wir das Scrutor NuGet-Paket in unserem Projekt installieren. Öffnen Sie die Package Manager-Konsole und führen Sie den folgenden Befehl aus:

 Install-Package Scrutor


Als nächstes müssen wir unsere Repositorys und ihre entsprechenden Schnittstellen definieren. Dieses Beispiel ist im Wesentlichen leer, aber wir werden uns gleich auf diese beziehen:

 public interface IUserRepository { // Interface methods } public class UserRepository : IUserRepository { // Implementation } public interface IProductRepository { // Interface methods } public class ProductRepository : IProductRepository { // Implementation }


Lassen Sie uns nun unsere Abhängigkeiten mit Scrutor verknüpfen. Fügen Sie in Ihrem Startcode (z. B. in der Methode „ConfigureServices“ in ASP.NET Core) den folgenden Code hinzu:

 services.Scan(scan => scan .FromAssemblyOf<Startup>() .AddClasses(classes => classes.AssignableToAny( typeof(IUserRepository), typeof(IProductRepository))) .AsImplementedInterfaces() .WithScopedLifetime());


Dieser Code verwendet die Scan-Methode von Scrutor, um die Assembly zu scannen, die die Startup-Klasse enthält. Anschließend werden die Klassen herausgefiltert, die den Schnittstellen IUserRepository oder IProductRepository zuweisbar sind. Schließlich ordnet es die Implementierungen dieser Schnittstellen zu und registriert sie bei ihren jeweiligen Schnittstellen.


Jetzt können wir diese Abhängigkeiten in unsere Klassen einfügen. Nehmen wir zum Beispiel an, wir haben eine UserService-Klasse, die IUserRepository erfordert:

 public class UserService { private readonly IUserRepository _userRepository; public UserService(IUserRepository userRepository) { _userRepository = userRepository; } // Rest of the class implementation }


Durch die Deklaration von IUserRepository als Abhängigkeit im Konstruktor löst Scrutor zusammen mit IServiceCollection die UserRepository-Instanz automatisch auf und fügt sie für uns ein.


2 – Das Decorator-Muster – Beispiel für die Protokollierung für Dienste

Stellen Sie sich vor, Sie haben eine Serviceschnittstelle IService und eine Implementierung MyService . Sie möchten den Ein- und Ausgang jedes Methodenaufrufs in MyService protokollieren, ohne dessen Geschäftslogik durch Protokollierungsprobleme zu beeinträchtigen.


Definieren Sie zunächst die IService Schnittstelle und ihre Implementierung:

 public interface IService { void DoWork(); } public class MyService : IService { public void DoWork() { // Business logic here } }


Als Nächstes erstellen Sie eine Dekoratorklasse LoggingDecorator , die IService implementiert. Diese Klasse umschließt den eigentlichen Dienst und fügt eine Protokollierung um die delegierten Methodenaufrufe hinzu:

 public class LoggingDecorator : IService { private readonly IService _decorated; private readonly ILogger<LoggingDecorator> _logger; public LoggingDecorator(IService decorated, ILogger<LoggingDecorator> logger) { _decorated = decorated; _logger = logger; } public void DoWork() { _logger.LogInformation("Starting work."); _decorated.DoWork(); _logger.LogInformation("Finished work."); } }


Verwenden Sie jetzt Scrutor, um Ihren Dienst und seinen Dekorator in Startup.cs oder wo immer Sie Ihre Dienste konfigurieren, zu registrieren:

 public void ConfigureServices(IServiceCollection services) { // Register the base service services.AddScoped<IService, MyService>(); // Use Scrutor to apply the decorator services.Decorate<IService, LoggingDecorator>(); // Make sure to register the ILogger or ILogger<T> dependencies if not already done }


Dieses Setup verwendet Scrutor, um die IService Registrierung mit dem LoggingDecorator zu umschließen. Beim Auflösen von IService stellt der DI-Container eine Instanz von LoggingDecorator bereit, die wiederum eine Instanz von MyService umschließt. Dieser Ansatz erreicht die Trennung von Belangen, indem er die Protokollierungslogik außerhalb Ihrer Geschäftslogik hält.


3 – Funktionsumschaltung für Service-Implementierungen

Wenn wir komplexe Systeme erstellen, gibt es oft Fälle, in denen wir so etwas wie Feature-Flags einführen möchten. Dadurch können wir je nach Konfiguration unterschiedliche Codepfade verwenden und müssen nicht eine gesamte Anwendung neu kompilieren und bereitstellen. In manchen Situationen geht es nicht nur darum, einen anderen Codepfad auszuwählen, sondern auch darum, eine gesamte Implementierung von etwas auszutauschen!

Probieren wir gemeinsam ein Beispiel aus! Angenommen, Sie verfügen über eine IFeatureService Schnittstelle mit mehreren Implementierungen: NewFeatureService (eine neue, experimentelle Funktion) und StandardFeatureService (die aktuelle, stabile Funktion). Sie möchten zur Laufzeit basierend auf einem Konfigurationsflag zwischen diesen Implementierungen wechseln.


Definieren Sie zunächst die IFeatureService Schnittstelle und ihre Implementierungen:

 public interface IFeatureService { void ExecuteFeature(); } public class NewFeatureService : IFeatureService { public void ExecuteFeature() { // New feature logic } } public class StandardFeatureService : IFeatureService { public void ExecuteFeature() { // Standard feature logic } }


Als Nächstes benötigen Sie eine Möglichkeit, anhand einer Funktionsumschalteinstellung zu bestimmen, welche Implementierung verwendet werden soll. Dies kann ein Wert in appsettings.json , eine Datenbankeinstellung oder eine andere Konfigurationsquelle sein.


Verwenden Sie nun Scrutor, um die entsprechende Dienstimplementierung basierend auf der Funktionsumschaltung dynamisch zu registrieren:

 public void ConfigureServices(IServiceCollection services) { // Assume GetFeatureToggleValue() retrieves the current feature toggle setting var useNewFeature = GetFeatureToggleValue("UseNewFeature"); // Dynamically register the appropriate implementation based on the feature toggle if (useNewFeature) { services.AddScoped<IFeatureService, NewFeatureService>(); } else { services.AddScoped<IFeatureService, StandardFeatureService>(); } // Optional: You could combine this with the previous example // to use the decorator pattern too! // services.Decorate<IFeatureService, FeatureServiceProxy>(); } private bool GetFeatureToggleValue(string featureName) { // This method would typically check your // configuration source to determine if the feature is enabled // For simplicity, this is just a placeholder return false; // or true based on actual configuration }


Ein Ansatz wie dieser kann uns helfen bei:

  • Flexibilität : Ermöglicht der Anwendung, zwischen Funktionsimplementierungen zu wechseln, ohne dass eine erneute Bereitstellung erforderlich ist. Sie können Funktionen mit nur einer Konfigurationsänderung aktivieren oder deaktivieren.
  • Testen in der Produktion : Sie können neue Funktionen in einer Produktionsumgebung mit einer begrenzten Anzahl von Benutzern testen, indem Sie die Funktion für diese Benutzer aktivieren.
  • Schrittweise Einführung : Hilft bei der schrittweisen Einführung von Funktionen, um die Auswirkungen zu überwachen und die Stabilität vor einer umfassenderen Veröffentlichung sicherzustellen.
  • Risikominderung : Kehren Sie schnell zur alten Implementierung zurück, wenn Probleme mit der neuen Funktion auftreten, und minimieren Sie so Ausfallzeiten und Auswirkungen auf Benutzer.

Zusammenfassung von Scrutor in C#

In diesem Artikel habe ich Ihnen drei einfache Tipps für die Abhängigkeitsinjektion mit Scrutor in C# gegeben. Nach einem kurzen Überblick darüber, was Abhängigkeitsinjektion ist und wie Scrutor darin passt, sind wir direkt zu unseren Beispielen übergegangen. Wir haben gesehen, wie man Assemblys scannt, wie man Abhängigkeiten dekoriert und sogar, wie man Feature-Flags für ganze Implementierungen in Betracht zieht!


Die Abhängigkeitsinjektion kann Ihre Anwendungen erheblich vereinfachen, wenn sie immer komplexer werden. Scrutor kann eine große Hilfe sein, wenn Sie beim integrierten IServiceCollection-Angebot von Microsoft bleiben möchten. Wenn Sie dies nützlich fanden und nach weiteren Lernmöglichkeiten suchen, sollten Sie meinen kostenlosen wöchentlichen Software-Engineering-Newsletter abonnieren und sich meine kostenlosen Videos auf YouTube ansehen! Treten Sie mir und den anderen Community-Mitgliedern auf Discord bei!