C# 将JSON数据发布到ASP.NET MVC
我正在尝试使用JSON将行项目列表发送到网页,然后通过ajax请求使用到达的相同JSON结构将其操作并发送回服务器(除非更改了字段值) 从服务器接收数据很容易,操作更容易!但是将JSON数据发送回服务器保存。。。自杀时间!有人能帮忙吗 JavascriptC# 将JSON数据发布到ASP.NET MVC,c#,jquery,asp.net-mvc,ajax,json,C#,Jquery,Asp.net Mvc,Ajax,Json,我正在尝试使用JSON将行项目列表发送到网页,然后通过ajax请求使用到达的相同JSON结构将其操作并发送回服务器(除非更改了字段值) 从服务器接收数据很容易,操作更容易!但是将JSON数据发送回服务器保存。。。自杀时间!有人能帮忙吗 Javascript var lineitems; // get data from server $.ajax({ url: '/Controller/GetData/', success: function(data){ li
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" });
}
客户端
它使用json.org的stringify方法,在这个dependecy中可用(缩小时为2.5kb)
看看Phil Haack在上的帖子。问题是默认的模型绑定器没有正确序列化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();
此外,这段代码使用了content type='application/json',因此请确保在jquery中这样设置:
$.ajax({
dataType: "json",
contentType: "application/json",
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
在MVC3中,他们添加了这个 但更美妙的是,由于MVC源代码是开放的,您可以获取ValueProvider并在自己的代码中使用它(如果您还没有使用MVC3) 你最终会得到这样的结果
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory())
如果您将JSON数据作为字符串输入(例如,“[{“id”:1,“name”:“Charles”},{“id”:8,“name”:“John”},{“id”:13,“name”:“Sally”}]”) 然后我会使用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"
}
}
}
这是最简单的方法
我建议您阅读直接解决您问题的内容。
正如Phil Haack指出的那样,使用自定义模型绑定并不是真正明智的做法(他的博客文章也链接在上面的博客文章中)
基本上,您有三个选项:
JsonValueProviderFactory
并使用客户端库,如json2.js
与JSON直接通信JQueryValueProviderFactory
,了解在$.ajax
中发生的jQuery JSON对象转换,或者IList
和日期的数组,它们将在服务器端正确解析为DateTime
实例)Asp.net MVC默认模型绑定器将理解这一点[HttpPost]
[Route("Customer/{customerId:int}/Vehicle/{vehicleId:int}/Policy/Create"]
public async Task<JsonNetResult> Create(int customerId, int vehicleId, PolicyRequest policyRequest)
幸运的是,ValueProvider在使用此方法时已计算出路由值。您可以尝试这些。
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});
}
[HttpPost]
公共JsonResult操作(字符串数据){
string\u jsonObject=data.Replace(@“\”,string.Empty);
var serializer=new System.Web.Script.Serialization.JavaScriptSerializer();
Dictionary jsonObject=序列化程序。反序列化(_jsonObject);
返回Json(新对象{status=true});
}
我按照vestigal的提示解决了这个问题:
当我需要将大型json发布到控制器中的操作时,我会遇到著名的“使用json JavaScriptSerializer进行反序列化时出错。字符串长度超过maxJsonLength属性上设置的值。\r\n参数名称:输入值提供程序”
我所做的是创建一个新的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;
}
}
}
我使用“手动”反序列化解决了这个问题。
我会用代码解释的
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
}
public ActionResult MyMethod([System.Web.Http.FromBody]MyModel)
{
if(module.Fields==null&&!string.IsNullOrEmpty(Request.Form[“Fields”]))
{
model.Fields=JsonConvert.DeserializeObject(Request.Form[“Fields”]);
}
//…更多代码
}
我看到这里的每个人都“走了很长的路!”。只要你使用的是MVC
,我强烈建议你使用最简单的方法,那就是Newtonsoft.JSON
…如果你不想使用库,也可以查看下面的答案链接。我花了很长的时间为自己解决了这个问题,这些就是我找到的解决方案
首先实现Newtonsoft.Json:
using Newtonsoft.Json;
$.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" });
}
准备Ajax请求:
using Newtonsoft.Json;
$.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" });
}
然后进入结果类:
using Newtonsoft.Json;
$.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" });
}
public ActionResult SaveData(字符串传入,int documentId){
//作为模型数组反序列化到模型中
LineItem[]jsr=JsonConvert.DeserializeObject(临时);
foreach(jsr中的行项目){
//留点东西
}
返回Json(新的{success=true,message=“Some message”});
}
看到上面的诀窍了吗?我没有使用JsonResult
而是使用常规ActionResult
和包含json字符串的字符串。然后反序列化到我的模型中
,这样我就可以在我拥有的任何操作方法中使用它
此方法的优点是:
using Newtonsoft.Json;
$.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" });
}