MVC系统学习3—ModelBinder

      在ASP.NET MVC中,每个请求都被映射到一个Action方法,我们可以在action的方法中定义相应类型的参数,View中通过post、get方式提交的request参数,只要名称一致就会对应到相应的action参数,一切似乎理所当然,但是请注意我们的http是基于文本协议的,提交上去的参数应该是被认为是字符串形式,但是我们可以在action中定义string类型之外的其他参数,如int,datetime。在提交到action进行请求的过程里肯定有一个转换。

      MVC框架里实现这个转换的就是DefaultModelBinder,DefaultModelBinder实现了IModelBinder接口,该接口的代码如下:

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

     DefaultModelBinder能实现如下类型的转换:

      如果研究MVC的源码我们可以发现, 调用action最终是由ControllerActionInvoker类的InvokeAction方法实现,这个方法里首先会获取调用action所需要的参数,即GetParametersValues方法。这个方法会有一个IModelBinder的选择过程和原则:

  • 尝试从附加在参数的CustomModelBinderAttribute特性获取
  • 尝试从ModelBinders.Binders集合中按参数类型检索
  • 尝试从附加在参数的类型的CustomModelBinderAttribute特性获取
  • 使用ModelBinders.Binders.DefaultBinder

     如果DefaultModelBinder不能实现我们所需要的转换功能,则我们可以自己定义实现IModelBinder接口的ModelBinder。这种情况现在暂时还没碰到过,通过老赵的一片博客的例子来联系,例如当我们从客户端接口一个可以转换成datetime的类型时,我们希望可以自动转换成某种形式的DateTime。

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
1 public class DateTimeModelBinder : IModelBinder
2 {
3 public string Format { get ; private set ; }
4
5 public DateTimeModelBinder( string format)
6 {
7 this .Format = format;
8 }
9
10 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
11 {
12 object value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).RawValue;
13 if (value is string )
14 {
15 return DateTime.ParseExact(( string )value, this .Format, null );
16 }
17 else
18 {
19 return value;
20 }
21 }
22 }

      定义好了ModelBinder,怎么让框架能够使用它,上面讲到了框架中IModelBinder的选择过程和原则。因此我们可以有这么几种实现方法:

      1.利用CustomerModelBinderAttribute,写一个类来实现它的GetBinder方法。

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
1 public class DateTimeAttribute : CustomModelBinderAttribute
2 {
3 public string Format { get ; private set ; }
4
5 public DateTimeAttribute( string format)
6 {
7 this .Format = format;
8 }
9
10 public override IModelBinder GetBinder()
11 {
12 return new DateTimeModelBinder( this .Format);
13 }
14
15 }
   public ActionResult Test([DateTime("yyyy-MM-dd")]DateTime date)

       2.通过在全局文件中想ModelBinders集合添加我们自定义的ModelBinder

MvcAppDemo.Models.DateTimeModelBinder dateTimeBinder = new Models.DateTimeModelBinder("yyyy-MM-dd");
            ModelBinders.Binders.Add(typeof(DateTime), dateTimeBinder);
 public ActionResult Test(DateTime date)

        3.通过向我们参数的类型添加CustomerModelBinderAttribute来实现,但是这里DateTime是基本类型,这里通过另外一个例子来实现。蛋疼下,自己定义一个实体,然后实现这个实体的转换。

Blog实体:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
1 [BlogBinder]
2 public class Blog
3 {
4 public string Title { get ; set ; }
5 public string Content { get ; set ; }
6 public string Author { get ; set ; }
7 public DateTime PostDate { get ; set ; }
8 }

自定义的ModelBinder:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
public class BlogBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
object model = Activator.CreateInstance(bindingContext.ModelType);
PropertyDescriptorCollection col
= TypeDescriptor.GetProperties(model);
foreach (PropertyDescriptor item in col)
{
string value = bindingContext.ValueProvider.GetValue(item.Name).AttemptedValue;
item.SetValue(model, Convert.ChangeType(value,item.PropertyType));
}
return model;
}
}
实现CustomerModelAttribute:

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
public class BlogBinderAttribute : CustomModelBinderAttribute
{
public override IModelBinder GetBinder()
{
return new BlogBinder();
}
}

     其实实现自定义ModelBinder的思路很简单,就是通过反射获取我们的绑定类型的各个成员,接下来以各个成员的名称为键到bindingContext中去找值,接下来进行类型转换,然后再赋值给我们的模型。这个实现的过程中有碰到两个问题

     1.类型转换,如果我不适用Convert.ChangeType(object value,Type convertType),而是使用TypeConvert.ConvertTo(object value,destinationType),在转换DateTime类型时会出错?这时为什么?

     2.在使用反射进行转换的时候可以利用TypeDescriptor.GetProperties(model)和PropertyDescriptor,自己使用Type和PropertyInfo也同样可以使用,在MVC里面很多地方使用了TypeDescriptor,或者可以见到以Descriptor为后缀的类。TypeDescriptor和Type有什么区别?


转载于:https://www.cnblogs.com/wuxiaoqian726/articles/2000642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值