JSON object does not serialize for huge data - c#

I am trying to serialize data in JSON. But i face below exception.
OutOfMemoryException was unhandled by user code.
An exception of type 'System.OutOfMemoryException' occurred in Newtonsoft.Json.dll but was not handled in user code
Below i defined my code:
Main controller:
public class TrackingController : BaseAngularController
{
var lstDetails = _services.GetTrackingDetailsByAWBIds(awbids, awbType);
if (lstDetails != null)
{
return AngularJson(lstDetails);
}
}
Base Controller:
public abstract class BaseAngularController : Controller
{
public AngularJsonResult<T> AngularJson<T>(T model)
{
return new AngularJsonResult<T>() { Data = model };
}
}
Angular JSON Result class:
public class AngularJsonResult<T> :AngularJsonResult
{
public new T Data
{
get { return (T)base.Data; }
set { base.Data = value; }
}
}
JSON Result class:
public class AngularJsonResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
DoUninterestingBaseClassStuff(context);
SerializeData(context.HttpContext.Response);
}
private void DoUninterestingBaseClassStuff(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(ContentType) ? "application/json" : ContentType;
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
}
protected virtual void SerializeData(HttpResponseBase response)
{
if (ErrorMessages.Any())
{
Data = new
{
ErrorMessage = string.Join("\n", ErrorMessages),
ErrorMessages = ErrorMessages.ToArray()
};
response.StatusCode = 400;
}
if (Data == null) return;
response.Write(Data.ToJson());
}
}
Serializing Object to JSON:
public static class JsonExtensions
{
public static string ToJson<T>(this T obj, bool includeNull = true)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new JsonConverter[] { new StringEnumConverter() },
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore,//newly added
//PreserveReferencesHandling =Newtonsoft.Json.PreserveReferencesHandling.Objects,
NullValueHandling = includeNull ? NullValueHandling.Include : NullValueHandling.Ignore
};
return JsonConvert.SerializeObject(obj, settings);
}
}
Here i defined AngularJson method for passing object and override ExecuteResult method for converting Object to JSON.
So my SerializeData method was passing Response and converting to Objet in JSON, like Data.ToJson()
Please let me know your suggestions.

Your problem is that you are serializing your huge data to a string in memory on the server, then writing the entire string to the HttpResponseBase (which also buffers everything by default), and running out of memory somewhere in the process, possibly by exceeding the maximum c# string length.
One way to reduce memory use is to serialize directly to HttpResponseBase.OutputStream using JsonSerializer.Serialize(). This avoids the intermediate string representation.
You may also need to set HttpResponseBase.Buffer = false, and if so, follow the advice given in Unbuffered Output Very Slow and wrap the output stream in a BufferedStream.
The following extension method can be used for this:
public static class HttpResponseBaseExtensions
{
public static void WriteJson<T>(this HttpResponseBase response, T obj, bool useResponseBuffering = true, bool includeNull = true)
{
var contentEncoding = response.ContentEncoding ?? Encoding.UTF8;
if (!useResponseBuffering)
{
response.Buffer = false;
// use a BufferedStream as suggested in //https://stackoverflow.com/questions/26010915/unbuffered-output-very-slow
var bufferedStream = new BufferedStream(response.OutputStream, 256 * 1024);
bufferedStream.WriteJson(obj, contentEncoding, includeNull);
bufferedStream.Flush();
}
else
{
response.OutputStream.WriteJson(obj, contentEncoding, includeNull);
}
}
static void WriteJson<T>(this Stream stream, T obj, Encoding contentEncoding, bool includeNull)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new JsonConverter[] { new StringEnumConverter() },
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore,//newly added
//PreserveReferencesHandling =Newtonsoft.Json.PreserveReferencesHandling.Objects,
NullValueHandling = includeNull ? NullValueHandling.Include : NullValueHandling.Ignore
};
var serializer = JsonSerializer.CreateDefault(settings);
var textWriter = new StreamWriter(stream, contentEncoding);
serializer.Serialize(textWriter, obj);
textWriter.Flush();
}
}
Then use the extension method in place of response.Write(Data.ToJson());

Related

Why serialization object to JSON with type info works wrong?

