paint-brush
C# で Scrutor を使用した依存関係の注入に関する 3 つの簡単なヒント@devleader
430 測定値
430 測定値

C# で Scrutor を使用した依存関係の注入に関する 3 つの簡単なヒント

Dev Leader7m2024/03/04
Read on Terminal Reader

長すぎる; 読むには

C# の Scrutor を使用した高度な依存関係注入テクニックを探索します。登録と解決を最適化し、デコレーター パターンを使用してロギングを実装し、動的なサービス実装に機能切り替えを利用する方法を学びます。効率的なコードの編成と管理のための専門的な戦略を使用して、ASP.NET Core アプリケーションを強化します。
featured image - C# で Scrutor を使用した依存関係の注入に関する 3 つの簡単なヒント
Dev Leader HackerNoon profile picture
0-item

C#での依存関係の挿入は、依存関係を整理するとき、特により複雑な ASP.NET Core アプリケーションの場合に救世主となります。すでにIServiceCollection に精通している場合、またはすでに提供されている DI 製品にできるだけ近づけたいと考えている場合、 C# の Scrutor は優れた機能強化です。


この記事では、C# の依存関係の挿入と Scrutor の概要を説明します。しかし、そこから、Scrutor で使用でき、アプリケーションで非常に役立つ可能性がある 3 つのヒントに進みます。


C# の Scrutor とは何ですか?

Scrutor は、依存関係の注入を強化する C# の強力な NuGet パッケージです。依存関係の登録と解決が簡素化され、コードの管理と整理が容易になります。


依存関係の注入は、疎結合を促進し、テスト容易性と保守容易性を向上させる、アプリケーションを構成するための一般的なアプローチです。これには、依存関係をクラス内に直接作成するのではなく、クラスに依存関係を注入することが含まれます。これは、依存関係を作成する責任は、それを必要とするクラスが所有するのではなく、コール スタック上の誰かが所有することを意味します。最終的には、ほぼすべての依存関係の作成がアプリケーションのエントリ ポイントに押し込まれ、扱いにくくなります。ただし、依存関係注入フレームワークは、 このロジックすべてをクリーンアップして整理するのに役立ちます。


Scrutor は、依存関係を登録および解決するためのシンプルかつ直感的な方法を提供することで、この概念をさらに一歩進めています。 Scrutor を使用すると、依存関係を 1 つずつ手動で登録する必要がなくなりました。代わりに、規則と属性を使用してプロセスを自動化できます。

1 – 登録と解決にScrutorを使用する

C# で Scrutor を使用して登録と解決を行う方法を説明するために、簡単なシナリオを考えてみましょう。 UserRepository や ProductRepostiory など、さまざまなデータ リポジトリの使用を必要とするアプリケーションがあると想像してください。


まず、Scrutor NuGet パッケージをプロジェクトにインストールする必要があります。パッケージ マネージャー コンソールを開き、次のコマンドを実行します。

 Install-Package Scrutor


次に、リポジトリとそれに対応するインターフェイスを定義する必要があります。この例は本質的には空ですが、これらについては後ほど参照します。

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


次に、Scrutor を使用して依存関係を結び付けてみましょう。スタートアップ コード (ASP.NET Core の ConfigureServices メソッドなど) に、次のコードを追加します。

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


このコードは、Scrutor の Scan メソッドを使用して、Startup クラスを含むアセンブリをスキャンします。次に、IUserRepository インターフェイスまたは IProductRepository インターフェイスに割り当て可能なクラスをフィルターで除外します。最後に、これらのインターフェイスの実装をマップし、それぞれのインターフェイスに登録します。


これで、これらの依存関係をクラスに注入できるようになりました。たとえば、IUserRepository を必要とする UserService クラスがあるとします。

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


コンストラクターで IUserRepository を依存関係として宣言すると、Scrutor と IServiceCollection が自動的に解決し、UserRepository インスタンスを挿入します。


2 – デコレータ パターン – サービスのロギングの例

サービス インターフェイスIServiceと実装MyServiceがあると想像してください。 MyServiceの問題でビジネス ロジックを汚染することなく、MyService の各メソッド呼び出しの開始と終了をログに記録したいと考えています。


まず、 IServiceインターフェイスとその実装を定義します。

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


次に、 IServiceを実装するデコレータ クラスLoggingDecoratorを作成します。このクラスは実際のサービスをラップし、委任されたメソッド呼び出しの周囲にロギングを追加します。

 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."); } }


ここで、Scrutor を使用して、サービスとそのデコレーターをStartup.csまたはサービスを構成する場所に登録します。

 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 }


このセットアップでは、Scrutor を使用してIService登録をLoggingDecoratorでラップします。 IServiceを解決するとき、DI コンテナはLoggingDecoratorのインスタンスを提供し、それがMyServiceのインスタンスをラップします。このアプローチでは、ロギング ロジックをビジネス ロジックの外部に保持することで、懸念事項の分離を実現します。


3 – サービス実装の機能切り替え

複雑なシステムを構築していると、機能フラグのようなものを導入したい場合がよくあります。これらにより、構成に基づいて異なるコード パスを選択できるため、アプリケーション全体を再コンパイルしてデプロイする必要がなくなります。状況によっては、単に別のコード パスを選択するだけではなく、何かの実装全体を交換することも必要になります。

一緒に例を試してみましょう! NewFeatureService (新しい実験的な機能) とStandardFeatureService (現在の安定した機能) という複数の実装を備えたIFeatureServiceインターフェイスがあるとします。構成フラグに基づいて、実行時にこれらの実装を切り替える必要があります。


まず、 IFeatureServiceインターフェイスとその実装を定義します。

 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 } }


次に、機能の切り替え設定に基づいて、どの実装を使用するかを決定する方法が必要です。これは、 appsettings.json 、データベース設定、またはその他の構成ソースの値である可能性があります。


次に、Scrutor を使用して、機能の切り替えに基づいて適切なサービス実装を動的に登録します。

 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 }


このようなアプローチを採用すると、次のことに役立ちます。

  • 柔軟性: アプリケーションは、再デプロイすることなく機能実装を切り替えることができます。構成を変更するだけで、機能を有効または無効にできます。
  • 運用環境でのテスト: 限られたユーザーのセットを使用して、これらのユーザーに対して機能をオンに切り替えることで、運用環境で新機能をテストできます。
  • 段階的なロールアウト: 機能を段階的に展開して影響を監視し、広範囲にリリースする前に安定性を確保するのに役立ちます。
  • リスクの軽減: 新機能で問題が発生した場合は、すぐに古い実装に戻し、ダウンタイムとユーザーへの影響を最小限に抑えます。

C# での Scrutor のまとめ

この記事では、C# で Scrutor を使用した依存関係注入に関する 3 つの簡単なヒントを提供しました。依存関係注入とは何か、Scrutor が依存関係注入にどのように適合するのかについて簡単に説明した後、早速例に移ります。アセンブリのスキャン、依存関係を修飾する方法、さらには実装全体に機能フラグを付ける方法を検討する方法についても学びました。


依存関係の注入は、複雑さが増すアプリケーションを大幅に簡素化できるものであり、 Microsoft が提供する組み込みの IServiceCollectionを使い続けたい場合には、Scrutor が非常に役立ちます。これが役立つと思われ、さらに学習の機会を探している場合は、無料の毎週のソフトウェア エンジニアリング ニュースレターの購読を検討し、 YouTube で私の無料ビデオをチェックしてください。私や他のコミュニティメンバーと一緒に Discord に参加してください!