将 JSON 数据发布到 ASP.NET MVC [英] Posting JSON Data to ASP.NET MVC

查看:27
本文介绍了将 JSON 数据发布到 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.Serializationusing 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