Home > Programming > Creating a Webservice Proxy with jQuery

Creating a Webservice Proxy with jQuery


Contents

Introduction

In a previous post I’ve shown how to use WCF, jQuery and jTemplates to retrieve information from the server and lay it out on the page using jTemplates’ templating engine.

The code example in that article used the Microsoft Ajax client library and the proxy it creates at run time to ease the javascript code needed to call the methods of the webservice I created.

In this article I would like to show you an easy way of creating a similar proxy to the Microsoft one in pure javascript and the help of jQuery’s AJAX capabilities. This makes a lot of sense if you do not have the option to use the MS library on the client or simply because you don’t want to.
I will be relying mostly on the code examples and concepts I described in the previous article  so I’d recommend reading it first before continuing to read this one.

You can let me know if you find this article useful or not by using the ratings and comments below.

Server Side

The good news: no need to change anything on the server side, the web service can continue to work as it always did. All we’re doing in this exercise is to replace the client side logic and so we will not touch the server code.

Client Side

Using the same website I’ve shown how to create in the previous article we will create the new proxy for our WCF webservice.
In the System folder create a javascript file and call it ServiceProxy.js, To the file add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
ServiceProxy = function() //constructor for the proxy
{
  this._baseURL = "Services/TutorialService.svc/";
};

ServiceProxy.prototype =
{
  _defaultErrorHandler: function(xhr, status, error)
  {
    alert(xhr.statusText);
  },

  _doAjax: function(method, data, fnSuccess, fnError)
  {
    if (!data) data = {};

    if (!fnError) fnError = this._defaultErrorHandler;

    $.ajax({
      type: "GET",
      url: this._baseURL + method,
      data: data,
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: fnSuccess,
      error: fnError,
      dataFilter: function(data)
          {
            var response;

            if (typeof (JSON) !== "undefined" && typeof (JSON.parse) === "function")
              response = JSON.parse(data);
            else
              response = val("(" + data + ")");

            if (response.hasOwnProperty("d"))
              return response.d;
            else
              return response;
          }
    });
  }
};

Lets examine the code:

The first section is the constructor of the proxy object, in there we define the base URL of the service we will be calling.

The second method is _defaultErrorHandler, this is a default error handler, its strictly a developer friendly method, allowing the calling method to leave the pointer to an error handling method empty. Of course the implementation of this default error handler should be changed in a real life scenario as its not wise to show any raw error information to a website’s visitor.

The third and most important method is _doAjax, this is where the “magic” happens which takes care of the back and forward communication with the server.

The first two lines take care of the defaults, if there is no data passed to the webservice we assign an empty object and if there is no pointer supplied to an error handler we assign our default method.

Next is the where we use jQuery’s incredibly convenient Ajax method, lets examine this call, jQuery’s ajax method accepts an object that sets all the needed information:

‘type’: The HTTP verb: could be GET, POST, etc. In this example we use GET since we’re only retrieving from the server.
For a more robust scenario we would probably want to turn this into a parameter of the method.

‘url’: The URL of the webservice method, in this case the base URL defined in the constructor and the name of the method.

‘data’: The parameters passed to the service method, constructed as a JSON object.

‘contentType’: the content type of the data being sent to the server. In our case we’re communicating with the webservice using JSON and therefore we use: “application/json; charset=utf-8”

‘success’: A pointer to the method to be called when the asynchronous call has finished successfully.

‘error’: A pointer to the method to be called when the asynchronous call finished with an error.

‘dataFilter’: I’ve taken the code block in this example from Dave Ward’s Encosia blog. I will add the links to a couple of his articles at the end of this post.

The dataFilter is used whenever there is a successful response from the server and allows us to modify the response in any way we like before its passed to the success method.

In this example there are two uses to the filter: The first one is to turn the response into a JSON object from the string result coming from the server. It will first check whether the current browser supports JSON parsing natively (Firefox 3.5, IE8 for example). If it does it will use the native JSON object and if not will use the less optimized and less secure eval() function.

The second part is to check whether the response is enclosed within a ‘d’ property, this ‘d’ property is added automatically by Microsoft’s WCF service and since we want to abstract this fact from the caller we only return the relevant response if this is the case.

Now that we have everything we need for our base proxy functionality all we need to do is add the methods that match the exposed methods on the webservice. To the prototype of the ServiceProxy object add these two methods:

1
2
3
4
5
6
7
8
9
10
11
getArticles: function(success, error)
{
  this._doAjax("GetArticles", null, success, error);
},

getArticle: function(link, success, error)
{
  var data = {link: link};

  this._doAjax("GetArticle", data, success, error)
},

These two methods call our _doAjax, passing the necessary information such as the method name and the parameters if needed to the call.

In fact the methods mirror the methods available on the webservice thus completing the proxy.

