博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在MVC中使用Json.Net序列化和反序列化Json对象
阅读量:5926 次
发布时间:2019-06-19

本文共 8820 字,大约阅读时间需要 29 分钟。

在.Net的MVC开发中,经常会使用到Json对象,于是,系统提供了JsonResult这个对象,其本质是调用.Net系统自带的Json序列化类JavaScriptSerializer对数据对象进行序列化。但是这个系统自带的Json序列化对象方法没有Json.Net好用,于是打算有些时候用Json.Net替代默认的实现。

要实现有时候用Json.Net,有时候用默认实现,那么就要保证系统中两种实现并存。对于Server将对象序列化成Json传给Client很简单,我们只需要建立一个新的ActionResult,我们命名为JsonNetResult,然后在Get时,return这个JsonNetResult即可。JsonNetResult的代码实现为:

using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace MvcJsonNet{ using System.IO; using System.Web; using System.Web.Mvc; using Newtonsoft.Json; public class JsonNetResult : JsonResult { public JsonNetResult() { Settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Error }; } public JsonNetResult(object data, JsonRequestBehavior behavior = JsonRequestBehavior.AllowGet, string contentType=null, Encoding contentEncoding=null) { this.Data = data; this.JsonRequestBehavior = behavior; this.ContentEncoding = contentEncoding; this.ContentType = contentType; } public JsonSerializerSettings Settings { get; private set; } public override void ExecuteResult(ControllerContext context) {  if (context == null) throw new ArgumentNullException("context"); if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("JSON GET is not allowed"); HttpResponseBase response = context.HttpContext.Response; response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType; if (this.ContentEncoding != null) response.ContentEncoding = this.ContentEncoding; if (this.Data == null) return; var scriptSerializer = JsonSerializer.Create(this.Settings); using (var sw = new StringWriter()) { scriptSerializer.Serialize(sw, this.Data); response.Write(sw.ToString()); } } }}

要返回一个Json.Net序号列后的对象,那么调用方法是:

[HttpGet]public ActionResult GetJsonNet(){ var myClass = InitClass(); return new JsonNetResult(myClass);}

这是Get方法,但是对于ClientPost一个Json回Server,那么就比较麻烦了,需要修改好几处地方:

1,建立Json.Net的ValueProviderFactory,这个类主要就是用于Json字符串的反序列化。

using System;using System.Collections.Generic;using System.Linq;using System.Web;namespace MvcJsonNet{ using System.Collections; using System.Dynamic; using System.Globalization; using System.IO; using System.Web.Mvc; using System.Web.Script.Serialization; using Newtonsoft.Json; public class JsonNetValueProviderFactory : ValueProviderFactory { private void AddToBackingStore(Dictionary
backingStore, string prefix, object value) { IDictionary
d = value as IDictionary
; if (d != null) { foreach (KeyValuePair
entry in d) { AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value); } return; } IList l = value as IList; if (l != null) { for (int i = 0; i < l.Count; i++) { AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]); } return; } // primitive backingStore[prefix] = value; } private object GetDeserializedObject(ControllerContext controllerContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.InvariantCultureIgnoreCase)) { // not JSON request return null; } StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream); string bodyText = reader.ReadToEnd(); if (String.IsNullOrEmpty(bodyText)) { // no JSON data return null; } //接下来的代码是关键,判断content type,如果是json.net,那么就使用Json.Net的反序列化方法,如果不是,那么就使用系统默认的反序列化方法 if (controllerContext.HttpContext.Request.ContentType.StartsWith("application/json.net", StringComparison.InvariantCultureIgnoreCase)) { var jsonData = JsonConvert.DeserializeObject
(bodyText); return jsonData; } else { JavaScriptSerializer serializer = new JavaScriptSerializer(); object jsonData = serializer.DeserializeObject(bodyText); return jsonData; } } public override IValueProvider GetValueProvider(ControllerContext controllerContext) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } object jsonData = GetDeserializedObject(controllerContext); if (jsonData == null) { return null; } Dictionary
backingStore = new Dictionary
(StringComparer.OrdinalIgnoreCase); AddToBackingStore(backingStore, String.Empty, jsonData); return new DictionaryValueProvider
(backingStore, CultureInfo.CurrentCulture); } private string MakeArrayKey(string prefix, int index) { return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]"; } private string MakePropertyKey(string prefix, string propertyName) { return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName; } }}

2,在初始化MVC时替换掉默认的JsonValueProviderFactory。

在Global.asax的Application_Start时,写入以下代码:

ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType
().FirstOrDefault());ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());

3,建立新的ModelBinder,命名为JsonNetModelBinder。

