Saturday, April 11, 2009

ASP.Net Ajax in Mono

In a recent discussion with a friend of mine, it was brought to my attention that one of the additions in Asp.Net Ajax (the features located in System.Web.Extensions.dll) was the ability for asmx web services to emit lean-and-sexy JSON instead of tubby-and-pimply SOAP.

This is an exceptionally cool feature, since it effectively gets you out of having to deal with the horrifically complicated configuration involved in setting up WCF, just to get JSON to your client script.

Since web applications are becoming more client-script/web service oriented these days, I was curious at how well these kinds of ASP.Net applications would port to Mono. After all, with the economy being what it is, some companies are becoming interested in ways to continue to innovate while saving some money, and Mono runs ASP.Net on Linux.

In order to get started quickly, I got a copy of VMWare Player (which is free), and downloaded the VMWare image from the Mono project's web site for Mono 2.4. When I started the image, I discovered that everything I needed to start experimenting was ready to go out of the box. There were some samples, and a copy of the new version of MonoDevelop, just waiting for me.

The first thing I did was to create a new ASP.Net web project in C#, and create an asmx web service that would return a complex type of some sort, and then use JQuery on the Default.aspx to call the web service. I used the JSON2.js serializer on the client side to verify that the output by just deserializing it.

The initial results were a disaster. All I could get from Mono's asmx web service was XML output, despite putting the ScriptMethodAttribute on my web service method. ScriptMethodAttribute tells the asmx HttpHandler to output in JSON format.

Assuming (incorrectly, as I later discovered) that I had found a rather silly bug in the Mono class library, I tested the exact same code in Microsoft's ASP.Net...which proceeded to work as expected.

After a bit of a break, I started thinking about how, exactly, MS got the old asmx HttpHandler to output JSON without modifying the existing class library. After all, when the smart folks as MS started adding in the 3.0 and 3.5 class libraries, they vowed to not change the existing class library if it wasn't truly necessary.

I took another look at my web.config file in Visual Studio and discovered what magic made this possible:

<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
...
</httpHandlers>


In Visual Studio, the default web.config unwires the old asmx http handler, then wires up a new asmx http handler that lives in System.Web.Extensions.dll. The old handler is still unaware of JSON, the new handler takes care of all of this instead.

The default web.config MonoDevelop created did not contain these modifications the the httpHandler section. Fortunately, everything about the <add> line was the same except for the assembly version (Really? You got the public key token the same but not the assembly version? Why?). Once I modified web.config, I got JSON output from the asmx.

I know not everything in ASP.Net 2.0 is working in Mono, but its really satisfying to see that the team working on it have implemented the parts that are most interesting to everyday web developers. I'm looking forward to seeing what cool bits the next release of Mono will bring.



6 comments:

  1. Regarding the System.Web.Extensions version numbers, Mono includes two versions -- both the 3.5 version (3.5.0.0) and the 1.0 version (1.0.61025.0). Note that you'll only be able to reference the 3.5 version from MonoDevelop if you project targets the 3.5 runtime profile.

    I'm uncertain under what circumstances MD should automatically make/undo the asmx handler changes, since some users might want SOAP while using other SWE features. FWIW, the default ASP.NET MVC template in MD does include the asmx handler change.

    ReplyDelete
  2. That's good to know that they support compatibility with the 3.5 version as well. When I set the reference in MonoDevelop, it gave me the old version number, I probably don't have the project version set up correctly.

    As far as I can tell, there is no real advantage to using the old asmx handler. If you still need SOAP, you can just leave the ScriptMethodAttribute off of your WebMethodAttribute decorated methods. At least, that's how it works on the MS version of the class library.

    ReplyDelete
  3. If adding the asmx handler change can't break anything, then it'd be a good idea to add it automatically when the S.W.E.dll is referenced. I'll have to check if there could be any side effects first. Thanks for the pointers!

    (For the record, I work on the ASP.NET support in MD)

    ReplyDelete
  4. how did u modify the web.info file, i am stuck at the place where asmx file doesnt output json stream but xml instead.

    ReplyDelete
  5. web.config is the file you want, not web.info.

    You should be able to place the xml in the posting into your system.web section of your web.config and have it spit out JSON. Don't flat replace the httpHandlers section if it's already in there, or you'll wish you didn't.

    Then its just a matter of setting the right attributes on the web method.

    Basically, the xml fragment in the post instructs ASP.Net to use a different bit of code to process .asmx urls, and the new bit knows about JSON and the ScriptMethod attribute. The default asmx processor knows nothing about ScriptMethod attributes so it ignores them.

    ReplyDelete
  6. I can't get this to work. I have modified the web.config as you did. Tried both versions of the SWE.dll but all I get is soap XML. What am I missing here?

    ReplyDelete