1

I have a controller action Export which accepts a List of models like below. This is sending back and manipulated dataset back from the view where the user could interact with it. So we have been able to send the data down with much more information.

[HttpPost]
public JsonResult Export(List<MappingExportModel> sources){}

This works fine in all cases but there is one where we have a bigger than normal dataset. This is causing an issue with the export. So far I have tried just passing the values as an object or string but I am unable to convert them into any usable instance after the data is into the controller.

Is it possible to preemptively increase this maxjsonlength value somewhere. The value from the web.config is being ignored from what I have come across so far.

The error I receive is

"Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property"

I need to be able to accept this directly from the ajax request into the controller action. Spinning up a version of JsonResult and then setting the max value will not work because the error is thrown the the data is trying to be deserialized into the object var presented above. We get the value in the original GET request and do set the value before the view is loaded. Now we are taking the data from this view and sending it back plus all the manipulations the users have created.

User posts data to server, the controller action is hit with the data. The error is encountered and spit back out to the browser which handles the error.

TheHamstring
  • 712
  • 2
  • 6
  • 22
  • Possible duplicate of [Can I set an unlimited length for maxJsonLength in web.config?](https://stackoverflow.com/questions/1151987/can-i-set-an-unlimited-length-for-maxjsonlength-in-web-config) –  Jan 02 '18 at 18:32
  • @Amy It's not because the value set from the web.config is ignored when the user hits the controller as part of the request. – TheHamstring Jan 02 '18 at 18:35
  • What is the actual error you're getting? I'm getting the impression you have misidentified the issue. –  Jan 02 '18 at 19:08
  • My issue isn't with the web.config as the controller action being hit doesn't go through the controller so it does not take the value from the web.config. – TheHamstring Jan 02 '18 at 19:19
  • That isn't what I asked. What is the actual error you're getting? What do you mean it doesn't go through the controller? –  Jan 02 '18 at 19:22
  • I edited the issue with my response. – TheHamstring Jan 02 '18 at 19:26

1 Answers1

0

You can use custom json length. add the following file in your project and edit your global.asax.cs

Global.asax

  public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

          ///// **********
    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());
   /////*************

    }
}


///******** for json length
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;
    }
}

JsonValueProviderFactory.cs

public sealed class JsonValueProviderFactory : 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;
    }
}

by this you can pass lengthy json through ajax to controller and if you want to retrieve a lengthy string back to ajax result from controller then add below code in your controller also

//add this for getting large json string
    protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
    {
        return new JsonResult()
        {
            Data = data,
            ContentType = contentType,
            ContentEncoding = contentEncoding,
            JsonRequestBehavior = behavior,
            MaxJsonLength = Int32.MaxValue
        };
    }
user3501613
  • 596
  • 7
  • 28