1

パラメータにインターフェイスを使用するときに、AutofacExtensibleActionInvokerがMVCModelBinderと対話する際に問題が発生します。背景は次のとおりです。

私はMVCアプリケーションを構築しており、Autofac MVC3のExtensibleActionInvokerを使用して、アクションのパラメーターとしてサービスを挿入しています。

    public ActionResult Test( IMyService service)
    {
        //A new instance of service is created by Autofac ExtensibleActionInvoker 
        return View();
    }

これは非常にうまく機能し、非常にクリーンなデザインになります(このアプローチの詳細については、 Alex Meyer-Gleavesの投稿を参照してください)。アクション、ビュー、サービス、およびDTOを作成するためのコードジェネレーターを作成しているときにこのメソッドを使用したいと思います。アクションごとのサービスアプローチにより、これが簡単になります。

ただし、HttpPostアクションから入力を受け取る、クラス化されたアクションのパラメーターにもインターフェイスを使用したいと思います。これは、DIを使用して各レイヤーの外部にクラスを作成しているためです。DIを使用してクラスを作成するようにDefaultModelBinderを変更すると(これを行う方法については、MVC3に関するSteve Sandersonの本の595ページを参照)、これは正常に機能します。

    [HttpPost]
    public ActionResult Test(ITestClass dataComingFromView)
    {
        //model binder creates the class via DI and then binds it to the data from the post
        return View();
    }

ただし、上記の簡単な例では、ExtensibleActionInvokerを有効にすると競合が発生します。

  1. ExtensibleActionInvokerが有効になっていない場合、上記のメソッドは正常に機能します。つまり、拡張DefaultModelBinderはDIを使用してTestClassクラスを作成し、modelbinderはビューからの入力をクラスのフィールドにバインドします。
  2. ExtensibleActionInvokerを有効にすると、機能しません。つまり、バインディングのない空のTestClassクラスを取得します。ExtensibleActionInvokerがモデルバインダーよりも優先され、空のTestClassクラスを作成するだけだと思います。
  3. (完全を期すために、MVCを「箱から出して」使用する場合、つまり、新しいDefaultModelBinderとExtensibleActionInvokerが有効になっていない場合、アクションメソッドパラメーターとしてインターフェイスを使用できないと表示されます。)

Autofacの知識が私よりも優れている人への私の質問は、Autofac ExtensibleActionInvokerを変更して、バインド先を選択できるかどうかです。クラス分けされたすべての注入されたサービスはIServiceで始まるので、それでフィルタリングできます。Autofacの他の場所でそれを行うことができることは知っていますが、ExtensibleActionInvokerでそれを行うことはできませんでしたが、おそらく私はそれを見逃しました。

どんな助けでもいただければ幸いです。

JonSmith-選択的分析

4

2 に答える 2

0

この問題に取り組んだ後、私は簡単な答えを見つけました。私の問題は、MVCモデルバインディングがどのように機能するかを本当に理解していないことが原因でした。

私の元の問題を見ると、モデルパラメータとしてインターフェイスを使用できるようにDefaultModelBinderを作成しました(上部の元の質問を参照)。これは、IServiceタイプをバインドするためにAutofacのExtensibleActionInvokerを含めた後に追加されました。問題は、2つのDIアプローチが衝突したことでした。

答えは、DefaultModelBinderでデータクラスとサービス定義の両方をバインドするのに十分だったので、AutofacのExtensibleActionInvokerは必要ないということでした。完全を期すために、他の人に役立つ場合に備えてDefaultModelBinderコードを含めました。

public class DiModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return modelType.IsInterface
                   ? DependencyResolver.Current.GetService(modelType)
                   : base.CreateModel(controllerContext, bindingContext, modelType);
    }
}

レイヤー間で抽象クラスを渡さないため、モデルタイプがインターフェイスである場合にのみDependencyResolverを呼び出すことに注意してください。DIがタイプを解決しない場合は、常にDependencyResolverを呼び出してから、base.CreateModelを呼び出すこともできます。DependencyResolverの呼び出しは少しコストがかかるため、これを行いませんでした。必要な場合にのみ呼び出します。

于 2012-09-11T14:04:05.700 に答える
0

ExtensibleActionInvoker問題がクラスによって引き起こされていることは正しいです。そのソースを見ると、 というメソッドがありGetParameterValue()ます。下記参照:

    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        if (_injectActionMethodParameters)
            return _context.ResolveOptional(parameterDescriptor.ParameterType) ?? base.GetParameterValue(controllerContext, parameterDescriptor);

        return base.GetParameterValue(controllerContext, parameterDescriptor);
    } 

このメソッドは、最終的に MVC フレームワークのモデル バインダー インフラストラクチャを使用するメソッドをオーバーライドします。つまり、ActionInvoker は最初に AutoFac を使用してパラメーターの解決を試み、失敗した場合はデフォルトの機能にフォールバックします。取得している結果に基づいて、AutoFac 構成をセットアップして、デフォルトの解像度ITestClass.

カスタム ModelBinder を AutoFac に登録するには、いくつかのオプションがあります。でビュー モデルを装飾するModelBinderTypeAttributeか、 にあるカスタム拡張メソッドを使用して構成で行うことができますRegistrationExtensions

私が見つけた 1 つの記事は、同様の問題に対する簡単な解決策を提供しているように見えますが (末尾を参照)、個人的にはテストしていません。

于 2012-08-29T14:28:11.273 に答える