ASP.NET MVC 5学習ノートのActionパラメータモデルバインド基本手順

12388 ワード

Controllerでアクションを定義すると、通常は1つ以上のパラメータが定義され、各パラメータは1つのモデル、ASPと呼ばれます.NET MVCフレームワークは、モデルバインディングと呼ばれるメカニズムを提供し、要求された情報から各モデルを自動的にインスタンス化して値を付与しようとします.これには、モデルのメタデータ提供とモデルの検証も含まれます.
文字列値からオブジェクト値へのマッピングメカニズムを定義する場合は、次の情報を知る必要があります.
1.オブジェクトのタイプや名前などのオブジェクト自体のメタデータ
2.オブジェクト属性のメタデータ情報
3.クエリ文字列からオブジェクトおよびオブジェクト属性への値マッピングメカニズム
4.特定のバインドプロセス
前の1,2はASP.NET MVCフレームワークのメタデータ提供メカニズム保証,3はその値提供メカニズム保証,4は具体的なモデルバインドオブジェクトによって実行される.ただASP.NET MVCはモデルバインドが完了した後,ついでにモデルの検証を検証した.
具体的なコードを見てみましょうパラメータモデルバインディング実行肯定特定のActionメソッドが実行される前に、ControllerActionInvokerのInvokeAction側で、Actionメソッドを実行するのはInvokeActionMethodWithFiltersであり、その前の行のコードはIDictionaryparameters=GetParameterValues(controllerrContext,actionDescriptor);この方法の目的はActionのすべてのパラメータ値をパラメータ名に基づいて辞書にカプセル化することである.実装を見てみましょう.
 1 protected virtual IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)

 2         {

 3             Dictionary<string, object> parametersDict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

 4             ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters();

 5 

 6             foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors)

 7             {

 8                 parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);

 9             }

10             return parametersDict;

11         }

すべてのパラメータ記述情報配列がActionDescriptorによって取得され、各パラメータはGetParameterValueを呼び出してそのパラメータ値を取得することがわかります.ここに重要なクラスParameterDescriptorがあります.このクラスは抽象クラスで、以下のように定義されています.
 1  public abstract class ParameterDescriptor : ICustomAttributeProvider

 2     {

 3        

 4         protected ParameterDescriptor();

 5         public abstract ActionDescriptor ActionDescriptor { get; }

 6 

 7         public virtual ParameterBindingInfo BindingInfo { get; }

 8 

 9         public virtual object DefaultValue { get; }

10         public abstract string ParameterName { get; }

11         public abstract Type ParameterType { get; }

12         public virtual object[] GetCustomAttributes(bool inherit);

13         public virtual object[] GetCustomAttributes(Type attributeType, bool inherit);

14         public virtual bool IsDefined(Type attributeType, bool inherit);

15     }

このタイプはBindingInfo属性以外の属性は何も言うことはありません.BindingInfoのタイプはParameterBindingInfoです.このパラメータタイプモデルのバインド中に使用される情報を説明します.具体的には、このタイプの定義を見てみましょう.
1  public abstract class ParameterBindingInfo

2     {

3         protected ParameterBindingInfo();

4         public virtual IModelBinder Binder { get; }

5         public virtual ICollection<string> Exclude { get; }

6         public virtual ICollection<string> Include { get; }

7         public virtual string Prefix { get; }

8     }

Binderプロパティとは、パラメータ固有のバインディングを指し、ModelBinderAttributeで指定し、ExcludeとIncluudeはパラメータプロパティモデルのバインディングリストに参加しないか参加しないか、Prefixはバインディング中に使用されるプレフィックスを表し、この3つのプロパティはBindAttributeプロパティで設定されます.
では、GetParameterValueメソッドの実装を振り返ってみましょう.
 1 protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)

 2         {

 3             // collect all of the necessary binding properties

 4             Type parameterType = parameterDescriptor.ParameterType;

 5             IModelBinder binder = GetModelBinder(parameterDescriptor);

 6             IValueProvider valueProvider = controllerContext.Controller.ValueProvider;

 7             string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;

 8             Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor);

 9 

10             // finally, call into the binder

11             ModelBindingContext bindingContext = new ModelBindingContext()

12             {

13                 FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified

14                 ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),

15                 ModelName = parameterName,

16                 ModelState = controllerContext.Controller.ViewData.ModelState,

17                 PropertyFilter = propertyFilter,

18                 ValueProvider = valueProvider

19             };

20 

21             object result = binder.BindModel(controllerContext, bindingContext);

22             return result ?? parameterDescriptor.DefaultValue;

23         }

a.前の数行のコードはコンテキストをバインドして使用する情報を準備して、簡単なここでは言わないで、具体的なModelBinderはGetModelBinder方法によって取得して、その実現はこのようにです:
  return parameterDescriptor.BindingInfo.Binder ?? Binders.GetBinder(parameterDescriptor.ParameterType); 
ModelBinderAttributeによって指定されたModelBinderは最も優先度が高く、BindersはModelBindersであることがわかります.Binders静的属性、パラメータがModelBinderを指定していない場合はModelBinders.Binders.ModelBinders.Binders.GetBinderメソッドで検索します.具体的な検索はここでは分析しません.ここでは結果を示します.
  1. パラメータにModelBinderAttributeを適用
  2. ModelBinderProviderコレクションで検索
  3. グローバルに登録されたモデルバインドコレクションテーブルで検索
  4. パラメータタイプに対してCustomModelBinderAttributeで指定したモデルバインドタイプ
  5. デフォルトのDefaultModelBinderを返します
b.インスタンス化バインディング上記では、BinderAttributeのPrefixでプレフィックスを指定すると、システムのデフォルトのFallbackToEmptyPrefixは使用されなくなり、また、パラメータモデルのメタデータは、システムのメタデータを呼び出すことによってメカニズムを提供するModelMetadataProviders.Current.GetMetadataForType.
c.nullを返してパラメータ指定のデフォルト値を返すモデルバインドを実行する
このコード情報量は比較的大きく,メタデータ提供メカニズム,値提供メカニズム,モデルバインドと検証を含む.後述する章では、それぞれ説明します.