MVC擴展(ModelBinder)


1.從最簡單的開始

model

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
}

cshtml

@using (Html.BeginForm())
{
            <div>@Html.TextBoxFor(_ => _.ID)</div> 
        <div>@Html.TextBoxFor(_ => _.Name)</div> 
        <input type="submit" value="Submit" />
    }

 

controller

public ActionResult Person()
    {
        var person = new Person() {ID = "PsersonId", Name = "PersonName"};
        return View();
    }

    [HttpPost]
    public ActionResult Person(Person person)
    {
        return View();
    }

Person和表單元素實現了自動綁定。省去了逐一賦值的步驟。當頁面的字段增多時,ModelBind機制可以節省不少開發時間。

2.實現原理

綁定的過程由MVC中的DefaultModelBinder完成。

DefaultModelBinder簽名如下

/// <summary>
  /// Maps a browser request to a data object. This class provides a concrete implementation of a model binder.
  /// </summary>
  public class DefaultModelBinder : IModelBinder
  {
    /// <summary>
    /// Binds the model by using the specified controller context and binding context.
    /// </summary>
    /// 
    /// <returns>
    /// The bound object.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext "/>parameter is null.</exception>
    public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Binds the specified property by using the specified controller context and binding context and the specified property descriptor.
    /// </summary>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="propertyDescriptor">Describes a property to be bound. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value.</param>
    protected virtual void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor);
    /// <summary>
    /// Creates the specified model type by using the specified controller context and binding context.
    /// </summary>
    /// 
    /// <returns>
    /// A data object of the specified type.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="modelType">The type of the model object to return.</param>
    protected virtual object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType);
    /// <summary>
    /// Creates an index (a subindex) based on a category of components that make up a larger index, where the specified index value is an integer.
    /// </summary>
    /// 
    /// <returns>
    /// The name of the subindex.
    /// </returns>
    /// <param name="prefix">The prefix for the subindex.</param><param name="index">The index value.</param>
    protected static string CreateSubIndexName(string prefix, int index);
    /// <summary>
    /// Creates an index (a subindex) based on a category of components that make up a larger index, where the specified index value is a string.
    /// </summary>
    /// 
    /// <returns>
    /// The name of the subindex.
    /// </returns>
    /// <param name="prefix">The prefix for the subindex.</param><param name="index">The index value.</param>
    protected static string CreateSubIndexName(string prefix, string index);
    /// <summary>
    /// Creates the name of the subproperty by using the specified prefix and property name.
    /// </summary>
    /// 
    /// <returns>
    /// The name of the subproperty.
    /// </returns>
    /// <param name="prefix">The prefix for the subproperty.</param><param name="propertyName">The name of the property.</param>
    protected internal static string CreateSubPropertyName(string prefix, string propertyName);
    /// <summary>
    /// Returns a set of properties that match the property filter restrictions that are established by the specified <paramref name="binding context"/>.
    /// </summary>
    /// 
    /// <returns>
    /// An enumerable set of property descriptors.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
    protected IEnumerable<PropertyDescriptor> GetFilteredModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Returns the properties of the model by using the specified controller context and binding context.
    /// </summary>
    /// 
    /// <returns>
    /// A collection of property descriptors.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
    protected virtual PropertyDescriptorCollection GetModelProperties(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Returns the value of a property using the specified controller context, binding context, property descriptor, and property binder.
    /// </summary>
    /// 
    /// <returns>
    /// An object that represents the property value.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="propertyDescriptor">The descriptor for the property to access. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value.</param><param name="propertyBinder">An object that provides a way to bind the property.</param>
    protected virtual object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder);
    /// <summary>
    /// Returns the descriptor object for a type that is specified by its controller context and binding context.
    /// </summary>
    /// 
    /// <returns>
    /// A custom type descriptor object.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
    protected virtual ICustomTypeDescriptor GetTypeDescriptor(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Determines whether a data model is valid for the specified binding context.
    /// </summary>
    /// 
    /// <returns>
    /// true if the model is valid; otherwise, false.
    /// </returns>
    /// <param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext"/> parameter is null.</exception>
    protected static bool IsModelValid(ModelBindingContext bindingContext);
    /// <summary>
    /// Called when the model is updated.
    /// </summary>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
    protected virtual void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Called when the model is updating.
    /// </summary>
    /// 
    /// <returns>
    /// true if the model is updating; otherwise, false.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param>
    protected virtual bool OnModelUpdating(ControllerContext controllerContext, ModelBindingContext bindingContext);
    /// <summary>
    /// Called when the specified property is validated.
    /// </summary>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="propertyDescriptor">Describes a property to be validated. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value.</param><param name="value">The value to set for the property.</param>
    protected virtual void OnPropertyValidated(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value);
    /// <summary>
    /// Called when the specified property is validating.
    /// </summary>
    /// 
    /// <returns>
    /// true if the property is validating; otherwise, false.
    /// </returns>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="propertyDescriptor">Describes a property being validated. The descriptor provides information such as component type, property type, and property value. It also provides methods to get or set the property value.</param><param name="value">The value to set for the property.</param>
    protected virtual bool OnPropertyValidating(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value);
    /// <summary>
    /// Sets the specified property by using the specified controller context, binding context, and property value.
    /// </summary>
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><param name="propertyDescriptor">Describes a property to be set. The descriptor provides information such as the component type, property type, and property value. It also provides methods to get or set the property value.</param><param name="value">The value to set for the property.</param>
    protected virtual void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value);
    /// <summary>
    /// Gets or sets the model binders for the application.
    /// </summary>
    /// 
    /// <returns>
    /// The model binders for the application.
    /// </returns>
    protected internal ModelBinderDictionary Binders { get; set; }
    /// <summary>
    /// Gets or sets the name of the resource file (class key) that contains localized string values.
    /// </summary>
    /// 
    /// <returns>
    /// The name of the resource file (class key).
    /// </returns>
    public static string ResourceClassKey { get; set; }
  }