namespace MvcJsonNet{ using System; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Web.Mvc; using Newtonsoft.Json; public class JsonNetModelBinder : DefaultModelBinder { protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) { Debug.WriteLine("BindProperty"); if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json.net", StringComparison .InvariantCultureIgnoreCase)) { //根据Content type来判断,只有json.net这种content type的才会使用该ModelBinder,否则使用默认的Binder base.BindProperty(controllerContext, bindingContext, propertyDescriptor); return; } // need to skip properties that aren't part of the request, else we might hit a StackOverflowException string name = propertyDescriptor.Name; foreach (object attribute in propertyDescriptor.Attributes) { if (attribute is JsonPropertyAttribute) { var jp = attribute as JsonPropertyAttribute; name = jp.PropertyName; } } string fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName, name); if (!bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey)) { return; } // call into the property's model binder IModelBinder propertyBinder = Binders.GetBinder(propertyDescriptor.PropertyType); object originalPropertyValue = propertyDescriptor.GetValue(bindingContext.Model); ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name]; propertyMetadata.Model = originalPropertyValue; var innerBindingContext = new ModelBindingContext { ModelMetadata = propertyMetadata, ModelName = fullPropertyKey, ModelState = bindingContext.ModelState, ValueProvider = bindingContext.ValueProvider }; object newPropertyValue = GetPropertyValue(controllerContext, innerBindingContext, propertyDescriptor, propertyBinder); propertyMetadata.Model = newPropertyValue; // validation ModelState modelState = bindingContext.ModelState[fullPropertyKey]; if (modelState == null || modelState.Errors.Count == 0) { if (OnPropertyValidating(controllerContext, bindingContext, propertyDescriptor, newPropertyValue)) { SetProperty(controllerContext, bindingContext, propertyDescriptor, newPropertyValue); OnPropertyValidated(controllerContext, bindingContext, propertyDescriptor, newPropertyValue); } } else { SetProperty(controllerContext, bindingContext, propertyDescriptor, newPropertyValue); // Convert FormatExceptions (type conversion failures) into InvalidValue messages foreach ( ModelError error in modelState.Errors.Where(err => String.IsNullOrEmpty(err.ErrorMessage) && err.Exception != null) .ToList()) { for (Exception exception = error.Exception; exception != null; exception = exception.InnerException) { if (exception is FormatException) { string displayName = propertyMetadata.GetDisplayName(); string errorMessageTemplate = "The value '{0}' is not valid for {1}."; string errorMessage = String.Format(CultureInfo.CurrentCulture, errorMessageTemplate, modelState.Value.AttemptedValue, displayName); modelState.Errors.Remove(error); modelState.Errors.Add(errorMessage); break; } } } } } }}

4,建立一个VModel的基类,为该基类添加Attribute,然后在Global中添加Model和Binder的映射。

[ModelBinder(typeof (JsonNetModelBinder))]public abstract class VEntity{ public virtual long Id { get; set; }}

Global.asax中Application_Start添加代码:

ModelBinders.Binders.Add(typeof(VEntity), new JsonNetModelBinder());

5在前端Post Json时,指定content type为application/json.net

function PostJsonNet() { var jsonstr = $("#jsonstring")[0].innerHTML; $.ajax({ url: "MyTest/CreateFromJsonNet", type: "POST", data: jsonstr, contentType: "application/json.net", dataType: "json", success: function (data) { alert(data);  } }); }

我们这样处理后,Client在往Server传送Json数据时,如果指定了contentType是application/json,那么就使用系统默认的方法来反序列化对象,如果是application/json.net,那么就使用Json.Net来反序列化。

转载地址:http://dqovx.baihongyu.com/

你可能感兴趣的文章
javascript中查看元素事件函数的一些技巧(转)
查看>>
1、Python初识
查看>>
php 禁止屏蔽类
查看>>
maven 使用记录
查看>>
一项回顾性研究提示TNF拮抗剂增加感染住院风险
查看>>
前后端分离djangorestframework——分页组件
查看>>
love
查看>>
docker 13 dockerfile的保留字指令
查看>>
configurationmanager.getsection usage
查看>>
About configuration center of Apollo
查看>>
pycharm使用技巧 + 调试程序-12
查看>>
Oracle学习指南
查看>>
Gym 101775J Straight Master(差分数组)题解
查看>>
FJUT3701 这也是一道数论题(线段树)题解
查看>>
使用两个队列实现一个栈
查看>>
jQuery+php+mysql,轻松实现ajax无刷新省市二级联动
查看>>
简单考试系统(只包含单选,多选)的实现
查看>>
自动修改电脑IP地址.bat
查看>>
UITableView 自定义多选
查看>>
Tapable.plugin is deprecated. Use new API on `.hooks` instead
查看>>