在.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<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> 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<ExpandoObject>(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<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(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<JsonValueProviderFactory>().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来反序列化。

示例程序下载

在MVC中使用Json.Net序列化和反序列化Json对象的更多相关文章

  1. ASP.NET MVC 网站开发总结(六)——简谈Json的序列化与反序列化

    首先,先简单的谈一下什么是序列化与反序列化,序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通 ...

  2. 在C#中,Json的序列化和反序列化的几种方式总结

    在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据,以及如何反序列化Json数据到对象. 什么是JSON? JSON (JavaScript Object Notation) ...

  3. C#中的Json的序列化和反序列化

    Json是一种通用的数据格式,我们在数据交换的时候,经常会用到,下面介绍c#中的json序列化和反序列化,当然也可用在asp.net,silverlight,wpf中.我们在下面实例讲解如何进行Jso ...

  4. Asp.net中Json的序列化和反序列化(一)

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  5. ASP.NET中JSON的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍 ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介 ...

  6. ASP.NET 中JSON 的序列化和反序列化

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  7. 在C#中,Json的序列化和反序列化的几种方式总结 转载

    转载自  https://www.cnblogs.com/caofangsheng/p/5687994.html    谢谢 在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据 ...

  8. ASP.NET中JSON的序列化和反序列化(转)

    JSON是专门为浏览器中的网页上运行的JavaScript代码而设计的一种数据格式.在网站应用中使用JSON的场景越来越多,本文介绍ASP.NET中JSON的序列化和反序列化,主要对JSON的简单介绍 ...

  9. C#中,Json的序列化和反序列化的几种方式总结

    在这篇文章中,我们将会学到如何使用C#,来序列化对象成为Json格式的数据,以及如何反序列化Json数据到对象. 什么是JSON? JSON (JavaScript Object Notation) ...

随机推荐

  1. Android发送短信

    // 发送短信 public void sendMsg(){ String content = edtSend.getText().toString(); SmsManager smsManager ...

  2. 深度技术32位Win7系统Ghost版2014年

    深度技术32位Win7系统Ghost版,GhostWin7是指使用Ghost软件做成压缩包的Windows7,俗称克隆版Win7.用克隆版的目的是节省安装时间.本作品在采用微软封装部署技术的基础上,结 ...

  3. object references an unsaved transient instance - save the transient instance before flushing错误

    异常1:not-null property references a null or transient value解决方法:将“一对多”关系中的“一”方,not-null设置为false(参考资料: ...

  4. 51Node 1065----最小正子段和

    51Node  1065----最小正子段和 N个整数组成的序列a[1],a[2],a[3],…,a[n],从中选出一个子序列(a[i],a[i+1],…a[j]),使这个子序列的和>0,并且这 ...

  5. 更新整理本人所有博文中提供的代码与工具(C++,2013.10)

    为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载. C++ 1.<通用高性能 Windows Socket 组件 HP-Soc ...

  6. Guacamole之配置Guacamole(五)

    摘要 在网上看到一篇Guacamole官方手册的翻译,但是找不到后续,于是想自己也翻译几篇,有时间的话,会尽量多翻译一些. 原文地址:http://guacamole.incubator.apache ...

  7. Croppic – 免费开源的 jQuery 图片裁剪插件

    Croppic 这款开源的 jQuery 图片裁剪插件能够满足网站开发人员各种不同的使用需要.只需要简单的上传图片,就可以实现你想要的图像缩放和裁剪功能.因为使用了 HTML5 FormData  对 ...

  8. Sublime Text 3汉化中文版

    Sublime Text 3汉化中文版是Sublime Text2的升级版.Sublime Text 是一款流行的文本编辑器软件,有点类似于TextMate,跨平台,可运行在Linux,Windows ...

  9. sharepoint2010问卷调查(1)-实现问卷的图片调查(采用JS实现)

      1. 首先建立个图片库上传图片 2. 采用:评估范围(一系列选项或 Likert 范围)制作,如下图: http://win-i07fillcfom:8003/DocLib2/1.jpg http ...

  10. SharePoint Online 创建门户网站系列之图片滚动

    前 言 创建SharePoint Online栏目我们之前已经介绍过了,具体就是内容编辑器方式.自带WebPart方式和JavaScript读取后台数据前台做展示的三种: 但是,对于复杂的展示来说,这 ...