ASP.NET CoreにおけるGetService()とGetRequiredService()の違い

7831 ワード

前回の記事『.NET Core 3.0のWPFでIOCグラフィックチュートリアルを使用する』では、WPFに.NET Core内蔵のIOCを適用してプログラミングを試み、MainWindowを解析する際にGetRequiredService()の方法を使いました.その時、このGetRequiredService()の方法とGetService()の方法にはいったいどんな違いがあるのかと考えていました.そこで、グーグルは、彼らの違いを紹介する文章を見つけました.そこで、翻訳を試みました.皆さんに役に立つことを願っています.文章の最後に原文のリンクが表示されます.以下は翻訳内容です.
作者:依楽祝原文住所:https://www.cnblogs.com/yilezhu/p/11107648.html
ここでは、Microsoft.Extensions.DependencyInjectionで提供するデフォルト/内蔵ASPについて説明する.NET Core DI容器の方法GetService()およびGetRequiredService().それらの違いと、どの方法を使用するべきかについて説明します.
サービスが存在しない場合、GetService()nullGetRequiredService()に戻り、異常を放出する.サードパーティ製コンテナを使用している場合は、可能な限りGetRequiredServiceを使用します.例外が発生した場合、サードパーティ製コンテナは、異常情報に基づいて適切な診断情報を提供し、サービスが登録されていない理由を特定できます.

コンテナのコア-IServiceProviderインタフェース


ASP.NET Core依存注入抽象のコアはIServiceProviderインタフェースである.このインタフェースは、実際にはSystemネーミングスペースのベースクラスライブラリの一部です.インタフェース自体は簡単です.
public interface IServiceProvider
{
    object GetService(Type serviceType);
}

DIコンテナ(IServiceCollectionを使用)を使用してすべてのクラスを登録すると、ほとんどのDIコンテナがGetService()を使用してオブジェクトのインスタンスを検索できるようにする必要があります.
もちろん、通常はIServiceProviderをコードに直接使用するべきではありません.逆に、標準的なコンストラクション関数注入を使用して、フレームワークをベアリングさせ、バックグラウンドでIServiceProviderを使用する必要があります.IServiceProviderを直接使用することは、サービスロケータモードの一例である.これは通常、クラスの依存関係を隠すため、逆モードとみなされます.
しかし、時には選択の余地がないことがあります.たとえば、サービスを属性に注入しようとする場合や、DIコンテナの構成時に転送タイプを使用する場合は、IServiceProviderを直接使用する必要があります.

GetService()とGetRequiredService()の比較