I works on the saving system of my game and ran into a problem:
When I deserialize JSON, types of objects in dynamic array just disappear (I use Newtonsoft.Json).
Here is how I'm make a save file:
SaveFile SF = new SaveFile(_Map, _Character);
string json = JsonConvert.SerializeObject(SF, new JsonSerializerSettings() {
TypeNameHandling = TypeNameHandling.All
});
Properties.Settings.Default._Save = json;
Properties.Settings.Default.Save();
Loading it:
string saveSTR = Properties.Settings.Default._Save;
SaveFile save = JsonConvert.DeserializeObject<SaveFile>(saveSTR);
if (!saveSTR.Equals(JsonConvert.SerializeObject(new SaveFile(_Map, _Character), new JsonSerializerSettings() {TypeNameHandling = TypeNameHandling.All}))) {
MessageBoxResult res = MessageBox.Show("Не сохранённый прогресс будет утерян, вы уверены что хотите продолжить?", "", MessageBoxButton.YesNo, MessageBoxImage.None, MessageBoxResult.No);
if (res == MessageBoxResult.Yes) NavigationService.Navigate(new Game(save._Character, save._Map));
return;
}
NavigationService.Navigate(new Game(save._Character, save._Map));
And here is classes:
public class SaveFile {
public Character _Character;
public Map _Map;
public SaveFile(Map _Map, Character _Character) {
this._Map = _Map;
this._Character = _Character;
}
}
public class Room {
public dynamic[,] Content;
//...
}
public class Map {
public Room[,] Rooms;
//...
}
In JSON types exist:
But not when it deserialized:
Can it happens because of Room.Content type is dynamic? How can I fix it?
Here is my project. Saving into the Game.xaml.cs, classes into MainWindow.xaml.cs

RestSharp can't deserialize int body value

I have a service that returns an integer value like this example:
Now, I´m trying to consume this service using Restsharp, like this:
public static Task<T> ExecuteRequestAsync<T>(RestClient restClient, RestRequest request) where T : new()
{
var taskCompletionSource = new TaskCompletionSource<T>();
restClient.ExecuteAsync<T>(request, response =>
{
if (response.IsSuccessful())
taskCompletionSource.SetResult(response.Data);
else
taskCompletionSource.SetException(HandleResponseError(response));
});
return taskCompletionSource.Task;
}
private async Task<int> example() {
//Get a new RestClient
var restClient = new RestsharpManager.Builder()
.WithAuthenticator(new RequestsAuthenticator())
.Build();
//Parameters
var request = new RestRequest
{
Method = Method.GET,
Resource = "integration/install/size"
};
//Add parameters
request.AddParameter("productID", productID);
request.AddParameter("integrationID", integrationID);
request.AddParameter("currentVersion", currentVersion);
//Execute
return await ExecuteRequestAsync<int>(restClient, request);
}
And as a result, we get the following error:
What are we missing? Another response types, like Poco classes, are deserialized correctly. Look that the 'content' attribute, shown in the 2nd image contains the correct value that should be displayed.
I know that I can manually parse it, but I'd like to know why restClient.ExecuteAsync<T> isn't returning the desired value.
I found what was causing the issue...
The 'Json Deserializer' that comes with the Restsharp isn't able to automatically deserialize this.
Implementing a 'Custom Deserializer' that is based on Newtonsoft.Json library solved the problem.
Bellow is the Custom Serializer/Deserializer and the way to use it:
public class NewtonsoftJsonSerializer : ISerializer, IDeserializer
{
private readonly JsonSerializer _serializer;
public NewtonsoftJsonSerializer(JsonSerializer serializer)
{
_serializer = serializer;
}
public static NewtonsoftJsonSerializer Default => new NewtonsoftJsonSerializer(new JsonSerializer
{
NullValueHandling = NullValueHandling.Ignore
});
public T Deserialize<T>(IRestResponse response)
{
var content = response.Content;
using (var stringReader = new StringReader(content))
{
using (var jsonTextReader = new JsonTextReader(stringReader))
{
return _serializer.Deserialize<T>(jsonTextReader);
}
}
}
public string DateFormat { get; set; }
public string Namespace { get; set; }
public string RootElement { get; set; }
string ISerializer.ContentType
{
get { return "application/json"; }
set { }
}
public string Serialize(object obj)
{
using (var stringWriter = new StringWriter())
{
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
_serializer.Serialize(jsonTextWriter, obj);
return stringWriter.ToString();
}
}
}
}
To use it to 'Serialize' your object, configure the Request as below:
var request = new RestRequest
{
Method = Method.GET,
RequestFormat = DataFormat.Json,
JsonSerializer = NewtonsoftJsonSerializer.Default, //<= HERE!!!
Resource = "integration/install/size"
};
And also, register it to be the 'Default' JSON Deserializer:
//Creates the RestClient...
var restClient = new RestClient
{
BaseUrl = new Uri(_baseUrl),
Authenticator = _authenticator
};
//Defines the jsonSerializer that will handle the responses
var jsonSerializer = NewtonsoftJsonSerializer.Default;
restClient.AddHandler("application/json", jsonSerializer);
restClient.AddHandler("text/json", jsonSerializer);
restClient.AddHandler("text/x-json", jsonSerializer);
restClient.AddHandler("text/javascript", jsonSerializer);
restClient.AddHandler("*+json", jsonSerializer);

