Saturday, March 10, 2012

Use ResponseXML instead of ResponseText in Atlas?

You can create your own HttpHandler for .asmx that wraps the response from the JSON serializer in XML. You would return something like this:

<?xml version="1.0" encoding="UTF-8"?>
<json><![CDATA[
(response from RestHandler goes here)
]]></json
This needs to be done so that the result returned is a valid XML document, otherwise responseXML won't work in the browser. To create your own filter you need to use theReflector to look at Microsoft.Web.Services.ScriptHandlerFactory (in Microsoft.Web.Atlas.dll) and implement your own factory that does the same thing except that it wraps the RestHandler in your own handler before returning it. Your own handler could look like this:

public class AtlasHandlerWrapper : IHttpHandler {
private IHttpHandler restHandler;

public AtlasHandlerWrapper(HttpContext context) {
restHandler = RestHandler.CreateHandler(context);
}

public bool IsReusable {
get { return restHandler.IsReusable; }
}

public void ProcessRequest(HttpContext context) {
string encoding = "UTF-8";
context.Response.ContentType = "text/xml;charset=" + encoding;
context.Response.Write("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n");
context.Response.Write("<json><![CDATA[");
restHandler.ProcessRequest(context);
context.Response.Write("]]></json>");
}
}

Unfortunately, to get this to work you will need to modify the Microsoft.Web.Atlas assembly to make a few methods and classes publicly accessible (ildasm/ilasm). Then just modify web.config to use your factory instead of the ScriptHandlerFactory and you're done on the server. You'll also have to make sure to use the modified Atlas assembly in /Bin/.

Then in Atlas/AtlasCore/AtlasRuntime.js you will need to modify Web.Net.WebResponse.get_data() so that it checks for the new XML format before returning, like this:

this.get_data = function() {
return FilterJSONXML(_requestor.responseText, _requestor.responseXML);
}

function FilterJSONXML(responseText, responseXML) {
if (responseXML.getElementsByTagName('json') == null ||
responseXML.getElementsByTagName('json')[0] == null) {
return responseText;
}
return responseXML.getElementsByTagName('json')[0].firstChild.data;
}

All considered, it's a hack, it's never a good idea to modify someone else's assembly, and it might have other consequences (upgrading to the latest Atlas is now more complicated), but it works.

Thanks, Joel!

Works great!


I'm a little puzzled by that. What's the scenario for that and what does this hack accomplish exactly?
I believe responseText is always encoded in UTF-8 (link), at least on Mozilla and IE, whereas with responseXML you can set the encoding. This hack lets you use JSON with non-UTF-8 strings. If I'm mistaken, please correct me, but personal testing seems to reaffirm this.

Sure you can...

Simply use get_xml() instead of get_data() off of the Web.Net.WebResponse class (which is the type of the object returned from WebRequest's response property).

Hope this helps...

No comments:

Post a Comment