My calls to the server are built in the following way:
- I have a callServer function on the client that sends data to my API;
- My API then receives the data from it's controller and pass it to a function that makes a call to the DB;
- The controller sends the response back to the client.
This is how I do it (these are just the important pieces of the code, not everything is here):
API (Context.cs):
public static IEnumerable<Dictionary<string, object>> Proc_example(int? value)
{
using (NpgsqlConnection conn = new NpgsqlConnection(ConnStr))
{
try
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "proc_example";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new NpgsqlParameter("value", convertNullValue(value)));
var reader = cmd.ExecuteReader();
return new DrToDictionary().Serialize(reader);
}
}
catch (Exception e)
{
throw e;
}
finally
{
conn.Close();
}
}
}
API (Controller.cs):
[Authorize]
public JsonResult example(int? value)
{
try
{
var data = Context.Proc_example(value);
return Json(new AppServerResult()
{
Result = new { list = data }
}, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return Json(new AppServerResult()
{
HasError = true,
ErrorMessage = "Houve um erro ao consultar, tente novamente."
});
}
}
Client (callServer):
app.callServer = function (options, sucessCallback, httpErrCallback, serverErrCallback, operationErrorCallback) {
if (options.source == undefined)
options.headers = { "Authorization": $.cookie('Token') }
options.success = function (result) {
try {
var _result = result;
if (typeof _result == "string") {
_result = jQuery.parseJSON(_result);
}
if (typeof _result.HasError != "undefined" && _result.HasError) {
if (!_result.IsValidationError) {
if (typeof __apiCallerErrorCallback == "function")
__apiCallerErrorCallback(_result.ErrorMessage);
if (typeof serverErrCallback == "function") {
serverErrCallback(_result.ErrorMessage);
}
} else {
app.notifyValidationException(_result.ErrorMessage);
}
} else {
if (typeof sucessCallback == "function") {
if (_result.Result != undefined) sucessCallback(_result.Result);
else sucessCallback(_result);
}
}
} catch (ex) {
throw ex;
}
};
options.error = function (result) {
if (typeof httpErrCallback == "function") {
httpErrCallback();
}
if (typeof __apiCallerErrorCallback == "function")
__apiCallerErrorCallback("HTTP Error");
}
};
jQuery.ajax(options);
};
Calling example:
callingTheServerExample = function (callback, value) {
app.callServer({
type: "POST",
url: app.webAPIRootPath + "Controller/example",
data: "{ 'value':" + JSON.stringify(ko.toJS(value)) + " }",
contentType: "application/json; charset=utf-8",
dataType: "json"
}, function (result) {
if (typeof callback == "function")
callback(result);
});
}
My problem is that when my JSON gets too large, my API gives me a JsonMaxLength exception when sending tha data back to the client (the exception happens on the controller class). I'd prefer not to set my maxJsonLength to a higher value. Instead, I'd like to find a way to send my JSON in chunks from the API and mount it on the client through javascript.
Is there a way to do it?
EDIT:
I forgot to add a detail: I'm using a REST API. As stated in the comments below, pagination is a solution, but what I need is to get the whole record set to be available at once. It's possible to do it using pagination, but it seems to be slower and to cause more API calls. Streaming appears to be a solution, but I never did this before and I can't figure out how to implement it.
EDIT 2:
I've implemented my paging like this:
public JsonResult example(int? value, int page)
{
try
{
var data = Context.Proc_example(value, page);
if (pPage > 0)
{
var pagedResult = data.Skip((page - 1) * 20).Take(20).ToList();
return Json(new AppServerResult()
{
Result = new { list = data}
}, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new AppServerResult()
{
Result = new { list = data}
}, JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
return Json(new AppServerResult()
{
HasError = true,
ErrorMessage = "Houve um erro ao consultar, tente novamente."
});
}
}
But I still didn't achieve what I wanted. Would someone think of a better way?