My custom date format is not formatting date with newton soft json in mvc

I am trying to display date in dd-MM-yyyy but the date i am getting is always in this format:
2016-08-08T16:17:40.643
I am using asp.net mvc and returning data in json format but displaying this date with angular js.
Here is the answer i am trying from the Link and i have combined the answer given by Perishable Dave and dav_i:
public class JsonNetFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is JsonResult == false)
{
return;
}
filterContext.Result = new JsonNetResult(
(JsonResult)filterContext.Result);
}
private class JsonNetResult : JsonResult
{
private const string _dateFormat = "dd-MM-yyyy";
public JsonNetResult(JsonResult jsonResult)
{
this.ContentEncoding = jsonResult.ContentEncoding;
this.ContentType = jsonResult.ContentType;
this.Data = jsonResult.Data;
this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
this.MaxJsonLength = jsonResult.MaxJsonLength;
this.RecursionLimit = jsonResult.RecursionLimit;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
var isMethodGet = string.Equals(
context.HttpContext.Request.HttpMethod,
"GET",
StringComparison.OrdinalIgnoreCase);
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& isMethodGet)
{
throw new InvalidOperationException(
"GET not allowed! Change JsonRequestBehavior to AllowGet.");
}
var response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(this.ContentType)
? "application/json"
: this.ContentType;
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
// Using Json.NET serializer
var isoConvert = new IsoDateTimeConverter();
isoConvert.DateTimeFormat = _dateFormat;
response.Write(JsonConvert.SerializeObject(this.Data));
}
}
}
}
[JsonNetFilter]
public ActionResult GetJson()
{
return Json(new { hello = new Date(2016-08-02 05:49:11.000) }, JsonRequestBehavior.AllowGet)
}
How to date in dd-MM-yyyy format??
You're not passing your isoConvert variable to JsonConvert.SerializeObject(this.Data), so it's never used. You need to pass it to SerializeObject using an appropriate overload:
response.Write(JsonConvert.SerializeObject(this.Data, new [] { isoConvert } ));

How to serialize ANY object into a string?