Now the only thing to do is create a HTML file (or any other file, could even be JSP) that will replace the aspx page we created in the previous article.
You can find all the source code in the example site ive made available for download, in this post I will only show the changes needed.

- First, create a default.html in the root of the site.
- In the head element add these links:

<script src=”System/jquery.js” type=”text/javascript”></script>
<script src=”System/jquery-jtemplates.js” type=”text/javascript”></script>
<script src=”System/ServiceProxy.js” type=”text/javascript”></script>
<link href=”System/Styles.css” rel=”stylesheet” type=”text/css” />

- Copy over the entire javascript element.
- Add the following code as the first line of the script to declare the proxy:

<script type="text/javascript">
    var proxy = new ServiceProxy();

- In the document ready function replace the call to the GetArticles method with this one:

1
2
3
4
$(document).ready(function() //executes this code when page loading is done
{
       proxy.getArticles(articlesRetrieved);
});

- In the loadArticle function replace the call to getArticle with this one:

1
2
3
4
5
6
7
function loadArticle(link)
{
    $("#LoadingImg").removeClass("Hidden");
    $("#SingleArticle").html("");

    proxy.getArticle(link, articleRetrieved, serviceDefaultErrorHandler);
}

That’s all! Now you have a working page doing exactly the same as it did before only using our own javascript proxy without any dependencies on the Microsoft proxy or the MS Ajax library.
The end result is as expected identical to the one before:

serviceproxy result

Source Code

Can be downloaded here.

