我正在尝试使用JSON获取网页的订单项列表,然后将使用到达的相同JSON结构(通过更改字段值除外)通过ajax请求对其进行处理并发送回服务器。
从服务器接收数据很容易,甚至更容易操作!但是将JSON数据发送回服务器以节省...自杀时间!请有人帮忙!
Java脚本
var lineitems;
// get data from server
$.ajax({
url: '/Controller/GetData/',
success: function(data){
lineitems = data;
}
});
// post data to server
$.ajax({
url: '/Controller/SaveData/',
data: { incoming: lineitems }
});
C#-对象
public class LineItem{
public string reference;
public int quantity;
public decimal amount;
}
C#-控制器
public JsonResult GetData()
{
IEnumerable<LineItem> lineItems = ... ; // a whole bunch of line items
return Json(lineItems);
}
public JsonResult SaveData(IEnumerable<LineItem> incoming){
foreach(LineItem item in incoming){
// save some stuff
}
return Json(new { success = true, message = "Some message" });
}
数据作为序列化过帐数据到达服务器。自动模型绑定器尝试进行绑定,IEnumerable<LineItem> incoming
并令人惊讶地得到结果IEnumerable
具有正确的数量LineItems
-它只是不使用数据填充它们。
解
我使用了很多资料来源的答案,主要是djch
在另一个stackoverflow帖子及其后的帖子BeRecursive
中,我使用两种主要方法解决了我的问题。
服务器端
以下解串器需要参考System.Runtime.Serialization
和using System.Runtime.Serialization.Json
private T Deserialise<T>(string json)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var serialiser = new DataContractJsonSerializer(typeof(T));
return (T)serialiser.ReadObject(ms);
}
}
public void Action(int id, string items){
IEnumerable<LineItem> lineitems = Deserialise<IEnumerable<LineItem>>(items);
// do whatever needs to be done - create, update, delete etc.
}
客户端
它使用json.org的stringify方法,该方法可在此https://github.com/douglascrockford/JSON-js/blob/master/json2.js中使用(最小时为2.5kb)
$.ajax({
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
看一下Phil Haack关于模型绑定JSON数据的文章。问题是默认模型联编程序无法正确序列化JSON。您需要某种ValueProvider或可以编写自定义模型绑定程序:
using System.IO;
using System.Web.Script.Serialization;
public class JsonModelBinder : DefaultModelBinder {
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
if(!IsJSONRequest(controllerContext)) {
return base.BindModel(controllerContext, bindingContext);
}
// Get the JSON data that's been posted
var request = controllerContext.HttpContext.Request;
//in some setups there is something that already reads the input stream if content type = 'application/json', so seek to the begining
request.InputStream.Seek(0, SeekOrigin.Begin);
var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();
// Use the built-in serializer to do the work for us
return new JavaScriptSerializer()
.Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
// -- REQUIRES .NET4
// If you want to use the .NET4 version of this, change the target framework and uncomment the line below
// and comment out the above return statement
//return new JavaScriptSerializer().Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
}
private static bool IsJSONRequest(ControllerContext controllerContext) {
var contentType = controllerContext.HttpContext.Request.ContentType;
return contentType.Contains("application/json");
}
}
public static class JavaScriptSerializerExt {
public static object Deserialize(this JavaScriptSerializer serializer, string input, Type objType) {
var deserializerMethod = serializer.GetType().GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static);
// internal static method to do the work for us
//Deserialize(this, input, null, this.RecursionLimit);
return deserializerMethod.Invoke(serializer,
new object[] { serializer, input, objType, serializer.RecursionLimit });
}
}
并告诉MVC在您的Global.asax文件中使用它:
ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
另外,此代码利用了内容类型='application / json',因此请确保您在jquery中进行设置,如下所示:
$.ajax({
dataType: "json",
contentType: "application/json",
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
最简单的方法
我敦促您阅读这篇博客文章,直接解决您的问题。
正如Phil Haack指出的那样,使用自定义模型活页夹并不明智(他的博客文章也链接在上层博客文章中)。
基本上,您有三个选择:
-
编写
JsonValueProviderFactory
并使用客户端库,例如json2.js
直接与JSON进行通信。 -
编写一个
JQueryValueProviderFactory
,了解发生在$.ajax
或中的jQuery JSON对象转换 -
使用非常简单快捷的jQuery的博客文章插件概括,即准备任何JSON对象(甚至阵列将被绑定到
IList<T>
和日期,将在服务器端的正确分析DateTime
,将通过Asp.net MVC默认情况下可以理解实例)模型活页夹。
在这三者中,最后一个是最简单的,并且不会干扰Asp.net MVC内部工作,因此降低了可能的错误表面。使用博客文章中概述的这种技术将正确地将数据绑定到您的强类型操作参数并对其进行验证。因此,这基本上是双赢的局面。
他们在MVC3中添加了此功能。
但是,更妙的是,由于MVC源代码是开放的,因此您可以获取ValueProvider并在自己的代码中使用它(如果您尚未在MVC3上使用)。
你最终会得到这样的东西
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory())
您可以尝试这些。1.在通过ajax调用服务器操作之前,先对JSON对象进行字符串化。2.在操作中反序列化字符串,然后将数据用作字典。
下面的Javascript示例(发送JSON对象
$.ajax(
{
type: 'POST',
url: 'TheAction',
data: { 'data': JSON.stringify(theJSONObject)
}
})
下面的操作(C#)示例
[HttpPost]
public JsonResult TheAction(string data) {
string _jsonObject = data.Replace(@"\", string.Empty);
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
Dictionary<string, string> jsonObject = serializer.Deserialize<Dictionary<string, string>>(_jsonObject);
return Json(new object{status = true});
}
我按照这里的残余提示解决了这个问题:
我可以在web.config中为maxJsonLength设置无限长度吗?
当我需要将大型json发布到控制器中的操作时,我将得到著名的“使用JSON JavaScriptSerializer进行反序列化期间的错误。字符串的长度超过了在maxJsonLength属性上设置的值。\ r \ n参数名称:input价值提供者”。
我所做的是创建一个新的ValueProviderFactory,LargeJsonValueProviderFactory,并在GetDeserializedObject方法中设置MaxJsonLength = Int32.MaxValue。
public sealed class LargeJsonValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(LargeJsonValueProviderFactory.EntryLimitedDictionary backingStore, string prefix, object value)
{
IDictionary<string, object> dictionary = value as IDictionary<string, object>;
if (dictionary != null)
{
foreach (KeyValuePair<string, object> keyValuePair in (IEnumerable<KeyValuePair<string, object>>) dictionary)
LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
}
else
{
IList list = value as IList;
if (list != null)
{
for (int index = 0; index < list.Count; ++index)
LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakeArrayKey(prefix, index), list[index]);
}
else
backingStore.Add(prefix, value);
}
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return (object) null;
string end = new StreamReader(controllerContext.HttpContext.Request.InputStream).ReadToEnd();
if (string.IsNullOrEmpty(end))
return (object) null;
var serializer = new JavaScriptSerializer {MaxJsonLength = Int32.MaxValue};
return serializer.DeserializeObject(end);
}
/// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
/// <returns>A JSON value-provider object for the specified controller context.</returns>
/// <param name="controllerContext">The controller context.</param>
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
object deserializedObject = LargeJsonValueProviderFactory.GetDeserializedObject(controllerContext);
if (deserializedObject == null)
return (IValueProvider) null;
Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
LargeJsonValueProviderFactory.AddToBackingStore(new LargeJsonValueProviderFactory.EntryLimitedDictionary((IDictionary<string, object>) dictionary), string.Empty, deserializedObject);
return (IValueProvider) new DictionaryValueProvider<object>((IDictionary<string, object>) dictionary, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString((IFormatProvider) CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
if (!string.IsNullOrEmpty(prefix))
return prefix + "." + propertyName;
return propertyName;
}
private class EntryLimitedDictionary
{
private static int _maximumDepth = LargeJsonValueProviderFactory.EntryLimitedDictionary.GetMaximumDepth();
private readonly IDictionary<string, object> _innerDictionary;
private int _itemCount;
public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
{
this._innerDictionary = innerDictionary;
}
public void Add(string key, object value)
{
if (++this._itemCount > LargeJsonValueProviderFactory.EntryLimitedDictionary._maximumDepth)
throw new InvalidOperationException("JsonValueProviderFactory_RequestTooLarge");
this._innerDictionary.Add(key, value);
}
private static int GetMaximumDepth()
{
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
int result;
if (values != null && values.Length > 0 && int.TryParse(values[0], out result))
return result;
}
return 1000;
}
}
}
然后,在Global.asax.cs的Application_Start方法中,将ValueProviderFactory替换为新的:
protected void Application_Start()
{
...
//Add LargeJsonValueProviderFactory
ValueProviderFactory jsonFactory = null;
foreach (var factory in ValueProviderFactories.Factories)
{
if (factory.GetType().FullName == "System.Web.Mvc.JsonValueProviderFactory")
{
jsonFactory = factory;
break;
}
}
if (jsonFactory != null)
{
ValueProviderFactories.Factories.Remove(jsonFactory);
}
var largeJsonValueProviderFactory = new LargeJsonValueProviderFactory();
ValueProviderFactories.Factories.Add(largeJsonValueProviderFactory);
}
如果您有其他以字符串形式输入的JSON数据(例如'[{“ id”:1,“ name”:“ Charles”},{“ id”:8,“ name”:“ John”},{ “ id”:13,“ name”:“ Sally”}]')
然后我将使用JSON.net并使用Linq到JSON来获取值...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Request["items"] != null)
{
var items = Request["items"].ToString(); // Get the JSON string
JArray o = JArray.Parse(items); // It is an array so parse into a JArray
var a = o.SelectToken("[0].name").ToString(); // Get the name value of the 1st object in the array
// a == "Charles"
}
}
}
BeRecursive的答案是我使用的答案,因此我们可以在Json.Net上进行标准化(我们拥有MVC5和WebApi 5-WebApi 5已经使用Json.Net),但是我发现了一个问题。当您在要发布的路由中具有参数时,MVC会尝试为URI值调用模型绑定程序,并且此代码将尝试将发布的JSON绑定到这些值。
例:
[HttpPost]
[Route("Customer/{customerId:int}/Vehicle/{vehicleId:int}/Policy/Create"]
public async Task<JsonNetResult> Create(int customerId, int vehicleId, PolicyRequest policyRequest)
该BindModel
函数被调用三次,第一次轰炸,因为它试图将JSON绑定到customerId
错误:Error reading integer. Unexpected token: StartObject. Path '', line 1, position 1.
我将此代码块添加到的顶部BindModel
:
if (bindingContext.ValueProvider.GetValue(bindingContext.ModelName) != null) {
return base.BindModel(controllerContext, bindingContext);
}
幸运的是,ValueProvider具有在到达此方法时确定的路由值。
我使用“手动”反序列化解决了。我会用代码解释
public ActionResult MyMethod([System.Web.Http.FromBody] MyModel model)
{
if (module.Fields == null && !string.IsNullOrEmpty(Request.Form["fields"]))
{
model.Fields = JsonConvert.DeserializeObject<MyFieldModel[]>(Request.Form["fields"]);
}
//... more code
}
我看到这里的每个人都“走了很长的路!” 。只要您正在使用MVC
,我强烈建议您使用最简单的方法Newtonsoft.JSON
...。如果您不想使用库,请查看下面的答案链接。为此,我花了很多时间研究自己的问题,这些是我找到的解决方案。
首先实现Newtonsoft.Json:
using Newtonsoft.Json;
准备您的Ajax请求:
$.ajax({
dataType: "json",
contentType: "application/json",
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
然后进入结果类:
public ActionResult SaveData(string incoming, int documentId){
// DeSerialize into your Model as your Model Array
LineItem[] jsr = JsonConvert.DeserializeObject<LineItem[]>(Temp);
foreach(LineItem item in jsr){
// save some stuff
}
return Json(new { success = true, message = "Some message" });
}
看到那里的把戏吗?JsonResult
我没有使用常规ActionResult
,而是使用包含json字符串的常规字符串。然后反序列化到我的Model
这样我就可以在我拥有的任何操作方法中使用它。
这种方法的优点是:
- 更容易在动作之间传递
- 更少,更清晰的代码用法,
- 无需更改模型,
- 简单实施
JSON.stringify(Model)
- 仅传递字符串
这种方法的缺点是:
- 仅传递字符串
- 反序列化过程
还要检查这些确实有用的问题和答案:
https://stackoverflow.com/a/45682516/861019
另一种方法:
https://stackoverflow.com/a/31656160/861019
和另一种方法:
文章标签:ajax , asp.net-mvc , c# , jquery , json
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!
评论已关闭!