I'm running into an issue where my JSON serializer is failing randomly due to the character < showing up from time to time. I can't nail down where this is coming from and I want to - on exception - reserialize using a different method so I can see a full representation of the offending object. Is there any way to do this?
My current code:
// data is of type 'object'
serialized = JsonConvert.SerializeObject(data, new JsonSerializerSettings() {
Error = delegate(object sender, ErrorEventArgs args) {
// reserialize here and output object so I know what the heck is going on
}
})
There is no foolproof way to serialize any and every possible c# object.
Instead, you have a few ways to attack your problem:
Turn on Json.NET tracing. See Debugging with Serialization Tracing. This should tell you where in your object graph the problem is occurring.
Rather than serializing with JsonConvert.SerializeObject(), if you serialize with JsonSerializer.Serialize() and write to a string using a JsonTextWriter wrapping a StringWriter, you can flush the writer and log the partial serialization. That may give some idea where the problem arises.
You can try serializing using various other serializers, and if any work, log the result.
If one of your object properties is throwing an exception, you might try to force serialization of fields instead. See JSON.Net: Force serialization of all private fields and all fields in sub-classes.
For instance, putting #1, #2 and #3 together gives the following method:
public static class JsonSerializerExtensions
{
public static string SerializeObject(object obj, JsonSerializerSettings settings = null)
{
settings = settings ?? new JsonSerializerSettings();
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var jsonWriter = new JsonTextWriter(writer))
{
var oldError = settings.Error;
var oldTraceWriter = settings.TraceWriter;
var oldFormatting = settings.Formatting;
try
{
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
if (settings.TraceWriter == null)
settings.TraceWriter = new MemoryTraceWriter();
settings.Error = oldError + delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
jsonWriter.Flush();
var logSb = new StringBuilder();
logSb.AppendLine("Serialization error: ");
logSb.Append("Path: ").Append(args.ErrorContext.Path).AppendLine();
logSb.Append("Member: ").Append(args.ErrorContext.Member).AppendLine();
logSb.Append("OriginalObject: ").Append(args.ErrorContext.OriginalObject).AppendLine();
logSb.AppendLine("Error: ").Append(args.ErrorContext.Error).AppendLine();
logSb.AppendLine("Partial serialization results: ").Append(sb).AppendLine();
logSb.AppendLine("TraceWriter contents: ").Append(settings.TraceWriter).AppendLine();
logSb.AppendLine("JavaScriptSerializer serialization: ");
try
{
logSb.AppendLine(new JavaScriptSerializer().Serialize(obj));
}
catch (Exception ex)
{
logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
}
logSb.AppendLine("XmlSerializer serialization: ");
try
{
logSb.AppendLine(obj.GetXml());
}
catch (Exception ex)
{
logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
}
logSb.AppendLine("BinaryFormatter serialization: ");
try
{
logSb.AppendLine(BinaryFormatterExtensions.ToBase64String(obj));
}
catch (Exception ex)
{
logSb.AppendLine("Failed, error: ").AppendLine(ex.ToString());
}
Debug.WriteLine(logSb);
};
var serializer = JsonSerializer.CreateDefault(settings);
serializer.Serialize(jsonWriter, obj);
}
finally
{
settings.Error = oldError;
settings.TraceWriter = oldTraceWriter;
settings.Formatting = oldFormatting;
}
}
return sb.ToString();
}
}
public static class XmlSerializerExtensions
{
public static T LoadFromXML<T>(this string xmlString)
{
using (StringReader reader = new StringReader(xmlString))
{
return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
}
public static string GetXml<T>(this T obj)
{
using (var textWriter = new StringWriter())
{
var settings = new XmlWriterSettings() { Indent = true, IndentChars = " " };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj);
return textWriter.ToString();
}
}
}
public static class BinaryFormatterExtensions
{
public static string ToBase64String<T>(T obj)
{
using (var stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, obj);
return Convert.ToBase64String(stream.GetBuffer(), 0, checked((int)stream.Length)); // Throw an exception on overflow.
}
}
public static T FromBase64String<T>(string data)
{
return FromBase64String<T>(data, null);
}
public static T FromBase64String<T>(string data, BinaryFormatter formatter)
{
using (var stream = new MemoryStream(Convert.FromBase64String(data)))
{
formatter = (formatter ?? new BinaryFormatter());
var obj = formatter.Deserialize(stream);
if (obj is T)
return (T)obj;
return default(T);
}
}
}
You would likely replace the final Debug.WriteLine() with an appropriate logging method, then replace JsonConvert.SerializeObject(data) with JsonSerializerExtensions.SerializeObject(data) in your applications code.

MaxJsonLength Error For Large Data [duplicate]

