• 一起谈.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作为内置的功能了。

  • 相关阅读:
    软件工程第一次结对作业
    软件工程第二次作业
    vue之vuex
    ceshi
    第3次 结构与部分
    第二次作业
    获得领跑衫感言
    期末总结
    第十四,十五周作业
    第七周作业
  • 原文地址:https://www.cnblogs.com/waw/p/2162942.html
Copyright © 2020-2023  润新知