一尘不染

将JSON数据发布到ASP.NET MVC

c#

我试图使用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.Serializationusing 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 }
});

阅读 207

收藏
2020-05-19

共1个答案

一尘不染

看一下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 }
});
2020-05-19