Home > Programming > Creating a Gravatar client with jQuery and WCF

Creating a Gravatar client with jQuery and WCF


Introduction

A couple of weeks ago I announced the release of the first .NET implementation of the Gravatar API.

Gravatar.NET is available for download on Codeplex.

What I’d like to show in this article is how to make use of the library using jQuery and WCF to create your own Gravatar client (Ponderi.com style).

This article will demonstrate how to show a user their Gravatar account images, allow the user to activate a different image or delete it.

I will build upon many of the concepts I described in an earlier article I wrote called: “Creating a Webservice Proxy with jQuery”. So if you like, check it out first as I won’t go into the basics in this article.

All of the code shown in this article is available for download, the link below.

First, the server side:

Server Side

A few steps to get started:

  • Create a new web project in VS (I used VS 2010)
  • Download Gravatar.NET from Codeplex and set a reference to the Gravtar.NET.DLL  (.NET 3.5 or 4.0 both available)
  • Create a new WCF service.

In the interface for the service (IGravatarWebService) I added the following methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[ServiceContract(Namespace = "Tutorials", Name = "GravatarWebService")]
  public interface IGravatarWebService
  {
    [OperationContract, WebGet]
    GravatarResponse GetImages();

    [OperationContract, WebGet]
    GravatarResponse Login(string email, string password);

    [OperationContract]
    GravatarResponse SelectImage(string imageId);

    [OperationContract]
    GravatarResponse DeleteImage(string imageId);
  }

Login: Checks the credentials the user supplies and stores them for later use if they are successfully authenticated by Gravatar.

GetImages: Retrieves the images currently available on the Gravatar service for the given account.

SelectImage: Activates the selected image, making it the default for the given account.

DeleteImage: Deletes the selected image from the Gravatar service.

Notice that all of the methods return the same type; GravatarResponse which is a class with the following definition:

1
2
3
4
5
6
7
8
9
10
11
12
[DataContract]
  public class GravatarResponse
  {
    [DataMember]
    public bool Success { get; set; }

    [DataMember]
    public string Message { get; set; }

    [DataMember]
    public IEnumerable<GravatarImage> Images { get; set; }
  }

This gives us a consistent response that the client can work with, the Success property telling the client whether the method was executed successfully and the Message property allowing us to tell the client what happened if it didn’t.

Next step is to implement the methods in the service class (GravatarWebService).

I won’t go into each and every method for brevity but let’s have a look at the GetImages method as an example as it’s the more complicated one:

Unfortunately, Gravatar’s API doesn’t give us just one method to retrieve the images for an account with information to determine which image is the default one (the image currently in use). So we need to combine the results of two methods: ‘UserImages’ and ‘Addresses’.

UserImages gives us the collection of images, Addresses gives us the default image for the email address associated with the Gravatar account.

The good news are that Gravatar.NET implements all of the methods using both a synchronous and asynchronous way so we can use the asynchronous nature to our advantage and call both methods almost simultaneously and wait until they both complete so we can combine the results before sending the response back to the client:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public GravatarResponse GetImages()
    {
      var success = false;
      var msg = String.Empty;
      List<GravatarImage> images = null;
      IEnumerable<GravatarAddress> addresses = null;

      try
      {
        var reset = new ManualResetEvent(false);
        var waitCounter = 0;

        var service = GetAuthenticatedService(); 

        if (service != null)
        {
          service.SetCallBack((res, state) => //callback for UserImages method
            {
              if (!res.IsError)
              {
                images = new List<GravatarImage>();

                foreach (var img in res.ImagesResponse)
                {
                  images.Add(new GravatarImage
                  {
                    Name = img.Name,
                    Url = img.Url
                  });
                }
              }
              else
                msg = "Error! " + res.ErrorInfo; //typically would be a friendlier message

              waitCounter++;
              if (waitCounter > 1) reset.Set();

            }).UserImagesAsync(null);

          service.SetCallBack((res, state) => //callback for Addresses method
            {
              if (!res.IsError)
              {
                addresses = res.AddressesResponse;
              }
              else
                msg = "Error! " + res.ErrorInfo;

              waitCounter++;
              if (waitCounter > 1) reset.Set();

            }).AddressesAsync(null);

          reset.WaitOne();

          if (addresses != null && images != null)
          {
            var q = from a in addresses //get the active images for this address
                where a.Name == service.Email
                select a.ImageId;

            var activeImageId = q.First();

            foreach (var img in images)
            {
              img.Active = (img.Name == activeImageId);
            }

            success = true;
          }
          else
          {
            if (msg.IsEmpty()) msg = "Couldnt retrieve images information";
          }
        }
        else
          msg = "You must be log in first";
      }
      catch (Exception ex)
      {
        msg = "Error! " + ex.Message; //typically would be a friendlier message
      }

      return new GravatarResponse { Success = success, Message = msg, Images = images };
    }

In the code example above we first call the ‘UserImagesAsync’ method of the GravatarService instance. The ‘SetCallBack’ method gives us a way to pass a handler method that will be called once the service returns the response for the method call.

Within the handler we add the information about each returned image to a collection defined outside the handler and we increase the ‘waitCounter’ value by one. Then we check if the counter is greater than one, if it is, it means that the other method we called is already done and therefore we can set the ManualResetEvent object which is currently blocking the thread from continuing.

After calling ‘UserImagesAsync’ we immediately call ‘AddressesAsync’ which returns information about the account’s address, part of this information is the default image associated with the account(In Gravatar, an account may have multiple addresses associated with it).
In the callback handler for this method we’ll also perform the same check using the ‘waitCounter’ and set the reset event if the other method has already finished.

After defining handlers for both methods we use the ‘WaitOne’ method of the ManualResetEvent object that blocks the thread until the ‘Set’ method is called.
By doing this we hold off the thread execution until both of the Gravatar service methods complete.

