MVC中Action參數綁定的過程

1、題外話

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

ControllerContextweb

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

2、Model綁定者

2.1相關說明ide

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

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綁定者實現綁定的途徑this

1)直接在參數上綁定spa

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上加標記code

    [ModelBinder(typeof(PersonModelBinder))] 
    public class Person
    {
        
        public string Name { get; set; }

        public int Age { get; set; }

    }

3)ModelBinders.Binders中註冊orm

protected void Application_Start()

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

 

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

如下是

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都不會執行,因此使用系統默認的綁定者 }

 3、下一章接着介紹DefaultModelBinder

相關文章
相關標籤/搜索