Monday, June 28, 2010

Get along with WCF 4 and jQuery Ajax

Initially I thought this was going to be a breeze, but as I experienced it was closer to rough sea. But as any experienced sea creature knows, rough sea is just like a breeze.

web.config

<system.serviceModel>
<services>
<service name="StbSetupGUI.HtmlParser">
<endpoint address="" behaviorConfiguration="StbSetupGUI.AjaxAspNetAjaxBehavior" binding="webHttpBinding" contract="StbSetupGUI.HtmlParser" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="StbSetupGUI.AjaxAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
</system.serviceModel>

The most important part is the <enableWebScript /> attribute. (This config also has exception detailts turn on). This is added for you when you add an AJAX-enabled WCF Service to your project, so no snag there.

Service class

The service class will be automatically decorated with the AspNetCompatibilityRequirements attribute if you chose to add an AJAX-enabled WCF Service. Still crusing ahead.

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class HtmlParser{...}

WCF Methods

I wanted to use POST for my calls and decorated the method with the WebInvoke attribute. I initally used WebGet which worked fine, but WebInvoke got the waves crushing over my head.

[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json)]
public string GetText(string cssPath, string url){...}

jQuery call

This is where I had most trouble getting it right, due to my stubbornness of using WebInvoke.

First I had issues getting the json format correct, so I decided to use the json2 library to encode my parameters correct with double and single quotes.

Next, the content type made me slightly sea sick. Most examples specify this as “application/json; charset=utf-8”. This just gave me error upon error. In the end I removed the charset part and it all played ball. Who cares about utf-8 anyway, right?

var path = "H1";
var url = "http://something";
$.ajax({
type: "POST",
url: "HtmlParser.svc/GetText",
contentType: "application/json",
data: JSON.stringify({ cssPath: path, url: url }),
dataType: "json",
success: AjaxSuccess,
error: AjaxFailed
});

And if you want readable exceptions, parse the result.responseText to a json object in order to get at the details of the error message being returned from WCF. The WCF details are residing in a property called ExceptionDetail. So the key properties to remember is responseText and ExceptionDetail.

function AjaxFailed(result) {
var res = JSON.parse(result.responseText);
if (res.ExceptionDetail) {
alert(res.Message);
return;
}
};

Fairly easy, but alot of small things can go wrong. Took me a couple of days of trial and error (and a lot of Fiddling) to get it all 100% working. It was a breeze :D