2017-07-08 6 views
2

Microsoft.Extensions.DependencyInjection 1.1.1に依存するASP.NET Core 1.1.2 Webプロジェクトで、一般的なFluentValidationバリデーターをその実装とそのインターフェースの両方で登録してください。実行時には、ホストの建物の間に、私は例外次しまっ:ASP.NETコアで部分的に閉じたジェネリック型を登録するMicrosoft.Extensions.DependencyInjection

An unhandled exception of type 'System.ArgumentException' occurred in Microsoft.Extensions.DependencyInjection.dll 

Cannot instantiate implementation type 'MyProj.Shared.Api.WithUserCommandValidator`1[T]' for service type 'FluentValidation.IValidator`1[MyProj.Shared.Model.WithUser`1[T]]'. 

    at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceTable..ctor(IEnumerable`1 descriptors) 
    at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable`1 serviceDescriptors, Boolean validateScopes) 
    at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services) 
    at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() 
    at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() 
    at MyProj.Program.Main(String[] args) in X:\MySolution\src\MyProj\Program.cs:line 31 

これは(一般的な、非抽象)バリデータクラスです:

public class WithUserCommandValidator<TCommand> : AbstractValidator<WithUser<TCommand>> 
    where TCommand : ICommand 
{ 
    public WithUserCommandValidator(IValidator<TCommand> commandValidator) 
    { 
     RuleFor(cmd => cmd).NotNull(); 

     RuleFor(cmd => cmd.UserId).NotEqual(Guid.Empty); 

     RuleFor(cmd => cmd.Content).NotNull() 
      .SetValidator(commandValidator); 
    } 
} 

(わからない、それは、WithUser<T>クラスを示すことが重要ですGuid UserIdT Contentを保持しています)。

登録はそうのように起こる:

someInterface = typeof(FluentValidation.IValidator<WithUser<>>); 
someImplementation = typeof(Shared.Api.WithUserCommandValidator<>); 

// this is for top-level command validators, injected by interface 
services.AddScoped(someInterface, someImplementation); 

// this is for nested validators, injected by implementation 
services.AddScoped(someImplementation); 

と、実行時にこれらの変数を保持する:

+ someInterface {FluentValidation.IValidator`1[MyProj.Shared.Model.WithUser`1[TCommand]]} System.Type {System.RuntimeType} 
+ someImplementation {MyProj.Shared.Api.WithUserCommandValidator`1[TCommand]} System.Type {System.RuntimeType} 

正しい思われます。

私も同様の問題や疑問を抱えていますが、これは具体的なものですが、一般的な実装であるため、実際には関連していません。

私はDependencyInjectionモジュールコードを踏襲し、例外はhereをスローしました。なんらかの理由で、serviceTypeInfo.IsGenericTypeDefinitionfalse(インターフェイスタイプが一般的なのでtrueではないはずです)を返し、else-branchがとられます。代わりに、実装タイプが,からimplementationTypeInfo.IsGenericTypeDefinitionに戻りますので、例外があります。

ランタイム値は次のとおりです。

+ serviceTypeInfo {FluentValidation.IValidator`1[MyProj.Shared.Model.WithUser`1[TCommand]]} System.Reflection.TypeInfo {System.RuntimeType} 
+ implementationTypeInfo {MyProj.Shared.Api.WithUserCommandValidator`1[TCommand]} System.Reflection.TypeInfo {System.RuntimeType} 

いじっている間、私はまた、インターフェース+実装を登録せず、唯一の実装を登録しようとした、その例外が消えます。しかし、可能であれば実装を実装するのではなく、インタフェースを注入したいと思います。

私は間違っていますか? TA

+0

いくつかの詳細:シンプルなインジェクターで

は、単に以下の登録を行うことができます。しかし、私は前者が何を意味するかについての情報はありません。 – superjos

答えて

2

あなたがしようとしているのは、.NET CoreのDIコンテナではサポートされていない、部分閉鎖型(つまり、IValidator<WithUser<T>>)をマッピングすることです。ジェネリック型について言えば、.NET Coreコンテナは非常に最小限の単純化された実装です。抽象化とは異なる順序で

  • ジェネリック型制約
  • 部分的に閉じたタイプの抽象未満ジェネリック型引数を持つ
  • 実装ジェネリック型引数を持つ
  • 実装:のようなものを処理することができません
  • 部分的に閉じられた抽象化の型引数の一部としてネストされている汎用の型引数を持つ(正確な場合)
  • Curiously recurring template pattern

あなたはが内蔵され、このためのコンテナを使用し続けておきたい、この動作が必要な場合は、手動で各閉じ実装を登録する必要があります:

AddScoped(typeof(IValidator<WithUser<Cmd1>>), typeof(WithUserCommandValidator<Cmd1>)); 
AddScoped(typeof(IValidator<WithUser<Cmd2>>), typeof(WithUserCommandValidator<Cmd2>)); 
AddScoped(typeof(IValidator<WithUser<Cmd3>>), typeof(WithUserCommandValidator<Cmd3>)); 
// etc 

これがある場合は、維持できないComposition Rootにつながる場合は、別のコンテナを選択する必要があります。しかし、あなたの選択肢はこの点で制限されています。私が知っている唯一のDIコンテナは、これらの種類のジェネリックデザインを実際に完全にサポートしています。Simple Injectorです。代わりに、 `serviceTypeInfo.IsGenericType`が真の間、偽である.NETのコアコードをチェックし` serviceTypeInfo.IsGenericTypeDefinition`、:

container.Register(
    typeof(IValidator<>), 
    typeof(WithUserCommandValidator<>), 
    Lifestyle.Scoped); 
+0

私は参照してください。それらの特定の制限を認識していませんでした。 Thanks – superjos

+1

オートファックは、これらのオープンタイプを登録することもできます:http://autofaccn.readthedocs.io/en/latest/register/registration.html#open-generic-components。コマンドとクエリのパターンを使用しているため、この機能に大きく依存しています。 –

関連する問題