views:

367

answers:

5

I am calling a Page Method from JQuery as described here: http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/

This is all working fine. During testing I came across an error when my response from the Web Method was too large: Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.

I was able to do a bit of research on the maxJsonLength property and set it higher, however I would like to try to catch this exception serverside, before it is sent to the client during the Ajax call. How do I do this?

I have set a try/catch block within my method to no avail, it is happening outside my method (during JSON Serialization).

StackTrace looks like this:

at System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, StringBuilder output, SerializationFormat serializationFormat)  
at System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, SerializationFormat serializationFormat)  
at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)  
at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)

Update :
The global and page level catches won't work for me (but will probably get the bounty at this point. Maintaining a global exception for something very specific to one page call seems like a poor design decision.) The point of me wanting to catch the exception is so I can trunkcate the text and still make a valid response to the javascript call.

+2  A: 

Maybe How to: Handle Page-Level Errors will help.

eed3si9n
A: 

If you can't access the underlying code of the serializer which actually throws the exception to fix it, maybe custom error handlers are an option?

Joscha
+2  A: 

You can also try to add a global exception handler in your app .

NM
+3  A: 

It might be a great effort, but if a well-designed solution is what you're after, I'm thinking your best bet is probably to create a class that extends the service handler, that implements your own custom serializer, where you check for maxJsonLength. You could then setup your web.config to let all (or some) asmx requests be handled by your own handler. The Spring framework seems to facilitate this, although I haven't looked closer into that solution.

Be aware, though, that manually truncating a JSON string, without breaking the syntax, could be quite an effort in itself.

Another solution, which would perhaps be easier to implement, and still arguably pretty neat, would be to overwrite (or wrap) jQuery's $.ajax function with a function of your own, that stringifies the JSON on the client (this is done anyway, to create the request in the first place, so it shouldn't be a lot of overhead), and checks length there. The gain with this approach is that you don't have to mess with extending the service handler, but also, the part of truncating the object would be easier, as your javascript object is readliy at hand; you can iterate it, stringify subsets of it, check their length, or use wahtever mechanism you like, to implement smart truncating (obviously whatever means of truncating JSON you want to use, you'll have to know your data, to be able to decide what can safely be removed without breaking key functionality in the request).

If truncating cannot be done, you'd have the option of displaying an error message, without even having to hit the server.

Since javascript is so flexible, you could specify, say, $.ajaxCore = $.ajax, and then overwrite $.ajax with your own function, that calls $.ajaxCore.

David Hedlund
The problem is that the text that is too long is determined to be too long at the server, after my method has run, but before ajax gets a chance to do its own truncation. The idea of being able to trap the error would be that I could manually look a the object I am sending and truncate the specific field at fault.
Jeff Martin
+1 for a non-simple one line answer with a link tho.
Jeff Martin
oh, sorry, i misread you as the problem being with the incoming request =/ so your problem is basically that you return an object, and the code fails after you've handed over the return object for the server to serialize? well, in that case, how about manually invoking `System.Web.Script.Services.JavaScriptSerializer.Serialize` within a try/catch-block? I know your current execption happens at a point where you cannot try/catch it, but instead of just `return myObject` do `return getValidatedObject(myObject)` and then `getValidatedObject` serializes, catches exception and truncates, and...
David Hedlund
... returns an object, which can *then* be returned to the service handler, which will then serialize the code *again*. it would mean serializing every request twice, instead of just once, but at least it gives you the ability to know that what you return will validate
David Hedlund
Also (sorry for the rant), the idea of extending the service handler would still be a solution, only it'd work the other way around. Extend the service handler, map the asmx requests to handle it, invoke it the way the regular service handler normally does, but override the serialization part after your method returns an object, to include a try/catch-block, and do the necessary truncates. I think my previous comment should give you a quick and dirty solution, and this, a proper but lengthy solution.
David Hedlund
+1  A: 

Calculate object size yourself, before returning from method. You don't need to do exact calculation, just an estimate would be fine. Most likely it would be enough to get size of text fields that could be large (e.g. description of something or comments).

If result size is bigger than certain limit, truncate the data. Set MaxJsonLength twice as big as your limit.

Pavel Chuchuva