zoukankan      html  css  js  c++  java
  • 一起谈.NET技术,ASP.NET MVC中的Json Binding和Validate 狼人:

      电子商务网站支付功能页面往往会有很多信息,对于这些信息的保存,往往是分步完成的,那么使用Ajax最合适不过了,比如其中的收货人信息模块。这些信息的新建和编辑保存都是用Ajax来完成的。那么有几种方式完成这个操作呢,我想到如下几种。
      先来看看该功能的截图:

      一般情况下这些信息会对应一个实体类,就命名为:ReceiverInfo,简单起见,我定义ReceiverInfo如下:


      1、将需要的值拼接成json文本,再Action里面处理

      首先您需要将要保存的值拼接成一个json文本,类似:

    var test = "{ ReceiverId: 5, ReceiverName: 'will', Sex: 'F', CreateDate: '2011-02-21' }";

      然后用Jquery保存到数据库,代码如下:

    $.ajax({
    url:
    "/Home/test1",
    type:
    "post",
    cache:
    false,
    data: test
    });

      然后您在Action里面这样操作:

    StreamReader reader = new StreamReader(Request.InputStream);
    string bodyText
    = reader.ReadToEnd();
    JavaScriptSerializer js
    = new JavaScriptSerializer();
    ReceiverInfo receiver
    = js.Deserialize<ReceiverInfo>(bodyText);
    //保存。。。

      2、利用自定义的ModelBinder实现

    JsonBinder
    1 public class JsonBinder<T> : IModelBinder
    2 {
    3 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    4 {
    5 StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
    6 string json = reader.ReadToEnd();
    7
    8 if (string.IsNullOrEmpty(json))
    9 return json;
    10
    11 JavaScriptSerializer serializer = new JavaScriptSerializer();
    12 object jsonData = serializer.DeserializeObject(json);
    13 return serializer.Deserialize<T>(json);
    14 }
    15 }

      我们继承IModelBinder接口,实现其 方法:

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

      即可。我们可以在Action里面这样使用:

    public ActionResult Test1([ModelBinder(typeof(JsonBinder<ReceiverInfo>))] ReceiverInfo receiverInfo)

      这样我们自定义的 IModelBinder就会取代DefaultModelBinder完成数据绑定。
      3、直接传递一个Json对象

      上面两种方法并没有利用MVC的System.ComponentModel.DataAnnotations进行有效的数据验证。您可能需要自己手动验证,无疑增加了工作量。

      我们试试这种方式。

      前端的写法:

    1. var b = {
    2. ReceiverId: 5,
    3. ReceiverName: "will",
    4. Sex: "F",
    5. CreateDate: "2011-02-21"};$.ajax({
    6. url: "/Home/test1",
    7. type: "post",
    8. cache: false,
    9. data: b,
    10. success: function(data) { alert(data.message); },
    11. error: function(xhr, a, b) { alert
    12. (xhr.responseText); }});

      Action的写法:

    public ActionResult Test1(ReceiverInfo receiverInfo)

      我们能正常的得到绑定后的数据。而且我们还能利用System.ComponentModel.DataAnnotations进行数据验证。我们为ReceiverInfo做如下改动:

    [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "收货人必须填写")]
    public string ReceiverName { get; set; }

      并在前端为ReceiverName赋值为空字符串,再次执行,得到提示:

      很好,不过我们有新的要求了,那就是传递更复杂的对象,比如对象套嵌对象,对象有集合属性,这种方式不能胜任了。
      4、利用MvcFutures的JsonValueProviderFactory

      每一版的MVC都有一个MvcFutures,里面会有一些额外的功能,这些功能有些会加入下一个版本中,而这些功能在某些时候很有用处。我查看了里面的类,发现有一个类JsonValueProviderFactory正是处理复杂对象的提交和数据验证。

      由于json对象需要特定解析才能使用默认的DefaultModelBinder,而这个解析过程需要在ValueProvider阶段完成,所以需要实现特定的ValueProvider给DefaultModelBinder。我们需要实现一个ValueProviderFactory和IValueProvider,而MVC里面的DictionaryValueProvider<TValue>(继承了IValueProvider)已经足够使用了,所以只需要继承ValueProviderFactory实现其方法:public override IValueProvider GetValueProvider(ControllerContext controllerContext)即可,具体代码您可以看JsonValueProviderFactory。

      我们定义另一个类:

    ReceiverInfoChild
    public class ReceiverInfoChild
    {
    [System.ComponentModel.DataAnnotations.Required(ErrorMessage
    = "ChildId必须填写")]
    public string ChildId { get; set; }
    }

      并为类ReceiverInfo增加一个属性public List<ReceiverInfoChild> ReceiverInfoChild { get; set; }

      我们把JsonValueProviderFactory拿出来放在项目里面,然后在Global.asax里面注册一下,就可以使用了。

    1. protected void Application_Start(){
    2. AreaRegistration.RegisterAllAreas();
    3. RegisterRoutes(RouteTable.Routes);
    4. ValueProviderFactories.Factories.Add(new
    5. JsonValueProviderFactory());}

      因为JsonValueProviderFactory中有:if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))来判断进来的请求是不是json对象,所以我们提交数据的时候需要这样写:

    1. var ReceiverInfo = [
    2. {
    3. ReceiverInfoChild: [{ ChildId: "1" }, { ChildId: "11"}],
    4. ReceiverId: 5,
    5. ReceiverName: "will",
    6. Sex: "F",
    7. CreateDate: "2011-02-21"
    8. },
    9. {
    10. ReceiverInfoChild: [{ ChildId: "2" }, { ChildId: "22"}],
    11. ReceiverId: 5,
    12. ReceiverName: "will",
    13. Sex: "F",
    14. CreateDate: "2011-02-21" }
    15. ];$.ajax({
    16. url: "/Home/test1",
    17. type: "post",
    18. cache: false,
    19. contentType: "application/json;charset=utf-8",
    20. data: JSON.stringify(ReceiverInfo),
    21. success: function(data) { alert(data.message); },
    22. error: function(xhr, a, b) { alert(xhr.responseText); }});

      其中JSON.stringify(ReceiverInfo)是将json对象转换成字符串,您可以到这里下载该类库。

      在Action里面,我们这样写就可以了:

    public ActionResult Test1(List<ReceiverInfo> receiverInfo)

      看一下调试的结果:

      完全正常绑定了值。我们再看看数据验证:


      至此,我们实验了四种方案:

      第一种方案,最麻烦,而且容易出错(可能跟我个人不喜欢拼接字符串有关系);

      第二种方案,有一定的通用性,但是不利于数据验证;

      第三种方案,通用,可以进行有效的数据验证,应对一般的需求够用了,但是处理更复杂的对象不行;

      第四种方案,几乎可以处理我们遇到的所有情况

      另外,这是在ASP.NET MVC2中的使用,到了ASP.NET MVC3,微软已经把JsonValueProviderFactory作为内置的功能了。

  • 相关阅读:
    单例模式
    HashSet、LinkedHashSet、SortedSet、TreeSet
    ArrayList、LinkedList、CopyOnWriteArrayList
    HashMap、Hashtable、LinkedHashMap
    andrew ng machine learning week8 非监督学习
    andrew ng machine learning week7 支持向量机
    andrew ng machine learning week6 机器学习算法理论
    andrew ng machine learning week5 神经网络
    andrew ng machine learning week4 神经网络
    vue组件监听属性变化watch方法报[Vue warn]: Method "watch" has type "object" in the component definition. Did you reference the function correctly?
  • 原文地址:https://www.cnblogs.com/waw/p/2162942.html
Copyright © 2011-2022 走看看