MVC中Action參數綁定的過程


一、題外話

上一篇:MVC中Action的執行過程

ControllerContext

封裝有了與指定的 RouteBase ControllerBase 實例匹配的 HTTP 請求的信息。

二、Model綁定者

2.1相關說明

http請求中的參數綁定到Model,是由實現了IModelBinder的類來完成的。我們稱這樣的類叫做Model綁定者

using System;
namespace System.Web.Mvc
{
/// <summary>Defines the methods that are required for a model binder.</summary>
public interface IModelBinder
{
/// <summary>Binds the model to a value by using the specified controller context and binding context.</summary>
/// <returns>The bound value.</returns>
/// <param name="controllerContext">The controller context.</param>
/// <param name="bindingContext">The binding context.</param>
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}
}

2.2Model綁定者實現綁定的途徑

1)直接在參數上綁定

using System;
using System.Web;
using System.Web.Mvc;

namespace MVC_ST_2.Controllers
{

public class Person
{

public string Name { get; set; }

public int Age { get; set; }

}

public class PersonModelBinder : IModelBinder
{

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
HttpRequestBase request
= controllerContext.HttpContext.Request;
var p = new Person();
p.Name
= request["Name"];
p.Age
=int.Parse( request["Age"]);
return p;
}


}

public class HomeController : Controller
{
//通過參數標記
public ActionResult Index([ModelBinder(typeof(PersonModelBinder))] Person p)
{
return View();
}

public ActionResult Index2(Person p)
{
return View();
}
}
}

2)在model上加標記

    [ModelBinder(typeof(PersonModelBinder))] 
public class Person
{

public string Name { get; set; }

public int Age { get; set; }

}

3)ModelBinders.Binders中注冊

protected void Application_Start()

{
ModelBinders.Binders[
typeof(Person)] = new PersonModelBinder();
}

 

2.3 Action中是如何調用綁定者的?

以下是

private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor)
{
return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType);
}

說明:通過參數標記的方式優先,如果沒有則使用this.Binders.GetBinder(parameterDescriptor.ParameterType);

this.Binders的定義

protected internal ModelBinderDictionary Binders
{
get
{
if (this._binders == null)
{
this._binders = ModelBinders.Binders;
}
return this._binders;
}
set
{
this._binders = value;
}
}

從上圖可以看出,最終的綁定操作交給了ModelBinderDictionary(注意了,下面會接着講)

正好我們回到前兩章講的ControllerActionInvoker,其中的參數綁定賦值過程GetParameterValues如何獲取的過程即綁定的過程

 

 

protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
Type parameterType
= parameterDescriptor.ParameterType;
IModelBinder modelBinder
= this.GetModelBinder(parameterDescriptor);
IValueProvider valueProvider
= controllerContext.Controller.ValueProvider;
string modelName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate
<string> propertyFilter = ControllerActionInvoker.GetPropertyFilter(parameterDescriptor);
ModelBindingContext bindingContext
= new ModelBindingContext
{
FallbackToEmptyPrefix
= parameterDescriptor.BindingInfo.Prefix == null,
ModelMetadata
= ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
ModelName
= modelName,
ModelState
= controllerContext.Controller.ViewData.ModelState,
PropertyFilter
= propertyFilter,
ValueProvider
= valueProvider
};
object obj = modelBinder.BindModel(controllerContext, bindingContext);
return obj ?? parameterDescriptor.DefaultValue;
}
private IModelBinder GetModelBinder(ParameterDescriptor parameterDescriptor)
{
return parameterDescriptor.BindingInfo.Binder ?? this.Binders.GetBinder(parameterDescriptor.ParameterType);
}
 this.Binders 其類型正好是ModelBinderDictionary(上面提到過),他的方法如下
    public IModelBinder GetBinder(Type modelType)
{
return this.GetBinder(modelType, true);
}
/// <summary>Retrieves the model binder for the specified type or retrieves the default model binder.</summary>
/// <returns>The model binder.</returns>
/// <param name="modelType">The type of the model to retrieve.</param>
/// <param name="fallbackToDefault">true to retrieve the default model binder.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="modelType" /> parameter is null.</exception>
public virtual IModelBinder GetBinder(Type modelType, bool fallbackToDefault)
{
if (modelType == null)
{
throw new ArgumentNullException("modelType");
}
return this.GetBinder(modelType, fallbackToDefault ? this.DefaultBinder : null);
       //this.DefaultBinder 是下一章我們需要講的內容。也是整個MVC核心的默認的綁定者
}
private IModelBinder GetBinder(Type modelType, IModelBinder fallbackBinder)
{
IModelBinder modelBinder
= this._modelBinderProviders.GetBinder(modelType);
if (modelBinder != null)
{
return modelBinder;
}
if (this._innerDictionary.TryGetValue(modelType, out modelBinder))
{
return modelBinder;
}
modelBinder
= ModelBinders.GetBinderFromAttributes(modelType, () => string.Format(CultureInfo.CurrentCulture, MvcResources.ModelBinderDictionary_MultipleAttributes, new object[]
{
modelType.FullName
}));
return modelBinder ?? fallbackBinder;//DefaultBinder 很多情況下,前面的幾個if都不會執行,所以使用系統默認的綁定者
}

 三、下一章接着介紹DefaultModelBinder


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com