ASP.NET MVC Modelバインド(四)


ASP.NET MVC Modelバインド(四)
前言
前のページでは、ModelバインダーIModelBinderや実装タイプ、Modelバインダープロバイダについて大まかに説明しましたが、Modelバインダーを大きな容器に想像できるのはなぜですか?疑問をここに残します.
まず、コントローラのメソッドパラメータは複数のタイプ、複数の同じタイプである可能性があり、MVCフレームワークで使用されるバインド実装に対応するにはIValueProviderが行うが、パラメータタイプの違いなど、IValueProviderの実装クラスにも大きな違いがあり、これらの具体的な実装の説明は後述する.
傍観者清と言われていますが、MVCのフレームに入って外に立って見ないでください.本編では、IValueProviderについて外の角度から説明します.
 
Modelバインド
  • IModelBinder、カスタムModelバインダ
  • を簡単に実現
  • ModelバインダのMVCフレームにおける位置
  • MVCのデフォルトModel Binder生成プロセス
  • IModelBinderProviderの簡単な応用
  • IValueProviderがMVCフレームワークで生成する位置およびプロセス
  • IValueProviderのアプリケーションシーン
  • IValueProviderの実装N a m e ValueCollectionValueProvider
  •  
    IValueProviderがMVCフレームワークで生成する位置およびプロセス
    生成された場所
    ASPで覚えていますか?NET MVC Model Binding(二)では、Model Binder生成位置の説明について、生成位置の説明図を借りて、
    図1
    図1に示すように、青色ライン実行フローでは、Modelバインド生成後、IValueProviderタイプが生成されますが、生成が妥当でないということで、取得に変更しましょう.なぜかというと、次の生成部分では
     
    生成プロセス
    まず、図1の青い線の流れの実装コードを見てみましょう.
    コード1-1
    protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
            {
                Type parameterType = parameterDescriptor.ParameterType;
                IModelBinder modelBinder = this.GetModelBinder(parameterDescriptor);
                IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
                string str = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
                Predicate propertyFilter = GetPropertyFilter(parameterDescriptor);
                ModelBindingContext context2 = new ModelBindingContext
                {
                    FallbackToEmptyPrefix = parameterDescriptor.BindingInfo.Prefix == null,
                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
                    ModelName = str,
                    ModelState = controllerContext.Controller.ViewData.ModelState,
                    PropertyFilter = propertyFilter,
                    ValueProvider = valueProvider
                };
                ModelBindingContext bindingContext = context2;
                return (modelBinder.BindModel(controllerContext, bindingContext) ?? parameterDescriptor.DefaultValue);
            }

    コード1-1に示されている方法については,その戻りタイプやこの方法の役割を気にせず,IValueProviderがどのように来たのかを今知りたい!!!
    コード1−1から、Modelバインディングを生成した後、MVCフレームワークは、ControllerContextコントローラコンテキストパラメータオブジェクトから現在要求されているコントローラの参照を取得し、現在のコントローラオブジェクトの参照に基づいてIValueProviderタイプを取得することを明確に示す.
    その後、MVCフレームワークはModelBindingContextタイプをインスタンス化し、取得したIValueProviderタイプをValueProviderプロパティに割り当てます.
    ModelBindingContextタイプの場合、Modelはコンテキストオブジェクトをバインドし、定義コード1-2を参照してください.
    コード1-2
    public class ModelBindingContext
        {
            public ModelBindingContext();
            public ModelBindingContext(ModelBindingContext bindingContext);
            public bool FallbackToEmptyPrefix { get; set; }
            public object Model { get; set; }
            public ModelMetadata ModelMetadata { get; set; }
            public string ModelName { get; set; }
            public ModelStateDictionary ModelState { get; set; }
            public Type ModelType { get; set; }
            public Predicate PropertyFilter { get; set; }
            public IDictionary PropertyMetadata { get; }
            //
            //   :
            //               。
            //
            //     :
            //          。
            public IValueProvider ValueProvider { get; set; }
        }

    ここではModelBindingContextタイプを初歩的に理解するだけでいいので、トピックに戻って、現在のコントローラオブジェクトの参照から直接取得したものについて説明します.コントローラのValueProviderプロパティを見てみましょう.Controllerタイプ、コード1-3を見てみましょう.
    コード1-3
    public abstract class Controller : ControllerBase, IActionFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
    {
       ……
    }

    みんなと冗談を言って、雰囲気を和らげた.Controllerタイプには私たちが探している属性はありません.ある友达は、ベースクラスタイプで、確かにControllerBaseタイプであることを考えました(コード1-4).
    コード1-4
    public abstract class ControllerBase : IController
    {
       ……
       public IValueProvider ValueProvider { get; set; }
    }

    IValueProviderを使用するときにコントローラオブジェクトに値を割り当てるのですか?
    もちろんそうではありません.コード1-4のValueProviderプロパティの実装例を見てみましょう.コード1-5です.
    コード1-5
    public IValueProvider ValueProvider
            {
                get
                {
                    if (this._valueProvider == null)
                    {
                        this._valueProvider = ValueProviderFactories.Factories.GetValueProvider(this.ControllerContext);
                    }
                    return this._valueProvider;
                }
                set
                {
                    this._valueProvider = value;
                }
            }

    ここを見て、IValueProviderタイプの由来は、システムのValueProviderFactoriesタイプのFactoriesプロパティから現在のコントローラコンテキストに基づいて取得されていることがわかると思います.
    ここでは、IValueProviderタイプを生成するいくつかの関連タイプの定義を見てみましょう.サンプルコード1〜6です.
    コード1-6
        public static class ValueProviderFactories
        {
            //   :
            //                      。
            //
            //     :
            //                 。
            public static ValueProviderFactoryCollection Factories { get; }
        }
    
        public class ValueProviderFactoryCollection : Collection
        {
            public ValueProviderFactoryCollection();
            public ValueProviderFactoryCollection(IList list);
    
            //   :
            //                       。
            //
            //   :
            //   controllerContext:
            //         ,          HTTP      。
            //
            //     :
            //                         。
            public IValueProvider GetValueProvider(ControllerContext controllerContext);
            protected override void InsertItem(int index, ValueProviderFactory item);
            protected override void SetItem(int index, ValueProviderFactory item);
        }
    
        public abstract class ValueProviderFactory
        {
           
            protected ValueProviderFactory();
    
            //   :
            //                       。
            //
            //   :
            //   controllerContext:
            //         ,          HTTP      。
            //
            //     :
            //            。
            public abstract IValueProvider GetValueProvider(ControllerContext controllerContext);
        }

    ValueProviderFactoryCollectionタイプのこのモードは前に見たことが多すぎて、言うまでもなく、ValueProviderFactoryCollectionタイプの静的属性が含まれていますが、ValueProviderFactoryCollectionタイプはValueProviderFactoryタイプの集合タイプなので、最終生IValueProviderタイプになるときもValueProviderFactoryCollectionタイプを巡ります.各ValueProviderFactoryタイプのインスタンスを取得し、IValueProviderタイプを生成します.ここでも、最適な一致ではなく、最初に一致します.
    ここでは、ValueProviderFactoryタイプの生成ロジックをコントローラコンテキストオブジェクトで分類し、異なるコントローラに対して異なるIValueProviderタイプを生成することができます.IValueProviderタイプの使用については後述する.