Resources

  1. July 20, 2011 at 22:02 | #1

    nice! what about calling WCF Authentication Services?

  2. October 3, 2011 at 21:11 | #2

    Great articles.
    One discovery… jQuery 1.5 and above breaks it.
    I’m not a hardcore javascript developer, but the easiest workaround is to remove the dataFilter property in _doAjax.
    This unfortunately means the ‘d’ property added by the WCF service to all json responses is still present. The workaround to that is to change all ‘results’ to ‘results.d’ in index.html, but it would be nicer if the ‘d’ could be removed inside _doAjax as in the original code.

  3. October 3, 2011 at 21:36 | #3

    Followup…
    since the jquery ajax method now automatically converts responses to json, and the fact that dataFilter runs before this magic happens, the most sensible solution to me (feel free to disagree) is to manipulate the raw response before jQuery does the conversion to json. So for my own project, I’ve reinstated the dataFilter property with simple text manipulation to remove the ‘d’ property added by WCF.

    dataFilter: function (data) {
    //remove the ‘d’ property inserted by all WCF services (if it exists)
    return data.replace(/^\{“d”:(.*)\}$/, “$1″);
    }

    • Yoav Niran
      October 4, 2011 at 08:15 | #4

      Hi Greg,
      Its a great point you bring up, ive been meaning to update the article or write a new one but havent gotten around to doing it yet.
      In any case, since im very much adverse to string manipulation, however simple they may be, what i did in my usage of the proxy is wrap the Success handler with my own so it looks like this:

      $.ajax({

      success: function(data, status, xhr)
      {
      var newData = (data.hasOwnProperty(“d”) ? data.d : data)

      fnSuccess(newData, status, xhr);
      },

      });

      Thanks!
      Yoav

  4. Yosi
    November 21, 2011 at 22:13 | #5

    Where is the service?, I can’t find any file called : “Services/XXXX.svc/”

    I can find the Service References\WCFService\Reference.cs
    and the WCFService.asmx .

    Can you please help me what I should write in the _baseURL ?

  5. Yosi
    November 21, 2011 at 23:06 | #6

    Yosi :
    Where is the service?, I can’t find any file called : “Services/XXXX.svc/”
    I can find the Service References\WCFService\Reference.cs
    and the WCFService.asmx .
    Can you please help me what I should write in the _baseURL ?

    I did:
    this._baseURL = “Service/WcaService.asmx/”;

    and add my function
    GetPictures: function (link, success, error) {
    var data = { link: link };

    this._doAjax(“GetPictures”, data, success, error)
    },

    I call :

    var proxy = new ServiceProxy();
    prox.GetAlbums(0, OnGetPicturesSucceed, OnDefaultErrorHandler);

    nothing happen!

    • Yoav Niran
      November 22, 2011 at 06:57 | #7

      Hi Yosi,
      Im not sure to which asmx youre referring to… the web service exposed in the download i provided in this article (http://www.mediafire.com/file/jutyzjrzm5m/ServiceProxy%20-%20Turotial%20Site.zip) has an svc file called: TutorialService.svc
      you can find it in the zip file: JTemplatesWCF – Tutorial Site\Services folder.

      the bsae url property should point to the SVC file:
      this._baseURL = “Services/TutorialService.svc/”;

      you should find everything there :)

  6. Yosi
    November 22, 2011 at 12:56 | #8

    I successful, but with the following changes:
    1. type: “POST”, instead of “GET” -> any comment?
    2. success: fnSuccess, -> the “wrap the Success handler with my own” does not works.

  7. Yosi
    November 22, 2011 at 13:03 | #9

    Yoav Niran :
    Hi Yosi,
    Im not sure to which asmx youre referring to… the web service exposed in the download i provided in this article (http://www.mediafire.com/file/jutyzjrzm5m/ServiceProxy%20-%20Turotial%20Site.zip) has an svc file called: TutorialService.svc
    you can find it in the zip file: JTemplatesWCF – Tutorial Site\Services folder.
    the bsae url property should point to the SVC file:
    this._baseURL = “Services/TutorialService.svc/”;
    you should find everything there

    Thanks a lot Yoav, I successfully configure, in my case it is this._baseURL = “Service/WcaService.asmx/”;

    It works great, except he 2 issues I sent:
    1. type: “POST”, instead of “GET” -> any comment?
    2. success: fnSuccess, -> the “wrap the Success handler with my own” does not work, I use the change suggested by “Greg”, and it works fine.

    • Yoav Niran
      November 23, 2011 at 09:35 | #10

      Hi Yosi,

      Regarding the need to change to POST rather than using GET. thats up to how you create your webservice and its methods. You need to allow GET operations and make sure you mark the method as expecting GET. In WCF thats done using the WebGet attribute in combination with the OperationContract attribute decorating the method of the service class.

      The code for this method is a bit out of date and uses an older version of jQuery. things have changed a bit since then with they way jQuery handles AJAX so Greg’s comment is very valid and useful. Ill try and put up a post showing the AJAX with a current jQuery version.

      thanks for the feedback.
      Yoav.

      • Yosi
        November 23, 2011 at 09:39 | #11

        Thanks a lot Yoav,
        Sorry I didn’t say what I think and should say before:

        it is a great article very very useful and helpful, especially to new web dev like me.

        Thanks a gain , well done.

  8. Jamison
    September 19, 2012 at 18:20 | #12

    This post offers clear idea in support of the new visitors of blogging, that genuinely how to do blogging.

  9. October 5, 2012 at 13:07 | #13

    Wow! This blog looks just like my old one!

    It’s on a entirely different topic but it has pretty much the same page layout and design. Superb choice of colors!

  10. October 5, 2012 at 23:00 | #14

    Good post. I’m facing some of these issues as well..

  11. Jathin Devaiah
    October 10, 2012 at 15:34 | #15

    Hi,

    Im making use of the same feature. The change is that, I use Post instead of Get and the application i am working on is a portal application.

    Everytime i run the app, it gives me a error that it cannot find the resource file i.e. the asmx file which I have added.

    FYI, the asmx file is in the root of the project and the aspx file form which I am accessing the webservice is under the project in a folder like “content/abcd/xyz.aspx”.

    what shoudl be the URL like?

    • Yoav Niran
      October 10, 2012 at 16:35 | #16

      Hi Jathin,

      How are you setting the URL? can you share that piece of code?

      Are you using it from javascript?

      Basically it should point to “/myservice.asmx” if its indeed at the root of the site.

      Yoav.

  12. Jathin Devaiah
    October 11, 2012 at 12:15 | #17

    $.ajax({
    type: “POST”,
    url: “./myservice.asmx/HelloWorld”,
    dataType: “xml”,
    data: “sName=” + newName,
    success: function (msg) { ajaxFinish(msg); },
    error: function (msg) { ajaxError(msg); }
    });

    This is the code I am using.

    URLs tried (ABC is the folder in the server in which the service is present and the web page from which I am accessing is present in ABC/Page/Content/page.aspx)

    url: “./myservice.asmx/HelloWorld”

    url: “/ABC/myservice.asmx/HelloWorld”

    url: “~/ABC/myservice.asmx/HelloWorld”

    url: “/portal/ABC/myservice.asmx/HelloWorld

    Every iteration it gave the same error “Resource not found” and pointed to the web service for check whether it is spelt correct.

    • Yoav Niran
      October 17, 2012 at 13:47 | #18

      Hi,
      You mentioned that the ASMX is at the root of your project. Would it then be accessible simply from: “/myservice.asmx”?

  13. April 22, 2013 at 14:49 | #19

    Your facebook like module is not working right, at least it isn’t on my end. Does not appear to work no matter what I do. Wanted to provide you with a like, but I can’t.
    I’m sorry.

  1. August 5, 2009 at 10:55 | #1
  2. April 27, 2010 at 14:55 | #2
  3. August 1, 2010 at 20:46 | #3
  4. September 1, 2010 at 23:02 | #4

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 315 other followers

%d bloggers like this: