Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Monday, December 19, 2011 10:54 AM
I have an MVC 3 web site that i am building that needs to be able to handle a large amount of JSON data submitted to a controller's action via HTTP POST. I currently get the following error in the event log:
Exception information:
Exception type: ArgumentException
Exception message: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
I have this in my web.config:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483647"/>
</webServices>
</scripting>
</system.web.extensions>
I have seen several articles on implementing a custom JsonResult object. However, I am recieving JSON data, not returning JSON data (weill, I am actually, just not large amounts)
How can I increase this limit for recieving a JSON POST?
Thanks.
All replies (3)
Monday, December 19, 2011 11:11 AM ✅Answered
the MVC json serializer does not look at the webconfig to get the max length (thats for asp.net web services). you need to use your own serializer. you override ExecuteResult and supply you own json serializer. to override the input, create a new JsonValueProviderFactory, then override ValueProvider in the controller to return your new json factory when its a json request.
Monday, December 19, 2011 11:55 AM ✅Answered
Ok, thank you, Bruce for the explanation. I got this working. I figured I would share the solution for anyone else running into this.
First you must build a custom JsonValueProviderFactory. To do this I downloaded the MVC 3 source code and found the JsonValueProviderFactory.cs. Using this class as a template I created a CustomJsonValueProviderFactory. Here is the source. I only added one line of code to GetDeserializedObject. It is commented.
public sealed class CustomJsonValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = int.MaxValue; //increase MaxJsonLength. This could be read in from the web.config if you prefer
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
}
With that in place I modified the Global.asax.cs Application_Start method as such:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
//find the default JsonVAlueProviderFactory
JsonValueProviderFactory jsonValueProviderFactory = null;
foreach (var factory in ValueProviderFactories.Factories)
{
if (factory is JsonValueProviderFactory)
{
jsonValueProviderFactory = factory as JsonValueProviderFactory;
}
}
//remove the default JsonVAlueProviderFactory
if (jsonValueProviderFactory != null) ValueProviderFactories.Factories.Remove(jsonValueProviderFactory);
//add the custom one
ValueProviderFactories.Factories.Add(new CustomJsonValueProviderFactory());
}
That's all it took. Such a simple fix seems like it should have been handled in the base framework.
Hope this helps someone down the road.
Thursday, July 19, 2012 5:21 PM
I had the same exact problem in MVC3 and .NET 4.0. I was excited to find this post, but it didn't work. I implemented the custom class and put the stuff in global.asax.cs. No dice -- same error.
Any other ideas on this?