Passing JSON serialized objects to a WCF service with jQuery

Print Content | More

You can find a lot of posts on the web on the subject, why writing another one then? Simply because despite all the documentation I’ve already found on the web, while trying to put it in action I’ve spent a couple of hours in making that work, so I’ll use this post to recap all the action I made as a reference guide for my future implementations.

The scenario is: we have a WCF service that is able to accept call to methods with complex parameters (like Messages object in a simple web chat project) and we want to be able to use those methods with jQuery with the minimal impact on the service implementation.

WCF Service setup

We consider a very simple implementation, you don’t have to use any ‘strange’ or unusual attribute here:

The message class we are sending back and forth:

/// <summary>
/// a single message in a conversation
/// </summary>
[DataContract]
public class Message : Entity<int>
{
    /// <summary>
    /// the nickname of who is sending the message
    /// </summary>
    [DataMember]
    public virtual string Sender { get; set; }
 
    /// <summary>
    /// this will be assigned when the object get persisted into the storage, not before
    /// once assigned it's likely to not be modified again
    /// </summary>
    [DataMember]
    public virtual DateTime Timestamp { get; set; }
 
    [DataMember]
    public virtual string Text { get; set; }
}

A test service implementation

/// <summary>
/// service used to serialize/desierialize the data in JSon for JQuery
/// </summary>
[ServiceContract]
public interface IChatService
{
    /// <summary>
    /// return a simple message
    /// </summary>
    /// <returns></returns>
    [OperationContract]
    Message TestMessage();
 
    /// <summary>
    /// a test function that takes a message and returns it modified
    /// </summary>
    /// <param name="msg"></param>
    /// <returns></returns>
    [OperationContract]
    Message TestMessageModify(Message msg);
 
    /// <summary>
    /// a test function that get multiple parameters and return a message
    /// modified
    /// </summary>
    /// <param name="msg"></param>
    /// <param name="id"></param>
    /// <returns></returns>
    [OperationContract]
    Message TestMessageModifyWithSuppliedContent(Message msg, int id);
}
[AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]
public class ChatService : IChatService
{
    public Message TestMessage()
    {
        return new Message() { Id = 1, Sender = "Test", Text = "1 - Text message.", Timestamp = DateTime.Now };
    }
 
    public Message TestMessageModify(Message msg)
    {
        msg.Text = "2 - Modified message";
        msg.Timestamp = DateTime.Now;
        return msg;
    }
 
    public Message TestMessageModifyWithSuppliedContent(Message msg, int id)
    {
        msg.Text = "3 - Second parameter passed: " + id;
        msg.Timestamp = DateTime.Now;
        return msg;
    }
}

The only thing needed is the ‘AspNetCompatibilityRequirements’ attribute.

All the magic is done in the WCF configuration section:

   1: <system.serviceModel>
   2:     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
   3:     <services>
   4:         <service name="RemoteAssistance.Services.Impl.ChatService"
   5:                  behaviorConfiguration="DebugJSonBehavior">
   6:             <endpoint address="" 
   7:                       binding="webHttpBinding" 
   8:                       behaviorConfiguration="DebugJSonBehavior"
   9:                       contract="RemoteAssistance.Services.IChatService">
  10:                 <identity>
  11:                     <dns value="localhost" />
  12:                 </identity>
  13:             </endpoint>
  14:             <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  15:         </service>
  16:     </services>
  17:     <behaviors>
  18:         <endpointBehaviors>
  19:             <behavior name="DebugJSonBehavior">
  20:                 <enableWebScript />
  21:             </behavior>
  22:         </endpointBehaviors>
  23:         <serviceBehaviors>
  24:             <behavior name="DebugJSonBehavior">
  25:                 <serviceMetadata httpGetEnabled="true" />
  26:                 <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
  27:             </behavior>
  28:         </serviceBehaviors>
  29:     </behaviors>
  30: </system.serviceModel>

To activate JSON serialization and deserialization for an end point we have to supply some information:

  • in line 7 we set the binding to ‘webHttpBinding’, this is the main actor the inject the JSON DataContract Serializer into the WCF stack.
  • in line 8 we set a specific endpoint behavior for this end point
  • lines 18-22 enable the endpoint behavior that makes it possible to consume the service from ASP.NET AJAX web pages.

Consuming the web service is the real ‘tricky’ point, calling a function without parameter is extremely easy, you can use code like this:

   1: $(document).ready(function() {
   2:     $.ajax({
   3:         type: "POST",
   4:         url: "http://localhost:58829/ChatService.svc/TestMessage",
   5:         data: "{}",
   6:         contentType: "application/json; charset=utf-8",
   7:         dataType: "json",
   8:         success: function(data) {
   9:             //debugger;
  10:             alert(data.d.Text);
  11:         },
  12:         error: function(XMLHttpRequest, textStatus, errorThrown) {
  13:                 debugger;
  14:            alert("Error Occured!");
  15:         }
  16:     });
  17: });

