web-dev-qa-db-ja.com

Asp.Net Coreでのプロパティインジェクション

Asp.netアプリケーションをasp.netコアに移植しようとしています。このようなUnitOfWork実装でのプロパティインジェクション(ninjectを使用)があります。

[Inject]
public IOrderRepository OrderRepository { get; set; }
[Inject]
public ICustomerRepository CustomerRepository { get; set; }

.NETコアのDIでビルドを使用して同じ機能を実現する方法はありますか?また、規約ベースのバインディングを使用することは可能ですか?

26
Özgür Kaplan

いいえ、組み込みのDI/IoCコンテナーは、他のDIコンテナーをプラグインするためのベースを提供するために、使用法と機能の両方で意図的にシンプルに保たれています。

したがって、自動検出、自動登録、デコレータまたはインジェクタ、または規則ベースの登録に対する組み込みのサポートはありません。私の知る限り、これを組み込みのコンテナに追加する計画もまだありません。

プロパティインジェクションをサポートするサードパーティのコンテナを使用する必要があります。

プロパティインジェクションは依存関係を隠し、クラスの作成時にオブジェクトがインジェクトされる保証がないため、すべてのシナリオの98%でプロパティインジェクションが悪いと見なされることに注意してください。

コンストラクター注入を使用すると、コンストラクターでこれを強制し、nullをチェックして、クラスのインスタンスを作成しないようにすることができます。プロパティインジェクションではこれは不可能であり、ユニットテスト中に、コンストラクタで定義されていない場合にクラスが必要とするサービス/依存関係が明確ではないため、NullReferenceExceptionsを簡単に見逃してしまいます。

私がこれまでに見つけたプロパティインジェクションの唯一の正当な理由は、サードパーティライブラリ、つまりオブジェクトの作成を制御できないインターフェイスから作成されたWCFプロキシによって生成されたプロキシクラスにサービスをインジェクトすることでした。

それを避けるどこでも else。

37
Tseng

.NETコアのDIでビルドを使用して同じ機能を実現する方法はありますか?

いいえ。ただし、 autofacのプロパティインジェクションメカニズム を使用して、独自の[inject]属性を作成できます。

まず、独自のInjectAttributeを作成します。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InjectAttribute : Attribute
{
  public InjectAttribute() : base() { }
}

次に、リフレクションを使用して[inject]でマークされたプロパティをチェックする独自のInjectPropertySelectorを作成します。

public class InjectPropertySelector : DefaultPropertySelector
{
  public InjectPropertySelector(bool preserveSetValues) : base(preserveSetValues)
  { }

  public override bool InjectProperty(PropertyInfo propertyInfo, object instance)
  {
    var attr = propertyInfo.GetCustomAttribute<InjectAttribute>(inherit: true);
    return attr != null && propertyInfo.CanWrite
            && (!PreserveSetValues
            || (propertyInfo.CanRead && propertyInfo.GetValue(instance, null) == null));
  }
}

次に、ConfigureServicesでセレクタを使用します 接続先 your AutofacServiceProvider

public class Startup
{
  public IServiceProvider ConfigureServices(IServiceCollection services)
  {
    var builder = new ContainerBuilder();
    builder.Populate(services);

    // use your property selector to discover the properties marked with [inject]
    builder.RegisterType<MyServiceX>().PropertiesAutowired((new InjectablePropertySelector(true)););

    this.ApplicationContainer = builder.Build();
    return new AutofacServiceProvider(this.ApplicationContainer);
  }
}

最後に、サービスで[inject]を使用できるようになりました。

public class MyServiceX 
{
    [Inject]
    public IOrderRepository OrderRepository { get; set; }
    [Inject]
    public ICustomerRepository CustomerRepository { get; set; }
}

このソリューションをさらに活用することができます。サービスのクラス定義の上にサービスのライフサイクルを指定する属性を使用して...

[Injectable(LifetimeScope.SingleInstance)]
public class IOrderRepository

...次に、autofacを介してサービスを構成するときにこの属性を確認します。しかし、これはこの答えの範囲を超えています。

3
B12Toaster