window.location="http://taciturndiscourse.com/services/wcf-and-json-in-working-together/";
I'm working on a application that takes client interactions with the web app and reports them to a service I have. A lot of the interactions are javascript based so what better way to communicate with my web service then with [url=http://json.org/]JSON (Java Script Object Notation).[/url]
Of course, if you've ever worked with WCF you know that unless you are doing "out of the box" communication, configuring a WCF service can be on par with, say, jabbing yourself in the eye with a fork... repeatedly.
But I would not let myself be conquered by the configuration beast that WCF is so I dove in.
First, let's talk about the Service Interface. The ServiceContract property should have the Name property set to the Class name, and the Namespace property set to an empty string. Why? Because JSON uses the Name property as its object name and setting the Namespace property would mean you would have to fully qualify the class name everytime. Which to me: is a pain, so leave it blank.
For my OperationContract you'll see that I have a WebGet attribute. I have a WebGet instead of a WebInvoke because I plan on returning a boolean back down to the server. WebInvoke is more "fire and forget". You'll also notice that I have explicitly set the ResponseFormat property to return Json.
Code:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using System.Web.Script.Services;
using System.Text;
namespace Pixel73.Service
{
[ServiceContract( Namespace="", Name="ClientReporter")]
public interface IClientReporter
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
Boolean SendReporterClick(
String pageInstanceId,
String controlId,
String controlInstanceId,
String reporterMessageId,
String additionalInfo);
}
}
Second, let's take a look at the class definition. Step one is to make sure you have your AspNetCompatibilityRequirements set to "Allowed". This is very important if you plan on using this in a asp:ScriptManager... which we are... so put it in. My ClientReporter class uses the IClientReporter contract AND, if you remember, is the same name as the Name we gave our ServiceContract. The one method I have simply takes my identifiers and reports them to my app which returns a boolean value if it succeeded.
Code:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ClientReporter : IClientReporter
{
public Boolean SendReporterClick(
String pageInstanceId,
String controlId,
String controlInstanceId,
String reporterMessageId,
String additionalInfo)
{
return ClientReporterDirector.SendClientMessage(
pageInstanceId,
controlId,
controlInstanceId,
reporterMessageId,
additionalInfo);
}
}
Third is the configuration. Aside from the Attributes we've set, this is the heart of the service. Without the heart, your service fails. I'm going to leave out the top portion of the web.config and put the system.serviceModel stuff in only. Take a look below real quick.... .... not that bad is it? But there are KEY features to focus on.
1. binding="webHttpBinding" - obviously all of these calls are ajax so having a webHttpBinding just kinda makes sense.
2. - VERY important for JSON, because without this dandy little flag you won't get the javascript. No javascript, No JSON.
3. - This is needed for ASP.NET stuff. asp:ScriptManager won't load this very well without it.
Code:
<endpoint address="" binding="webHttpBinding" contract="Pixel73.Service.IClientReporter"
behaviorConfiguration="AjaxBehavior">
Guess what? That's it. Your service now spits JSON.
Let's quick wire it up in our ASP.NET app.
On your page, reference the location of your service followed by the "/js/" to return the JSON.
And then finally the Javascript function that calls it. Note how I don't have to fully qualify ClientReporter()? Isn't that nice? The first parameters to your call are the parameters you are sending to the server, the last two will be your Callback handler (it's an async call) and your error handler.
Code:
function SendClientReporterMessage(
pageInstanceId,
controlId,
controlInstanceId,
reporterId,
additionalInfo) {
var ci = new ClientReporter();
ci.SendReporterClick(
pageInstanceId,
controlId,
controlInstanceId,
reporterId,
additionalInfo,
Callback,
OnError);
}
function Callback(result) {
alert("Result: " + result);
}
function OnError(error) {
alert("Error: " + error._message);
}
Something very important to remember about WCF and JSON. WCF returns all JSON calls via POST. You CANNOT call a POST to another server because of security reasons and you WILL get an Access Is Denied error. And don't think the crossdomain.xml and clientaccesspolicy.xml files will save you either... they won't.
Any questions? Hit me up on Twitter [url=http://twitter.com/ShankRabbit]http://twitter.com/ShankRabbit[/url]