關於DefaultModelBinder的具體實現分析。 請參考http://www.cnblogs.com/artech/archive/2012/05/21/model-binder-provision.html

DefaultModelBinder繼承自IModelBinder. IModelBinder的接口

public interface IModelBinder {
        object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
    }

DefaultModelBinder繼承自IModelBinder同時DefaultModelBinder中有許多virtual方法我們可以直接實現IModelBinder或者DefaultModelBinder並重寫相應的虛方法實現這兩種方式自定義的ModelBinder。

 

 

3自定義ModelBinder

3.1.實現IModelBinder

 

Model

public class Settings
{
    public string ServerName { get; set; }
    public string Ip { get; set; }
    public string PortNumber { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public RequestInfo RequestInfo { get; set; }
}

public  class  RequestInfo
{
    public string Url { get; set; }
    public string ClientIP { get; set; }
}

Web.config

<appSettings>

    <add key="ServerName" value="Ruby"/>
    <add key="Ip" value="192.168.0.1"/>
    <add key="PortNumber" value="21"/>
    <add key="Username" value="admin"/>
    <add key="Password" value="password"/>
  </appSettings>

SettingsBinder

public class SettingsBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var request = controllerContext.HttpContext.Request;
        var setting = new Settings()
                          {
                              Ip = ConfigurationManager.AppSettings["Ip"],
                              ServerName = ConfigurationManager.AppSettings["ServerName"],
                              PortNumber = ConfigurationManager.AppSettings["PortNumber"],
                              Username = ConfigurationManager.AppSettings["Username"],
                              Password = ConfigurationManager.AppSettings["Password"],
                              RequestInfo = new RequestInfo()
                                                {
                                                    Url = request.Url.ToString(),
                                                    ClientIP = request.ServerVariables["REMOTE_ADDR"]
                                                }
                          };
        return setting;
    }
}

Controller

[HttpPost]
    public ActionResult Person2([ModelBinder(typeof(SettingsBinder))]Settings settings)
    {
    }

這時settings已經讀取了Web.config和Request的值。不必在Controller中賦值。這是一個較簡單的例子,實際應用當中往往還需要各種環境參數。BindModel方法的參數controllerContext和bindingContext已經包含了大多常用的上下文數據。如HttpContext,ControllerContext,ModelType,ModelMetadata等.

 

3.2 實現DefaultModelBinder

遇到稍微復雜的模型綁定,IModelBinder就顯得力不從心了。這時就需要更加強大的DefaultModelBinder來幫忙了。

需求:Trim模型中的字符串。上代碼

定義TrimAttribute

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class TrimAttribute : Attribute
{
    public TrimAttribute()
    {
    }

}

 

Model

[ModelBinder(typeof(StringTrimModelBinder))]
public class Person
{
    [Required]
    [Trim]
    public string ID { get; set; }
    public string Name { get; set; }
}

StringTrimModelBinder

public class StringTrimModelBinder : DefaultModelBinder
{
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        var obj = base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        if (obj is string
            && propertyDescriptor.Attributes[typeof(TrimAttribute)] != null)
        {
            return (obj as string).Trim();
        }
        return obj;
    }
}

StringTrimModelBinder繼承自DefaultModelBinder。。查看DefaultModelBinder的虛方法,發現正好有GetPropertyValue這個方法,斷重寫之。判斷是String且有[Trim]標記。

 

View

 

@using System.Web.Mvc.Html
@model Person

@{
    ViewBag.Title = "title";
}
@using (Html.BeginForm())
{
            <div>@Html.TextBoxFor(_ => _.ID)</div> 
        <div>@Html.TextBoxFor(_ => _.Name)</div> 
    <input type="submit" value="Submit" />
    @Html.ValidationSummary()
    }

運行效果

1

2

 Demo下載

參考:

http://www.cnblogs.com/artech/archive/2012/05/21/model-binder-provision.html

http://www.cnblogs.com/cjnmy36723/archive/2011/07/31/2122843.html

http://www.cnblogs.com/ldp615/archive/2010/07/30/sensitivewordsfiltermodelbinder.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM