3

IMapper初めて Autofac を使用して、オブジェクト マッピング要件を持つクラスにAutoMapper のインターフェイスを挿入しました。アセンブリ スキャンを使用して AutoMapper のレジスタに追加されたさまざまな依存関係を取得するために、少しの助けを借りて、いくつかの進歩を遂げました。

builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
    .AsClosedTypesOf(typeof(ITypeConverter<,>))
    .AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(AutoMapperExtensions).Assembly)
    .AssignableTo<Profile>().As<Profile>();

builder.Register(context => {
    var profiles = context.Resolve<IEnumerable<Profile>>();
    return new MapperConfiguration(x => {
        foreach (var profile in profiles) x.AddProfile(profile);
    });
}).SingleInstance().AutoActivate().AsSelf();

builder.Register(context => {
    var componentContext = context.Resolve<IComponentContext>();
    var config = componentContext.Resolve<MapperConfiguration>();
    return config.CreateMapper();
}).As<IMapper>();

ITypeConverter<,>これは、依存関係が注入されていないに対して完全に機能します。

public class SourceToDestinationTypeConverter : ITypeConverter<SourceModel, DestinationModel> {
    public DestinationModel Convert(SourceModel source, DestinationModel destination, ResolutionContext context) {
        if (source.Items == null) {
            return null;
        }

        return new DestinationModel {
            FirstItem = source.Items.FirstOrDefault(),
            LastItem = source.Items.LastOrDefault()
        };
    }
}

ただし、依存関係を追加した瞬間から、この不自然な例ではバリデーター:

public class SourceToDestinationTypeConverter : ITypeConverter<SourceModel, DestinationModel> {
    private readonly IValidator<SourceModel> _validator;

    public SourceToDestinationTypeConverter(IValidator<SourceModel> validator) {
        _validator = validator;
    }

    public DestinationModel Convert(SourceModel source, DestinationModel destination, ResolutionContext context) {
        if (!_validator.Validate(source)) return null;

        return new DestinationModel {
            FirstItem = source.Items.FirstOrDefault(),
            LastItem = source.Items.LastOrDefault()
        };
    }
}

次の例外がスローされます。

Application.TypeConverters.SourceToDestinationTypeConverter0 の引数またはオプションの引数のみを持つコンストラクターが必要です

依存関係を満たすためにAutofac を使用するように AutoMapper に指示する必要があることは明らかです。ただし、そうするように指示する方法を見つけることができませんでした。

エラーをさらに明確にする必要がある場合は、完全なソリューションを GitHubで入手できます。

4

2 に答える 2

3

注: Travis Illig は、広く一般的な方法で質問に回答するため、私が回答としてマークしている質問に対する全体的な回答を提供しました。ただし、質問に対する具体的な解決策も文書化したいと思いました。

依存関係リゾルバーを AutoMapper に接続する方法にはかなり注意する必要があります。正確には、クロージャー内のコンポーネント コンテキストを解決する必要があります。そうしないと、AutoMapper が解決する機会を得る前にコンテキストが破棄されます。依存関係。

解決策 1

IMapper私の例では、以前に定義された を使用してを登録する次のコード ブロックMapperConfiguration:

builder.Register(c => {
    var context = c.Resolve<IComponentContext>();
    var config = context.Resolve<MapperConfiguration>();
    return config.CreateMapper();
}).As<IMapper>();

AutoMapper が依存関係を構築するために使用する引数としてMapperConfiguration.CreateMapper()a を受け入れるのオーバーロードを使用することで、自明に適応させることができます。Func<Type, object>serviceCtor

builder.Register(c => {
    var context = c.Resolve<IComponentContext>();
    var config = context.Resolve<MapperConfiguration>();
    return config.CreateMapper(context.Resolve);
}).As<IMapper>();

Component Contextcontextは、クロージャ内で宣言されているとおりに使用cすることが不可欠です。使用しようとすると、次の例外が発生します。

この解決操作は既に終了しています。ラムダを使用してコンポーネントを登録する場合、ラムダへのIComponentContext' c' パラメータを格納できません。代わりに、 ' 'IComponentContextから再度解決するか、ベース ファクトリを解決して後続のコンポーネントを作成してください。cFunc<>

解決策 2

解決策 1 と非常によく似た手法を使用するIMapperConfiguration.ConstructServiceUsing(Func<Type, object>)と、より読みやすいコードを提供する を使用できます。元のコード:

builder.Register(c => {
    var profiles = c.Resolve<IEnumerable<Profile>>();
    return new MapperConfiguration(x => {
        foreach (var profile in profiles) x.AddProfile(profile);           
    });
}).SingleInstance().AsSelf();

そして、への呼び出しを含む更新されたコードx.ConstructServiceUsing(constructor):

builder.Register(c => {
    var profiles = c.Resolve<IEnumerable<Profile>>();
    var context = c.Resolve<IComponentContext>();
    return new MapperConfiguration(x => {
        foreach (var profile in profiles) x.AddProfile(profile);
        x.ConstructServicesUsing(context.Resolve);                   
    });
}).SingleInstance().AsSelf();

繰り返しますが、クロージャー/ラムダ内でのインスタンスの作成に失敗するとIComponentContext、マッパーが依存関係を作成する前にコンテキストが破棄されます。

于 2016-10-28T21:12:18.290 に答える
2

AutoMapper の構成中に呼び出しを追加するのConstructServicesUsingを忘れたと思います。これを必ず実行してください

Autofac をアプリに統合する正確な方法は、使用しているアプリの種類 (Windows サービス? MVC? Web API? Windows フォーム? UAP?) と、有効期間スコープの使用に関する期待値によって異なりますそれはあなたの質問には含まれていませんでした。ただし、Web で「autofac constructservicesusing」を検索すると、同じトピックに関する他のいくつかの StackOverflow の質問を含む多くの例が見つかります。

これは、あなたがしていることをほぼ正確に示す簡単な例です。MVC または Web API アプリを使用していて、リクエスト スコープごとのサポートが必要な場合は、それに関する完全なブログ チュートリアルがあります。

ちなみに、AutoActivate電話が本当に必要かどうかはわかりません。SingleInstanceはスレッドセーフであり、AutoMapper プロファイルを遅延して構築するのに実際にはそれほど時間がかかりません。特に AutoMapper 自体が実行されるまでその部分を実行しない場合は、それなしで試してみることをお勧めしAutoActivateます。

于 2016-10-28T13:21:58.320 に答える