私たちがもう使わないことを考えると.NET 1.0では、IServiceProviderからサービスを検索したい場合は、GetService()インタフェースメソッドではなく、汎用的な汎用的なGetService(Type)拡張メソッドを使用することができます.しかし、GetRequiredService()のような拡張方法にも気づいたかもしれません.問題は、それらの間にどのような違いがあるのか、どの方法を使うべきかということです.
任意のコードを研究する前に,これらの方法の予想される挙動について議論しよう.まず、GetService()メソッドのドキュメントから始めます.GetService()は、serviceTypeのタイプのサービスオブジェクトを返す.タイプのないサービスオブジェクトserviceTypeが返された場合、nullが返される.GetRequiredService()の文書の内容と比較します.GetRequiredService()は、serviceTypeのタイプのサービスオブジェクトを返す.serviceType型のサービスがない場合、InvalidOperationException異常が放出される.
したがって、要求されたインスタンスserviceTypeが利用可能である場合、両方の方法の動作は同じである.異なる点は、serviceTypeが登録されていない場合の動作です.
  • GetService-サービスが登録されていない場合、null
  • に戻る.
  • GetRequiredService-サービスが登録されていない場合、Exception例外が投げ出されます.

  • コードを見てみましょうServiceProviderServiceExtensionsクラスでMicrosoftExtensions.DependencyInjection.Abstraactionsライブラリでは、以下に示すように、汎用版GetService()GetRequiredService()の両方の方法が実装されています.
    私はすでに本文のコードからいくつかの前提条件検査を削除しました.完全なコードを見たい場合は、GitHubで確認してください.
    public static class ServiceProviderServiceExtensions
    {
        public static T GetService(this IServiceProvider provider)
        {
            return (T)provider.GetService(typeof(T));
        }
    
        public static T GetRequiredService(this IServiceProvider provider)
        {
            return (T)provider.GetRequiredService(typeof(T));
        }
    }

    この2つの方法は実際には同じである−汎用拡張方法は非汎用バージョンのGetService()およびGetRequiredService()に委任される.これらはただの便利さなので、typeof()とタイプ変換を自分のコードで使用する必要はありません.
    非汎用バージョンのGetService()IServiceProviderインタフェースの一部であるが、非汎用バージョンのGetRequiredService()実装は同じクラスの拡張方法である.
    public static class ServiceProviderServiceExtensions
    {
        public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
        {
            var requiredServiceSupportingProvider = provider as ISupportRequiredService;
            if (requiredServiceSupportingProvider != null)
            {
                return requiredServiceSupportingProvider.GetRequiredService(serviceType);
            }
    
            var service = provider.GetService(serviceType);
            if (service == null)
            {
                throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType));
            }
    
            return service;
        }
    }

    この方法の第1のステップは、提供されたIServiceProviderISupportRequiredServiceも実現したかどうかを確認することである.このインタフェースは、最下位の非汎用GetRequiredService実装を提供するので、サービスプロバイダが実装する場合、GetRequiredService()は直接呼び出すことができる.
    ASP.NET Coreに内蔵されているDI容器はISupportRequiredServiceを実現していない-GetRequiredService()を実現したのはサードパーティ容器のみである.IServiceProviderISupportRequiredServiceを実装していない場合は、予想されるように、GetService()呼び出し、nullを返すと例外が放出されます.

    どの方法を使うべきですか?


    私が前に言ったように、理想的には、両方ともできます!
    自分のコードでISeviceProviderを使用するのは、通常、サービスロケータの逆モードを使用しているフラグなので、一般的にはISeviceProviderを使用しないでください.ただし、設計上の制約が必要な場合(たとえば、属性でDIを使用できない場合)、またはDIコンテナ構成自体の一部として使用する場合、どちらを使用しますか?
    GitHubでGetRequiredService()を追加するように要求された元の問題と、Jeremy D.Millerが以前に提出した問題に基づいて、ほとんどの場合のルールは:GetRequiredService()の使用
  • 繰り返しを減らします.サービスが利用できない場合、GetRequiredService()を使用すると、すぐに例外が放出されます.GetService()を使用する場合は、呼び出しコードでnullであるかどうかを確認し、通常は例外を放出する必要があります.その空のチェックコードはどこでも繰り返す必要があります.
  • はすぐに失敗した.GetService()を使用するときにnullであるかどうかを確認するのを忘れた場合は、後でプログラムがNullReferenceExceptionで終了する可能性があります.異常の原因を特定するのは、明示的に教えてくれたInvalidOperationExceptionよりも困難で、より多くの仕事をする必要があります.
  • は、サードパーティ製コンテナの高度な診断を可能にする.StructureMapおよび他のサードパーティ製コンテナの大きな利点は、サービスが見つからない理由を説明する詳細な例外メッセージを提供することです.GetRequiredService()を使用している場合、サードパーティ製コンテナ自体に異常が発生するため、コンテナ固有の他の情報を提供できます.null(GetService()付き)だけを返すと、これ以上詳細な情報は表示されません.これがGetRequiredService()の導入の主な原因である.

  • もちろん、GetRequiredService()に反対するいくつかの観点を見ましたが、どちらも審査されないと思います.
  • 「サードパーティ製容器を使用していません」.内蔵コンテナを使用している場合(ISupportRequiredServiceは実装されていません)、他の診断を使用してGetRequiredService()の利益を得ることはできません.しかし、前の2つの利点は依然として存在し、GetRequiredServiceを使用する価値があると思います.また、後でサードパーティ製コンテナを追加する場合は、ベストプラクティスを使用しています.
  • 「オプションのサービスがあり、DIコンテナにしか登録されていない場合があります.」これはGetService()を使用する唯一の有効な理由かもしれません.コードが特定のサービスに登録されている場合にのみ実行される場合は、GetService()を使用する必要があります.しかし、GetService()がNULLを返すと、私もそれがロールバックサービスを使用するときに使用されているのを見ました.私から見れば、これはアプリケーションコードの良いモードではありません.ロールバックの編成は、サービスを使用する場所ではなく、DIコンテナ構成の一部であるべきである.

  • だから、今はGetService()GetRequiredService()の対比があります.さらに掘り起こす前に、もう一つではなく一つを選んだとき、私は少し武断しましたが、今はいつも当たり前のようにGetRequiredService()を使っていることを確認します.

    サマリ

    GetService()IServiceProvider上の唯一の方法であり、ISeviceProviderはASPである.NETコアDI抽象の中央インタフェース.サードパーティ製容器はまた、ISupportRequiredService方法を提供するオプションのインターフェースGetRequiredService()を実現することができる.要求のタイプserviceTypeが利用可能である場合、これらの方法の動作は同じである.サービスが利用できない(すなわち登録されていない)場合、GetService()nullを返し、GetRequiredService()InvalidOperationExceptionを投げ出す.GetRequiredService()GetService()に対する主な利点は、サービスが利用できない場合、サードパーティ製コンテナに追加の診断情報を提供することを可能にすることである.従って、サードパーティ製容器を使用する場合にはGetRequiredService()を使用することが望ましい.個人的には、内蔵のDI容器だけを使っても、どこでも使います.
    元の英語リンク:https://andrewlock.net/the-difference-between-getservice-and-getrquiredservice-in-asp-net-core/