In one of my controller actions I am returning a very large JsonResult to fill a grid.
I am getting the following InvalidOperationException exception:
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
Setting the maxJsonLength property in the web.config to a higher value unfortunately does not show any effect.
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644"/>
</webServices>
</scripting>
</system.web.extensions>
I don't want to pass it back as a string as mentioned in this SO answer.
In my research I came across this blog post where writing an own ActionResult (e.g. LargeJsonResult : JsonResult) is recommended to bypass this behaviour.
Is this then the only solution?
Is this a bug in ASP.NET MVC?
Am I missing something?
Any help would be most appreciated.
It appears this has been fixed in MVC4.
You can do this, which worked well for me:
public ActionResult SomeControllerAction()
{
var jsonResult = Json(veryLargeCollection, JsonRequestBehavior.AllowGet);
jsonResult.MaxJsonLength = int.MaxValue;
return jsonResult;
}
You could also use ContentResult as suggested here instead of subclassing JsonResult.
var serializer = new JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
return new ContentResult()
{
Content = serializer.Serialize(data),
ContentType = "application/json",
};
Unfortunately the web.config setting is ignored by the default JsonResult implementation. So I guess you will need to implement a custom json result to overcome this issue.
No need for a custom class. This is all that is needed:
return new JsonResult { Data = Result, MaxJsonLength = Int32.MaxValue };
where Result is that data you wish to serialize.
I'm surprised no one has suggested using a result filter. This is the cleanest way to globally hook into the action/result pipeline:
public class JsonResultFilter : IResultFilter
{
public int? MaxJsonLength { get; set; }
public int? RecursionLimit { get; set; }
public void OnResultExecuting(ResultExecutingContext filterContext)
{
if (filterContext.Result is JsonResult jsonResult)
{
// override properties only if they're not set
jsonResult.MaxJsonLength = jsonResult.MaxJsonLength ?? MaxJsonLength;
jsonResult.RecursionLimit = jsonResult.RecursionLimit ?? RecursionLimit;
}
}
public void OnResultExecuted(ResultExecutedContext filterContext)
{
}
}
Then, register an instance of that class using GlobalFilters.Filters:
GlobalFilters.Filters.Add(new JsonResultFilter { MaxJsonLength = int.MaxValue });
If use Json.NET to generate the json string, it doesn't need to set MaxJsonLength value.
return new ContentResult()
{
Content = Newtonsoft.Json.JsonConvert.SerializeObject(data),
ContentType = "application/json",
};
Alternative ASP.NET MVC 5 Fix:
In my case the error was occurring during the request. Best approach in my scenario is modifying the actual JsonValueProviderFactory which applies the fix to the global project and can be done by editing the global.cs file as such.
JsonValueProviderConfig.Config(ValueProviderFactories.Factories);
add a web.config entry:
<add key="aspnet:MaxJsonLength" value="20971520" />
and then create the two following classes
public class JsonValueProviderConfig
{
public static void Config(ValueProviderFactoryCollection factories)
{
var jsonProviderFactory = factories.OfType<JsonValueProviderFactory>().Single();
factories.Remove(jsonProviderFactory);
factories.Add(new CustomJsonValueProviderFactory());
}
}
This is basically an exact copy of the default implementation found in System.Web.Mvc but with the addition of a configurable web.config appsetting value aspnet:MaxJsonLength.
public class CustomJsonValueProviderFactory : ValueProviderFactory
{
/// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
/// <returns>A JSON value-provider object for the specified controller context.</returns>
/// <param name="controllerContext">The controller context.</param>
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
object deserializedObject = CustomJsonValueProviderFactory.GetDeserializedObject(controllerContext);
if (deserializedObject == null)
return null;
Dictionary<string, object> strs = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
CustomJsonValueProviderFactory.AddToBackingStore(new CustomJsonValueProviderFactory.EntryLimitedDictionary(strs), string.Empty, deserializedObject);
return new DictionaryValueProvider<object>(strs, CultureInfo.CurrentCulture);
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
string fullStreamString = (new StreamReader(controllerContext.HttpContext.Request.InputStream)).ReadToEnd();
if (string.IsNullOrEmpty(fullStreamString))
return null;
var serializer = new JavaScriptSerializer()
{
MaxJsonLength = CustomJsonValueProviderFactory.GetMaxJsonLength()
};
return serializer.DeserializeObject(fullStreamString);
}
private static void AddToBackingStore(EntryLimitedDictionary backingStore, string prefix, object value)
{
IDictionary<string, object> strs = value as IDictionary<string, object>;
if (strs != null)
{
foreach (KeyValuePair<string, object> keyValuePair in strs)
CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
return;
}
IList lists = value as IList;
if (lists == null)
{
backingStore.Add(prefix, value);
return;
}
for (int i = 0; i < lists.Count; i++)
{
CustomJsonValueProviderFactory.AddToBackingStore(backingStore, CustomJsonValueProviderFactory.MakeArrayKey(prefix, i), lists[i]);
}
}
private class EntryLimitedDictionary
{
private static int _maximumDepth;
private readonly IDictionary<string, object> _innerDictionary;
private int _itemCount;
static EntryLimitedDictionary()
{
_maximumDepth = CustomJsonValueProviderFactory.GetMaximumDepth();
}
public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
{
this._innerDictionary = innerDictionary;
}
public void Add(string key, object value)
{
int num = this._itemCount + 1;
this._itemCount = num;
if (num > _maximumDepth)
{
throw new InvalidOperationException("The length of the string exceeds the value set on the maxJsonLength property.");
}
this._innerDictionary.Add(key, value);
}
}
private static string MakeArrayKey(string prefix, int index)
{
return string.Concat(prefix, "[", index.ToString(CultureInfo.InvariantCulture), "]");
}
private static string MakePropertyKey(string prefix, string propertyName)
{
if (string.IsNullOrEmpty(prefix))
{
return propertyName;
}
return string.Concat(prefix, ".", propertyName);
}
private static int GetMaximumDepth()
{
int num;
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
{
return num;
}
}
return 1000;
}
private static int GetMaxJsonLength()
{
int num;
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonLength");
if (values != null && values.Length != 0 && int.TryParse(values[0], out num))
{
return num;
}
}
return 1000;
}
}
I solved the issue by following this link
namespace System.Web.Mvc
{
public sealed class JsonDotNetValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
var bodyText = reader.ReadToEnd();
return String.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>(JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new ExpandoObjectConverter()), CultureInfo.CurrentCulture);
}
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
//Remove and JsonValueProviderFactory and add JsonDotNetValueProviderFactory
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonDotNetValueProviderFactory());
}
there is a bit other case - data is sent from client to server.
when you are using controller method and model is huge :
[HttpPost]
public ActionResult AddOrUpdateConsumerFile(FileMetaDataModelView inputModel)
{
if (inputModel == null) return null;
....
}
system throws exception like this "Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property. Parameter name: input"
Only changing Web.config settings is not enough to help in this case. You could additionally override mvc json serializer for supporting huge data model sizes or manually deserialize model from Request. Your controller method becomes:
[HttpPost]
public ActionResult AddOrUpdateConsumerFile()
{
FileMetaDataModelView inputModel = RequestManager.GetModelFromJsonRequest<FileMetaDataModelView>(HttpContext.Request);
if (inputModel == null) return null;
......
}
public static T GetModelFromJsonRequest<T>(HttpRequestBase request)
{
string result = "";
using (Stream req = request.InputStream)
{
req.Seek(0, System.IO.SeekOrigin.Begin);
result = new StreamReader(req).ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(result);
}
You can try define in your LINQ expression only the field's that you will need.
Example. Imagine that you have an Model with Id, Name, Phone and Picture (byte array) and need to load from json into an select list.
LINQ Query:
var listItems = (from u in Users where u.name.Contains(term) select u).ToList();
The problem here is "select u" that get all fields. So, if you have big pictures, booomm.
How to solve? very, very simple.
var listItems = (from u in Users where u.name.Contains(term) select new {u.Id, u.Name}).ToList();
The best practices is select only the field that you will use.
Remember. This is a simple tip, but can help many ASP.NET MVC developpers.
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
};
}
Was the fix for me in MVC 4.
None of the above worked out for me until I changed the Action as [HttpPost].
and made the ajax type as POST.
[HttpPost]
public JsonResult GetSelectedSignalData(string signal1,...)
{
JsonResult result = new JsonResult();
var signalData = GetTheData();
try
{
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer { MaxJsonLength = Int32.MaxValue, RecursionLimit = 100 };
result.Data = serializer.Serialize(signalData);
return Json(result, JsonRequestBehavior.AllowGet);
..
..
...
}
And the ajax call as
$.ajax({
type: "POST",
url: some_url,
data: JSON.stringify({ signal1: signal1,.. }),
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data !== null) {
setValue();
}
},
failure: function (data) {
$('#errMessage').text("Error...");
},
error: function (data) {
$('#errMessage').text("Error...");
}
});
You need to read from the configuration section manually before your code returns a JsonResult object. Simply read from web.config in single line:
var jsonResult = Json(resultsForAjaxUI);
jsonResult.MaxJsonLength = (ConfigurationManager.GetSection("system.web.extensions/scripting/webServices/jsonSerialization") as System.Web.Configuration.ScriptingJsonSerializationSection).MaxJsonLength;
return jsonResult;
Be sure you defined configuration element in web.config
this worked for me
JsonSerializerSettings json = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var result = JsonConvert.SerializeObject(list, Formatting.Indented, json);
return new JsonResult { Data = result, MaxJsonLength = int.MaxValue };
You can put this code in cshtml if you are returning view from controller and you want to increase the length of view bag data while encoding in json in cshtml
#{
var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
jss.MaxJsonLength = Int32.MaxValue;
var userInfoJson = jss.Serialize(ViewBag.ActionObj);
}
var dataJsonOnActionGrid1 = #Html.Raw(userInfoJson);
Now, dataJsonOnActionGrid1 will be accesible on js page and you will get proper result.
Thanks

Categories

Resources