.NET JSON.decode()对于大型数组失败

问题描述 投票:1回答:2

MVC 4 ASP.NET Web API应用程序:

我有一个形式的JSON数组:

var json = "{
    'mapset':
    [
        {
            'id': '1',
            'key': 'key1',
            'value': 'value1',
            'timestamp': '2014-02-12T08:50:54.594Z'
        },
        {
            'id': '2',
            'key': 'key2',
            'value': 'value2',
            'timestamp': '2014-02-12T08:50:54.594Z'
        },
    ]
}";

dynamic data = System.Web.Helpers.JSON.decode(json);

对于每个大约1K字节的10K元素的数组,JSON.Decode()就像一个魅力。

对于100K元素失败并出现错误:

System.ArgumentException:使用JSON JavaScriptSerializer进行序列化或反序列化时出错。字符串的长度超过maxJsonLength属性上设置的值。参数名称:在System.Web.Helpers处的System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer序列化程序,字符串输入,类型类型,Int32 depthLimit)处输入。 Json.Decode(字符串值)

如何设置更高的限制?

我知道关于这个主题的另一篇文章:

Can I set an unlimited length for maxJsonLength in web.config?

但是那里提供的答案并没有解决我的具体问题。

我在MVC4应用程序中直接使用JSON.Decode(),因此修改web.config设置将不适用。并且JSON.Decode()将JSON字符串的反序列化执行到.NET JSON对象(而不是将.NET JSON对象序列化为JSON字符串)。

javascript .net arrays json serialization
2个回答
0
投票

System.Web.Script.Serialization.JavaScriptSerializer为我做了诀窍。

我认为这很难看,但是使用JavaScriptSerializer,我可以将maxJsonLength设置为一个很大的值:

JavaScriptSerializer ser = new JavaScriptSerializer();
ser.MaxJsonLength = Int32.MaxValue; // <-- should probably not use that huge value
var jsonArtikel = ser.Serialize(Model);

0
投票

Michael Witty的This blog article展示了如何解决这个问题。基本上,虽然不可能直接覆盖MaxJsonLength使用的基础JavaScriptSerializerSystem.Web.Helpers.Json.Decode,但是可以很容易地用几行复制System.Web.Helpers.Json.Decode并且通过控制最大长度。

以下是经过测试和运行的DynamicJsonObjectFormatter。它有一个静态方法dynamic DynamicJsonObjectFormatter.Decode(string json)复制System.Web.Helpers.Json.Decode,但让你控制最大长度:

public class DynamicJsonObjectFormatter : BufferedMediaTypeFormatter
{
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public static dynamic Decode(string json, int maxLength=0)
    {
        try
        {
            if (string.IsNullOrEmpty(json))
                return null;
            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            if( maxLength>0) {
                serializer.MaxJsonLength = maxLength;
            }
            var deserialized = serializer.DeserializeObject(json);
            if (deserialized != null)
            {
                var dictValues = deserialized as IDictionary<string, object>;
                if (dictValues != null)
                    return new DynamicJsonObject(dictValues);
                var arrayValues = deserialized as object[];
                if (arrayValues != null)
                {
                    return new DynamicJsonArray(arrayValues);
                }
            }
            log.Error("Internal: Attempt to deserialize unrecognized JSON string as DynamicJsonObject");
        }
        catch (Exception ex)
        {
            log.Error("Internal: exception deserializing JSON", ex);
        }
        return null;
    }
    override public object ReadFromStream(Type type, System.IO.Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
    {
        System.IO.StreamReader strdr = null;
        try
        {
            strdr = new System.IO.StreamReader(readStream);
            string json = strdr.ReadToEnd();
            int maxLength = 33554432; //Int32.MaxValue;
            return Decode(json, maxLength);
        }
        catch (Exception ex)
        {
            log.Error("Internal: exception deserializing JSON", ex);
        }
        finally
        {
            if (strdr != null)
            {
                strdr.Dispose();
            }
        }
        return null;
    }

    public DynamicJsonObjectFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/json"));
        //SupportedEncodings.Add(new UTF8Encoding(false, true));
    }

    public override bool CanReadType(Type type)
    {
        return (type == typeof(DynamicJsonObject)) || (type == typeof(DynamicJsonArray));
    }

    public override bool CanWriteType(Type type)
    {
        return false;
    }

}

(注意:strdr.ReadToEnd()也可能会给你一个大文件的问题。它的大小限制可以用

<system.web>
    <httpRuntime targetFramework="4.6.2" maxRequestLength="200000" />
    <!-- maxRequestLength is in KB, not B -->
</system.web>

在您的Web.config文件中。见this article。)


推荐问答