Things get a bit ‘complicated’ when you actually have to pass parameters (special tanks here go to my fellow Alkampfer for helping me find the solution). To pass a parameter successfully you have to supply as the data argument (line 5) a string that is the JSON representation of a JS object which properties matches the parameter name of the function you are calling, the parameters’ values are the actual values that will be sent to the server. If the parameter itself is a complex object (that is a class) you need to supply the JSON representation of the object, Let’s use an example to clarify:

if we want to call the TestMessageModify(Message msg) function we need to supply ad data parameter a JS object made like this:

   1: var msg2 = { "msg": { "Id": "2", "Sender": "Webpage", "Text": "Sended Text"} };

We’re defining an object that contains a ‘msg’ property (same name of the function parameter) which in turn contains another object (defined by the same properties that our Message object have, to allow JSON deserialization to work). What we need to pass to the ‘data’ argument of the function call is the string representation of object:

'{"msg":{"Id":"2","Sender":"Webpage","Text":"Sended Text"}}'

To have the JSON representation of JavaScript object we can use an external library like this one: http://www.JSON.org/json2.js

So, to call TestMessageModify(Message msg) and TestMessageModifyWithSuppliedContent(Message msg, int id), we can use the following code:

var msg2 = { "msg": { "Id": "2", "Sender": "Webpage", "Text": "Sended Text"} };
 
$(document).ready(function() {
    $.ajax({
        type: "POST",
        url: "http://localhost:58829/ChatService.svc/TestMessageModify",
        data: JSON.stringify(msg2),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(data) {
            alert(data.d.Text);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
            alert("Error Occured!");
        }
    });
});
 
var msg3 = { "msg": { "Id": "2", "Sender": "Webpage", "Text": "Sended Text"}, "id" : "1" };
 
$(document).ready(function() {
    $.ajax({
        type: "POST",
        url: "http://localhost:58829/ChatService.svc/TestMessageModifyWithSuppliedContent",
        data: JSON.stringify(msg3),
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(data) {
            alert(data.d.Text);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
            alert("Error Occured!");
        }
    });
});

It ended up being a quite long post for something that should have been much more simple.

Javascript, Jquery, Json, Wcf, Wcf service

7 comments

Related Post

  1. #1 da Garry - Saturday March 2010 alle 01:15

    Thank you. This post is exactly what I was looking for. Couldn't find any other post showing how to pass a JSON object using JQuery to a WCF service. Thanks again!

  2. #2 da uberVU - social comments - Saturday March 2010 alle 01:15

    Social comments and analytics for this post... This post was mentioned on Twitter by A_Giorgetti: Blogged: Passing JSON serialized objects to a WCF service with jQuery http://bit.ly/bax6pu...

  3. #3 da Tweets that mention Passing JSON serialized objects to a WCF service with jQuery at Primordial Code -- Topsy.com - Saturday March 2010 alle 01:15

    [...] This post was mentioned on Twitter by Elijah Manor, naoki osada, naoki osada, DotNetMarche, A_Giorgetti and others. A_Giorgetti said: Blogged: Passing JSON serialized objects to a WCF service with jQuery http://bit.ly/bax6pu [...]

  4. #4 da Daily links 2010-02-02 | Maxim's blog - Saturday March 2010 alle 01:15

    [...] Passing JSON serialized objects to a WCF service with jQuery [...]

  5. #5 da Jim - Wednesday October 2010 alle 05:52

    Good post! Thanks.

    I agree, it should not be this hard. I keep thinking, "If WCF is the solution, what was the problem?"

  6. #6 da Diego Guidi - Monday May 2011 alle 01:05

    Only a couple of notes:
    I've used webHttpBehavior instead of "enableWebScript", and the only way to make a valid REQUEST to the WCF service is to decorate the OperationContract with BodyStyle = WebMessageBodyStyle.WrappedRequest:

    [OperationContract]
    [WebInvoke(Method="POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    MyObject Echo(MyObject obj);

    using WebMessageBodyStyle.Base break json deserialization of the message

  7. #7 da Lanny Gibson - Thursday May 2011 alle 03:09

    Great post.

    I was having exactly this problem with wcf / jquery; took a couple days to get the hang of it and a lot of reading..wish I read this post sooner.

    Thanks

All fields are required and you must provide valid data in order to be able to comment on this post.


(will not be published)
(es: http://www.mysite.com)