将 JSON 数据发布到 ASP.NET MVC [英] Posting JSON Data to ASP.NET MVC
问题描述
我正在尝试使用 JSON 将订单项列表获取到网页,然后将使用到达的相同 JSON 结构(除非更改了字段值)由 ajax 请求操作并发送回服务器.
Im trying to get a list of line items to a webpage using JSON, which will then be manipulated and sent back to the server by ajax request using the same JSON structure that arrived (except having had a field values changed).
从服务器接收数据很容易,操作更容易!但是将 JSON 数据发送回服务器以节省……自杀时间!请有人帮忙!
Receiving data from the server is easy, manipulation even easier! but sending that JSON data back to the server for saving... suicide time! PLEASE can someone help!
Javascript
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
并令人惊讶地得到结果 IEnumerable
具有正确数量的 LineItems
- 它只是没有用数据填充它们.
The data arrives at the server as serialized post data. The automated model binder tries to bind IEnumerable<LineItem> incoming
and surprisingly gets the resulting IEnumerable
has the correct number of LineItems
- it just doesnt populate them with data.
解决方案
使用来自多个来源的答案,主要是另一个 stackoverflow 帖子上的 djch
和下面的 BeRecursive
,我使用两种主要方法解决了我的问题.
Using answers from a number of sources, primarily djch
on another stackoverflow post and BeRecursive
below, I solved my problem using two main methods.
服务器端
下面的反序列化器需要参考System.Runtime.Serialization
和using System.Runtime.Serialization.Json
The deserialiser below requires reference to System.Runtime.Serialization
and 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)
It uses json.org's stringify method, available in this dependecy https://github.com/douglascrockford/JSON-js/blob/master/json2.js (which is 2.5kb when minified)
$.ajax({
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
推荐答案
看看 Phil Haack 在 模型绑定 JSON 数据.问题是默认模型绑定器没有正确序列化 JSON.您需要某种 ValueProvider 或者您可以编写自定义模型绑定器:
Take a look at Phil Haack's post on model binding JSON data. The problem is that the default model binder doesn't serialize JSON properly. You need some sort of ValueProvider OR you could write a custom model binder:
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 文件中使用它:
And tell MVC to use it in your Global.asax file:
ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
另外,这段代码使用了 content type = 'application/json' 所以确保你在 jquery 中像这样设置:
Also, this code makes use of the content type = 'application/json' so make sure you set that in jquery like so:
$.ajax({
dataType: "json",
contentType: "application/json",
type: 'POST',
url: '/Controller/Action',
data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});
这篇关于将 JSON 数据发布到 ASP.NET MVC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!