首页 > 代码库 > 自定义模型绑定系统

自定义模型绑定系统

一 : 创建自定义的值提供器(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接口).然而三种方法都导致相同的结果,故使用何种技术并无多大关系.