目錄
-
ModelBinder
-
ModelBinderProvider
-
不同類型的Model綁定
- 簡單類型
- 復雜類型
- 其他類型
ModelBinder
ModelBinder是Model綁定的核心.
public interface IModelBinder
{
//綁定Model方法,返回綁定是否成功
bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext);
}
ModelBindingContext
public class ModelBindingContext
{
//數據源
public IValueProvider ValueProvider { get; set; }
//最終創建的對象 綁定過程就是創建Model
public object Model { get; set; }
//參數名稱
public string ModelName { get; set; }
//參數類型
public Type ModelType { get; }
//參數元數據
public ModelMetadata ModelMetadata { get; set; }
//屬性元數據
public IDictionary<string, ModelMetadata> PropertyMetadata { get; }
//存儲綁定結果(包括錯誤信息,ValueProviderResult),該值引用自ApiController的ModelState
public ModelStateDictionary ModelState { get; set; }
public bool FallbackToEmptyPrefix { get; set; }
}
當ModelBinder特性的Name(為null),FallbackToEmptyPrefix為True.
FallbackToEmptyPrefix為False時,則必須數據源有前綴才能綁定上.
Web API定義了一系列的ModelBinder,這里先介紹
public class CompositeModelBinder : IModelBinder
{
//IModelBinder 集合
public CompositeModelBinder(params IModelBinder[] binders)
//使用內部ModelBinder進行綁定Model(默認遍歷一次,如果FallbackToEmptyPrefix為True,則會有2次遍歷機會)
public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
}
ModelBinderProvider
Web API通過ModelBinderProvider創建ModelBinder
public abstract class ModelBinderProvider
{
public abstract IModelBinder GetBinder(HttpConfiguration configuration, Type modelType);
}
Web API中默認注冊了一系列的ModelBinderProvider
this.SetMultiple<ModelBinderProvider>(new ModelBinderProvider[8]
{
(ModelBinderProvider) new TypeConverterModelBinderProvider(),
(ModelBinderProvider) new TypeMatchModelBinderProvider(),
(ModelBinderProvider) new KeyValuePairModelBinderProvider(),
(ModelBinderProvider) new ComplexModelDtoModelBinderProvider(),
(ModelBinderProvider) new ArrayModelBinderProvider(),
(ModelBinderProvider) new DictionaryModelBinderProvider(),
(ModelBinderProvider) new CollectionModelBinderProvider(),
(ModelBinderProvider) new MutableObjectModelBinderProvider()
});
對應的我們先介紹一下
//同樣都是組裝一批ModelBinderProvider
public sealed class CompositeModelBinderProvider : ModelBinderProvider
{
public CompositeModelBinderProvider(IEnumerable<ModelBinderProvider> providers)
public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
}
ModelBinderAttribute除了通過Name設置FallbackToEmptyPrefix,還有個更重要的屬性BinderType
public class ModelBinderAttribute : ParameterBindingAttribute
{
public string Name { get; set; }
//用來指定ModelBinder 或 ModelBinderProvider
public Type BinderType { get; set; }
}
不同類型的Model綁定
不同的數據類型,有不同的數據結構.
所以針對他們的綁定機制也是不同的.
簡單類型
TypeConverterModelBinder
public sealed class TypeConverterModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
model = valueProviderResult.ConvertTo(bindingContext.ModelType);
bindingContext.Model = model;
return true;
}
}
復雜類型
在介紹復雜類型的Bind前,先介紹一下下面2個類型.
ComplexModelDto包含復雜類型的元數據和綁定結果
public class ComplexModelDto
{
public ComplexModelDto(ModelMetadata modelMetadata, IEnumerable<ModelMetadata> propertyMetadata)
public ModelMetadata ModelMetadata { get; private set; }
public Collection<ModelMetadata> PropertyMetadata { get; private set; }
//key 為屬性的元數據,value 為綁定結果
public IDictionary<ModelMetadata, ComplexModelDtoResult> Results { get; private set; }
}
ComplexModelDtoResult
public sealed class ComplexModelDtoResult
{
//綁定結果值
public object Model { get; private set; }
//驗證信息
public ModelValidationNode ValidationNode { get; private set; }
}
復雜類型的綁定由 MutableObjectModelBinder 和 ComplexModelDtoModelBinder共同完成.
而上面2個類型,實際就是用來在2個ModelBinder間傳遞的對象
public class MutableObjectModelBinder : IModelBinder
{
public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
//類型篩選
if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName) || !MutableObjectModelBinder.CanBindType(bindingContext.ModelType))
return false;
//1. 創建空對象
bindingContext.ModelMetadata.Model = Activator.CreateInstance(bindingContext.ModelType);
//2. 創建ComplexModelDto對象
ComplexModelDto complexModelDto = new ComplexModelDto(bindingContext.ModelMetadata,bindingContext.PropertyMetadata);
//3. 進入綁定流程
this.ProcessDto(actionContext, bindingContext, complexModelDto);
return true;
}
internal void ProcessDto(HttpActionContext actionContext, ModelBindingContext bindingContext, ComplexModelDto dto)
{
//創建子ModelBindingContext
var subContext = new ModelBindingContext(bindingContext)
{
ModelName = bindingContext.ModelName,
ModelMetadata = GetMetadata(typeof(ComplexModelDto))
};
//調用ComplexModelDtoModelBinder 對ComplexModelDto進行綁定
actionContext.Bind(subContext);
//對復雜類型的屬性進行綁定
foreach (var result in (IEnumerable<KeyValuePair<ModelMetadata, ComplexModelDtoResult>>) dto.Results)
{
ModelMetadata key = result.Key;
ComplexModelDtoResult dtoResult = result.Value;
if (dtoResult != null)
{
var property = bindingContext.ModelType.GetProperty(key.PropertyName);
this.SetProperty(actionContext, bindingContext, key, dtoResult,property);
}
}
}
}
ComplexModelDtoModelBinder則將所有屬性再通過調度其他的ModelBinder進行綁定.並將結果保存在ComplexModelDto的Results屬性中.
其他類型
Web API還提供了其他常用的數據類型 ModelBinder
CollectionModelBinder來實現 集合 類型(指的集合是實現了IEnumerable接口的類型)
ArrayModelBinder來實現 數組 類型
DictionaryModelBinder來實現 字典 類型
通過對應的ModelBinderProvider可以知道對應的ModelBinder 能實現哪種類型的綁定
備注
-
文章中的代碼並非完整WebAPI代碼,一般是經過自己精簡后的.
-
本篇內容使用MarkDown語法編輯