Once the methods return we combine the information from their results and set the ‘Active’ property for the default image and return the collection of images to the client.

Client Side

The HTML, CSS and Javascript included in this example result in a page looking like this:

Gravatar client web page

To achieve this result I used jQuery, jTemplates and BlockUI.

BlockUI gives us the nice overlay to put on top of the current page.

jTemplates gives us a templating engine for jQuery to render out the html for the images.

As a side note, I wanted to give the “new” templating engine 
from Microsoft/jQuery a try with this tutorial but couldn’t get 
the ‘If’ conditionals to work inside the template,  I just got 
an error no matter what I tried so I stuck with good ol’ jTemplates…

The first step in coding the client side logic was to grab the serviceproxy.js from my earlier tutorial’s code example.
Then, remove the unneeded methods from the previous article and add the methods to match those exposed by the web service:

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
  getImages: function (success, error)
  {
    this._doAjax("GetImages", null, success, error);
  },

  login: function (email, password, success, error)
  {
    var data = { email: email, password: password };

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

  selectImage: function (imgId, success, error)
  {
    var data = "{" + "\"imageId\": \"" + imgId + "\" }";

    this._doAjax("SelectImage", data, success, error, "POST");
  },

  deleteImage: function (imgId, success, error)
  {
    var data = "{" + "\"imageId\": \"" + imgId + "\" }";

    this._doAjax("DeleteImage", data, success, error, "POST");
  },

With the service proxy object definition ready we can wire up everything to get a functioning client.
I won’t go into every detail, you can download the code and play around with it yourself but as an example I will again take the getImages method in the javascript code (gravatar.js) I wrote to illustrate how it’s done.

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
function getImages()
{
  showProgress();

  _proxy.getImages(function (result)
  {
    hideProgress();

    if (result.Success)
    {
      var photoList = $("#photoList", _photoListContainer);

      photoList.setTemplateElement("tmplPhotoList"); //use template to render out the images retrieved from server
      photoList.processTemplate(result.Images);

      $(".photoItem").hover(function (e)
      {
        if (!_inProgress)
        {
          $(".photoTasks", $(e.currentTarget)).slideDown(300); //dont show buttons while in awaiting async method
        }
      },
        function (e)
        {
          $(".photoTasks", $(e.currentTarget)).hide();
        }
      );

      setTimeout(function () { hideStatus(); }, 2000);
    }
    else
    {
      showStatus(result.Message);
    }
  },
  errorHandler);
}

getImages is called immediately, as soon as the user is authenticated.

Gravatar client log in

The ‘getImages’ proxy method takes two arguments, the first, a callback method to handle a successful call(one that doesn’t throw an error) and the second for when an error is thrown that wasn’t handled by the service implementation.

The success handler method is called with one parameter(result), a JSON serialized object representing the GravatarResponse class defined in C#.

We first check the Success property, if true we use a HTML template defined on the page like so:

<textarea id=”tmplPhotoList” style=”display:none”>
{#foreach $T as image}
<li class=”photoItem {#if $T.image.Active}active{#/if}” rel=”{$T.image.Name}”>
<div class=”photoTasks”>
<img title=”Select Photo” class=”select” onclick=”selectPhoto(‘{$T.image.Name}’);” src=”/images/select.png”/>
<img title=”Delete Photo” onclick=”deletePhoto(‘{$T.image.Name}’);” src=”/images/delete.png”/>
</div>
<img id=”{$T.image.Name}” src=”{$T.image.Url}?size=200″ {#if $T.image.Active}title=”This is your active photo”{#/if} />
</li>
{#/for}
</textarea>


The template includes jTemplates syntax to inject the images data into the HTML. If you’re curious about jTemplates, I wrote an article a while back that has more information about it.

We then call processTemplate to render the HTML and the data from the Images property of the result object.

The last thing to do is to set a hover event handler on each ‘photoItem’ div which contains the actual image. In the hover handler we define that as long as there isn’t an async method running in the background we should show the tasks buttons (Select and Delete).

Gravatar client tasks

The reason not to show the tasks buttons while in progress is of course to avoid a situation where a user will click to delete an image and then immediately try to activate it, which will probably end up with a nasty error.

Conclusion

If you have a website or thinking about creating one, you undoubtedly have considered including user profile information and a personal photo for your users because let’s face it, what site doesn’t these days?!
A great way of avoiding the hassle of storing your users’ images yourself and then creating complex logic for handling the uploading of images and managing them is to use Gravatar.

To me one of the downsides was that by using Gravatar you would need to ask your users to go to an external site (gravatar.com) to upload and manage their photos which isn’t optimal. This was the reason I created the Gravatar.NET library.

Hopefully in this article I’ve managed to show that if you’re running a .NET site it won’t be too much of a daunting task to create a client that will let you enjoy the Gravatar advantages without driving your users out of your site.

Code

The code for this tutorial is available here.

  1. August 8, 2010 at 01:39 | #1

    nice post..

    • June 9, 2011 at 03:17 | #2

      I’m trying to have my gravatar placed on my web-site. “Like the one above this comment, Any one could instruct me to do this implementation?

      • Yoav Niran
        June 9, 2011 at 07:23 | #3

        Hi there, what exactly are you trying to achieve? If its just showing your own gravatar on your own site you can do this quite easily by placing an img tag on a page and pointing it to your gravatar unique URL. You can find this URL by going to gravatar.com and logging in to your account.

        If you want to show other users gravatar then this blog post should help you get started.

        Let me know if you have more questions.
        Yoav.

  2. August 15, 2010 at 02:51 | #4

    nice post, thx

  1. August 3, 2010 at 16:08 | #1
  2. August 4, 2010 at 14:28 | #2

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: