MVC框架中的值提供(一)

在MVC框架中action方法中的Model数据的绑定的来源有很多个,可能是http请求中的get参数或是post提交的表单数据,会是json字符串或是路径中的相关数据;MVC框架中针对这些不同的数据来源抽象了IValueProvider接口;

   public interface IValueProvider
   {
       bool ContainsPrefix(string prefix);
      ValueProviderResult GetValue(string key);
   }
  IValueProvider接口中的ContainsPrefix方法返回是否包含指定的前缀,GetValue方法时根据指定的key来获取相应的值数据结果;NameValueCollection
   NameValueCollection类时key和value都是字符串的字典,与Dictionary类型不同的是,一个key是可以对应多个值;
   NameValueCollection collection = new NameValueCollection();
   collection.Add("a", "aa");
   collection.Add("a", "bb");
   collection.Add("a", "cc");
   collection.Add("b", "aa");
   string[] rawValue = collection.GetValues("a");
   string attemptedValue = collection["a"];
   Console.WriteLine(attemptedValue);   // aa,bb,cc
   Console.WriteLine(rawValue);   // [aa,bb,cc]
   GetValues方法返回自定key的value的数组,attemptedValue 为指定key的value的字符串表示(项之间用,链接);

ValueProviderResult    ValueProviderResult类是存储Model数据的数据来源的值信息;msdn是这样描述的”表示将一个值(如窗体发布或查询字符串中的值)绑定到操作方法参数属性或绑定到该参数本身的结果“
  名称 说明
AttemptedValue 获取或设置要转换为字符串,以便显示的原始值。
Culture 获取或设置区域性。
RawValue 获取或设置值提供程序所提供的原始值。

在ValueProviderResult 类中含有一个ConvertTo(Type)方法,这个方法的目的是结果封装的值转换为指定的类型。在方法内部中将ValueProviderResult 类的RawValue转化为type类型的值数据。

ConvertTo(Type)方法内部实际上是调用的UnwrapPossibleArrayType 方法中的object value参数为RawValue,具体的处理逻辑如下:

1.当value值为空或是当前对象value是当前类的实例(当前类可以是value 的类、父类、接口),直接返回value值;

2.当Type的类型是数组类型时,首先会根据destinationType.GetElementType来获取数组元素的类型

2.1 当value值能够转化为Array 数组时,然后根据转换Array 数组的长度和数组元素的类型通过Array.CreateInstance方法创建一个类型数组,最后逐个遍历转化数组的元素调用内部的ConvertSimpleType方法转换;

2.2当value值不能够转化为Array数组时,type为数组类型时,首先调用内部ConvertSimpleType的方法获取到转换的值,然后创建一个长度为1的数组,将转换后的值写入到数组中。

3.当Type类型不是数组类型时,并且Value的类型为数组类型时

3.1当Value的类型为数组长度大于0时,获取到数组中的第一个元素值,调用内部ConvertSimpleType的方法获取到转换的值

3.2当Value的类型为数组长度为0时,直接返回null值;

4.当以上情况都不满足时,直接调用内部ConvertSimpleType的方法获取到转换的值

 private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType)
 {
      if (value == null || destinationType.IsInstanceOfType(value))
      {
         return value;
      }
      Array valueAsArray = value as Array;
      if (destinationType.IsArray)
      {
         Type destinationElementType = destinationType.GetElementType();
         if (valueAsArray != null)
         {
             IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);
             for (int i = 0; i < valueAsArray.Length; i++)
             {
                 converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);
             }
             return converted;
         }
         else
         {
             object element = ConvertSimpleType(culture, value, destinationElementType);
             IList converted = Array.CreateInstance(destinationElementType, 1);
             converted[0] = element;
             return converted;
         }
      }
      else if (valueAsArray != null)
      {
         if (valueAsArray.Length > 0)
         {
            value = valueAsArray.GetValue(0);
            return ConvertSimpleType(culture, value, destinationType);
         }
         else
         {
            return null;
         }
       }
     return ConvertSimpleType(culture, value, destinationType);
 }

在UnwrapPossibleArrayType 方法中经常会调用ConvertSimpleType方法,从字面意思上理解这个方法是进行简单类型的数组转换;

1.当value值为空或是当前对象value是当前类的实例(当前类可以是value 的类、父类、接口),直接返回value值;

2.当value值转换为字符串后为空字符串时直接返回null

3.通过Nullable.GetUnderlyingType方法获取type是否是可空的值类型,如果是可空的值类型,则返回基础的值类型,当value值不是字符串类型时,value是否继承了IConvertible 接口,如果是,直接调用IConvertible 接口的ToType方法.

4.当以上情况都不满足时,就会通过 TypeDescriptor.GetConverter类获取参数Type的类型转换器,获取到转换器后调用CanConvertFrom方法来获取value的type是否支持这个类型转换器,当不支持转换后,会获取value值的type类型的类型转换器;

4.1如果不支持转换并且类型转换器不能转换到type,这时候就会throw 一个InvalidOperationException异常,不过一种情况除外,当类是枚举类型时,由于EnumConverter不能转换整数,所以我们手动转化,因此会调用Enum.ToObject方法;

4.2如果类型转换器支持转换的话,就直接调用转换器的ConvertFrom的方法,否则调用ConvertTo方法来获取转化的值

private static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType)
{
      if (value == null || destinationType.IsInstanceOfType(value))
      {
         return value;
      }
      string valueAsString = value as string;
      if (valueAsString != null && String.IsNullOrWhiteSpace(valueAsString))
      {
         return null;
      }
             Type underlyingType = Nullable.GetUnderlyingType(destinationType);
      if (underlyingType != null)
      {
         destinationType = underlyingType;
      }
      if (valueAsString == null)
      {
         IConvertible convertible = value as IConvertible;
         if (convertible != null)
         {
            try
            {
              return convertible.ToType(destinationType, culture);
            }
             catch
             {
             }
          }
     }
      TypeConverter converter = TypeDescriptor.GetConverter(destinationType);
      bool canConvertFrom = converter.CanConvertFrom(value.GetType());
      if (!canConvertFrom)
      {
         converter = TypeDescriptor.GetConverter(value.GetType());
      }
      if (!(canConvertFrom || converter.CanConvertTo(destinationType)))
      {

         if (destinationType.IsEnum && value is int)
         {
           return Enum.ToObject(destinationType, (int)value);
         }

         string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ValueProviderResult_NoConverterExists,
                                               value.GetType().FullName, destinationType.FullName);
         throw new InvalidOperationException(message);
       }

        try
        {
            object convertedValue = (canConvertFrom)
                                            ? converter.ConvertFrom(null /* context */, culture, value)
                                            : converter.ConvertTo(null /* context */, culture, value, destinationType);
             return convertedValue;
        }
        catch (Exception ex)
        {
            string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ValueProviderResult_ConversionThrew,
                                               value.GetType().FullName, destinationType.FullName);
                throw new InvalidOperationException(message, ex);
        }
   }
时间: 2024-11-23 08:18:15

MVC框架中的值提供(一)的相关文章

MVC框架中的值提供机制(二)

在MVC框架中存在一些默认的值提供程序模板,这些值提供程序都是通过工厂模式类创建;在MVC框架中存在需要已Factory结尾的工厂类,在值提供程序中也存在ValueProviderFactories工厂类,这个类管理着许多的值提供的工厂; public static class ValueProviderFactories { private static readonly ValueProviderFactoryCollection _factories = new ValueProvider

mvc action 参数绑定——值提供器【学习笔记】

每次http请求的各种数据(表单数据.url的数据.路由数据等等)都保存在不同的IValueProvider接口的实现类中. 而IValueProvider接口的实现类是通过ValueProviderFactory创建的. 在mvc中原生的ValueProviderFactory有六种: ChildActionValueProviderFactory:根据给定的Controller上下文创建一个ChildActionValueProvider对象. FormValueProviderFactor

2014-07-30 MVC框架中对SQL Server数据库的访问

今天是在吾索实习的第16天.我自己主要学习了基于MVC框架的系统的开发时,对SQL Server数据库的相关访问.其步骤如下: 第一步,在Models文件夹中创建一个类,并命名为Movies.cs,如图1所示: 图1 第二步,在上述Movies.cs文件中的namespace MvcTest.Models{}中输入如下代码: 1 public class Movie 2 { 3 public int ID { get; set; } 4 public string Title { get; se

2014-07-29 浅谈MVC框架中Razor与ASPX视图引擎

今天是在吾索实习的第15天.随着准备工作的完善,我们小组将逐步开始手机端BBS的开发,而且我们将计划使用MVC框架进行该系统的开发.虽然我们对MVC框架并不是非常熟悉,或许这会降低我们开发该系统的效率,但是我们可以通过边学边做的方式来实现其开发的.这不仅便于我们日后对系统的管理与维护,而且还给我们带来一个学习的动力与实践的地方. 但我们在创建一个基于MVC框架的项目时,就遇到一些问题了.那就是MVC的视图引擎是有两种的,一种是Razor,会以cshtml后缀的文件作为视图文件:另一种是ASPX,

找到MVC框架中前端URL与后端同步的解决方案

基本思路: 先用URL标签生成完整的URL字符,前端动态参数的部分以适配符先填充,最后动态参数利用正则匹配进行替换. 这种方式,可以在各种MVC框架中适用,妙. 不废话,上码. var url = "{url app=xxxxn&act=yyy&id=[0]}"; url = url.format({$id}); //String.format 同时匹配[](){}内容方式 if (!String.prototype.format) { String.prototype

spring mvc框架中引入handlebars插件

本篇介绍引入spring mvc框架中引入handlebars.js插件最基本步骤 1.下载handlebars.js插件,并添加到项目中 2.下载handlebars依赖的jar包,添加到工程 红框中的是handlebars核心包,其他是handlebars依赖的工具包 3.在spring mvc配置文件springMvc-servlet.xml中添加handlebars视图解析器配置 1 <!-- VIEW RESOLVER --> 2 <bean id="handleba

asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析

下面我用一个实例来和大家分享一下我的经验,asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析. using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Web.Mvc; namespace MyWebApp.Controllers { public class TestController : Controller { public A

详述 Spring MVC 框架中拦截器 Interceptor 的使用方法

1 前言 昨天新接了一个需要,"拦截 XXX,然后 OOO",好吧,说白了就是要用拦截器干点事(实现一个具体的功能).之前,也在网络上搜了很多关于Interceptor的文章,但感觉内容都大同小异,而且知识点零零散散,不太方便阅读.因此,正好借此机会,整理一篇关于拦截器的文章,在此分享给大家,以供大家参考阅读. 2 拦截器 2.1 概念 Java 里的拦截器是动态拦截 action 调用的对象.它提供了一种机制可以使开发者可以定义在一个 action 执行的前后执行的代码,也可以在一个

命令模式在MVC框架中的应用

命令模式: 定义:把一个请求或者操作封装在命令对象中.命令模式同意系统使用不同的请求把client參数化,对请求排队或者记录请求日志,能够提供命令的撤销和恢复功能. Invoker类 被client调用,能够接受命令请求.设计命令队列.决定是否对应该请求,记录或撤销或重做命令请求.记录日志等等. [java] view plaincopy public class Invoker { private Command command; public void setOrder(Command co