首页 > 代码库 > 自定义模型绑定系统
自定义模型绑定系统
一 : 创建自定义的值提供器(IValueProvider接口定义了值提供器)==目的==>把"自己的数据源"添加到绑定过程中.
自定义值提供器就需要实现IValueProvider接口.
namespace System.Web.Mvc { /// <summary> /// Defines the methods that are required for a value provider in ASP.NET MVC. /// </summary> public interface IValueProvider { /// <summary> /// Determines whether the collection contains the specified prefix. /// </summary> /// <param name="prefix">The prefix to search for.</param> /// <returns>true if the collection contains the specified prefix; otherwise, false.</returns> bool ContainsPrefix(string prefix); /// <summary> /// Retrieves a value object using the specified key. /// </summary> /// <param name="key">The key of the value object to retrieve.</param> /// <returns>The value object for the specified key. If the exact key is not found, null.</returns> ValueProviderResult GetValue(string key); } }
ContainsPrefix 方法由模型绑定器调用,以确认这个值提供器是否可以解析给定前缀的数据.
GetValue方法返回给定数据键的值或在找不到合适的数据时,返回"null".
对名称为"CurrentTime"的属性绑定时间的一个值提供器.
public class CurrentTimeValueProvider:IValueProvider { public bool ContainsPrefix(string prefix) { return string.Compare("CurrentTime", prefix, true) == 0; } public ValueProviderResult GetValue(string key) { return ContainsPrefix(key) ? new ValueProviderResult(DateTime.Now, null, CultureInfo.InvariantCulture) : null; } }
我们已经定义自己的值提供机器,那么怎么把他叫MVC应用程序中??
==>第一步骤 :我需要创建一个工厂类,以便创建提供器的实例.而这个工程类派生于抽象类ValueProviderFactory.
下面是ValueProviderFactory类的代码:
namespace System.Web.Mvc { public abstract class ValueProviderFactory { public abstract IValueProvider GetValueProvider(ControllerContext controllerContext); } }
自定义的
public class CurrentTimeValueProviderFactory:ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { return new CurrentTimeValueProvider(); } }
当模型绑定器在绑定的过程中获取值,会调用GetValueProvider方法.
第二步骤: 在应用程序中注册这个工厂类.
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Insert(0, new CurrentTimeValueProviderFactory()); } }
如果需要希望自定义值提供器优先于内建提供器,就必须使用Insert方法把注册的工厂添加到集合的第一个位置.
如果希望提供器在其他提供器不能提供数据值时作为一个备选,那么可以使用Add方法把工厂追加到集合的末尾.
二.创建依赖性智能感知的模型绑定器
通过对DefaultModelBinder类进行派生,并重写CreateModel方法,以创建一个DI感知的绑定器.
public class DIModelBinder:DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) { //这个类使用了应用程序范围的依赖解析器来创建模型对象,并在必要的时候退回到基类实现 return DependencyResolver.Current.GetService(modelType)?? base.CreateModel(controllerContext, bindingContext, modelType); } }
我们必须把我们定义的模型绑定机器,注册为应用程序的默认模型绑定器
可以在Global.asax的Application_Start方法中进行注册:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { //把自定義的模型綁定器設置為應用程序的默認模型綁定器 ModelBinders.Binders.DefaultBinder = new DIModelBinder(); AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Insert(0, new CurrentTimeValueProviderFactory()); } }
三:创建自定义模型绑定器
通过创建一个特定类型的自定义模型绑定器,我们可以覆盖默认绑定器的行为.主要是实现IModelBinder接口
public class PersonModelBinder:IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { throw new NotImplementedException(); } }
把自定义模型绑定器注册到应用程序中有3中方法:
第一种方法是在ModelBinders.Binders.Add方法中直接指定模型类.
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { //把自定義的模型綁定器設置為應用程序的默認模型綁定器 ModelBinders.Binders.DefaultBinder = new DIModelBinder(); //為特定類型(Person類)指定一個模型綁定器 ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder()); AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Insert(0, new CurrentTimeValueProviderFactory()); } }
第二种是:通过实现IModelBinderProvider来创建一个模型绑定器的提供器.
public interface IModelBinderProvider { IModelBinder GetBinder(Type modelType); }
自定义的模型绑定提供器
public class CustomModelBinderProvider:IModelBinderProvider { public IModelBinder GetBinder(Type modelType) { return modelType == typeof(Person) ? new PersonModelBinder() : null; } }
注册自定义的模型绑定器提供器
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { //把自定義的模型綁定器設置為應用程序的默認模型綁定器 ModelBinders.Binders.DefaultBinder = new DIModelBinder(); //為特定類型(Person類)指定一個模型綁定器 ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder()); //註冊自定義模型綁定器的提供器 ModelBinderProviders.BinderProviders.Add(new CustomModelBinderProvider()); AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Insert(0, new CurrentTimeValueProviderFactory()); } }
第三种:把ModelBinder注解属性应用在模型类中.
//直接為模型類指定自定義的模型綁定器 [ModelBinder(typeof(PersonModelBinder))] public class Person { [HiddenInput(DisplayValue=false)] public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } [DataType(DataType.Date)] public DateTime BirthDate { get; set; } public Address HomeAddress { get; set; } }
给ModelBinder注解属性唯一的参数是:在绑定这种对象是应该使用的模型绑定器类型.
上面三种方法中,我倾向第二中方法(实现IModelBinderProvider接口).然而三种方法都导致相同的结果,故使用何种技术并无多大关系.