2

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?

Community
  • 1
  • 1
Pedro Corso
  • 557
  • 8
  • 22
  • One way of doing this without setting maxJsonLength is to paginate your data and send it to the client along with some identifier to get the next set of results. The client can make another API call to get the next set of results and repeat this till it gets the entire record set. – Vidhyardhi Gorrepati Mar 23 '17 at 18:08
  • @VidhyardhiGorrepati Paging my results would require multiple calls to the server. Isn't it better to maintain only one connection? I was researching about it and found this answer: http://stackoverflow.com/a/26281258/6882194, but I'm not finding any way to fit this on my current code. Maybe because I'm using a REST API? – Pedro Corso Mar 23 '17 at 18:17
  • Interesting article. Learning new stuff everyday... – Vidhyardhi Gorrepati Mar 23 '17 at 18:28
  • Possible duplicate of [JsonMaxLength exception on deserializing large json objects](http://stackoverflow.com/questions/9943727/jsonmaxlength-exception-on-deserializing-large-json-objects) – Liam Mar 24 '17 at 10:53

1 Answers1

0

for JsonMaxLength exception

Try

write in web.config

<system.web.extensions>
<scripting>
  <webServices>
    <jsonSerialization maxJsonLength="1000000">
    </jsonSerialization>
  </webServices>
</scripting>
</system.web.extensions>

By default the maxJsonLength is 102400.

Liam
  • 27,717
  • 28
  • 128
  • 190
Komal
  • 304
  • 1
  • 7