15

Autofac を使用して、MVC 4 アプリの FluentValidation に依存関係を挿入しようとしています。戦略はうまくいったと思いますが、リクエストごとの ISomething をシングルトンから解決することに行き詰まっています。

シナリオは次のとおりです。FluentValidation の AbstractValidator から派生したバリデーターがあります。FluentValidation バリデーターはシングルトンとして最高のパフォーマンスを発揮することを読んだので、コンストラクターは Func を期待し、後で使用するためにその Factory を格納します。バリデーターを使用する場合、格納されたファクトリに IDataStore を要求し、その要求に対して作成されたインスタンスを取得して使用する必要があります。それが理論です。このソリューションに落ち着くのに役立ったhttps://github.com/robdmoore/UnobtrusiveMVCTechniquesの功績を認めたいと思います。これがバリデーターです...

public class SiteAdminViewModelValidator : AbstractValidator<SiteAdminViewModel> {
    private readonly Func<IDataStore> _dbFactory;

    public SiteAdminViewModelValidator(Func<IDataStore> dbFactory) {
        _dbFactory = dbFactory;

        RuleFor(model => model.SiteCode).Length(1, 40).Must(BeSpecial);
    }

    public bool BeSpecial(string siteCode) {
        var db = _dbFactory();
        List<Stuff> stuffs = db.All<Stuff>().ToList();

        return true;
    }
}

誰かが私が達成しようとしていることの実用的な例を教えてくれれば、それは素晴らしいことですが、Autofac のこの特定のトリッキーさに対する解決策も知りたいです。

これが私のバリデータ登録です...

public class FluentValidatorModule : Module {
    protected override void Load(ContainerBuilder builder) {
        base.Load(builder);
        builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();

    var validators = AssemblyScanner.FindValidatorsInAssembly(System.Reflection.Assembly.GetExecutingAssembly());
    validators.ToList().ForEach(v => builder.RegisterType(v.ValidatorType).As(v.InterfaceType).SingleInstance());
    }
}

IDataStore ファクトリへの登録は次のとおりです...

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.Register<Func<IDataStore>>(c => {
                                       var context = c.Resolve<IComponentContext>();
                                       return context.Resolve<IDataStore>;
                                   });

これは、バリデーターが行で IDataStore を要求したときに発生するエラーです - var db = _dbFactory();

「AutofacWebRequest」に一致するタグを持つスコープは、インスタンスが要求されたスコープからは見えません。これは通常、HTTP ごとのリクエストとして登録されたコンポーネントが、SingleInstance() コンポーネント (または同様のシナリオ) によってリクエストされていることを示します。Web 統合の下では、コンテナー自体からではなく、常に DependencyResolver.Current または ILifetimeScopeProvider.RequestLifetime から依存関係をリクエストします。 .

...これは、自分の Factory 登録 (Func 登録) を作成する前に試してみたときに得られたものとまったく同じです。同様の質問に対するさまざまな回答を読んだところ、現在のリゾルバーを取得するために Func を解決していると思ったので、上記のものがうまくいくように見えました。

どんな助けでも大歓迎です。

4

2 に答える 2

18

これが機能することに同意します-Func<IDataStore>必要に応じて各メソッドで依存関係を生成するファクトリを定義しています。

この方法を回避する方法はDependencyResolver.Current、エラー メッセージが示すように使用することです。主な理由は、Autofac.Mvc4 nuget パッケージを使用して既にセットアップしたことです...

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

したがって、実際にメソッドをセットアップするには、次の機能があります

public Func<T> PerHttpSafeResolve<T>()
{
    return () => DependencyResolver.Current.GetService<T>();
} 

そして、コンテナを構築するとき

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());

編集: インスタンスを登録している 2 行目は、「必要な場合はFunc<IDataStore>、メソッドに渡された値を使用する」と言っています。の結果PerHttpSafeResolve<IDataStore>は単なる関数 (ファクトリ) であるため、単一のインスタンスとして存続できます。

于 2013-03-21T08:18:53.080 に答える
9

問題は、バリデータの範囲です。Autofac は常にSingleInstanceアプリケーション コンテナーから依存関係を解決します。つまり、バリデーターの依存関係もアプリケーション コンテナーから取得されます。

Autofac は、リクエスト コンテナからではなく、そこFunc<IDataStore>からインスタンスをリクエストしています。解決すると、バリデーターが解決されているコンテナー、つまりアプリケーション コンテナーが取得されます。リクエストのスコープであるため、 Autofacがアプリケーション レベルでそれを提供する方法がないため、エラーが発生します。IComponentContextFunc<IDataStore>

正しいアプローチは、バリデータを として登録することInstancePerHttpRequestです。コンポーネントの存続期間は、最長存続期間の依存関係によって決定されます。依存関係がない場合、バリデーターはシングルトンとして最適に機能します。ただし、この場合、依存するバリデーターはIDataStore、せいぜい IDataStoreインスタンスの存続期間にわたって存続するように制約されます。(明るい面では、を取り除くことができますFunc。)

パーティーに行くようなものだと考えてみてください。主催者の車に乗ったら、パーティーが終わるまでそこにいなければなりません。早く出発したい場合は、ホストと一緒に乗ることはできません。

于 2013-03-21T04:49:50.297 に答える