This article illustrates how to create a Volta control around Flickr, the popular image hosting service.
What is Volta?
Microsoft Live Labs Volta is Microsoft's emerging toolset that enables developers to build multi-tier web applications by applying familiar .NET techniques and patterns. The intended use of this toolset is for Developers to build web application as .NET client application, and then specify the portions of the codes that will run on the client and server side. The compiler then creates cross browser JavaScript, Web Services, communication, serialization, security etc. to tie the tiers together. This article is based on the first CTP of Volta considering its current limitations. We will see how we can create a Volta control that the compiler can convert into an AJAX Widget without requiring us writing a single line of JavaScript code. We will write code in our very familiar C# language. In this article, you will end up creating a Flickr widget like the one shown in figure 1.
Figure 1: The Flickr widget built using Volta
Currently Volta is at its first CTP release, which was made publicly available on December 5 last year. Volta requirements and the installer can be found at http://labs.live.com/volta/download/ Since it's just the first CTP, there are still a lot of limitations. I hope they will get over those in the next CTP or so.
The Specification of the Widget
The widget will have the following features:
- The photos for a particular Flickr user will be shown in a 3x3 grid.
- The tooltip of each of the photos will display the title of the image.
- There will be "prev" and "next" buttons for navigation.
- On click of each of the photos, a new window will open with the original Flickr source.
- There will not be a single line of JavaScript code.
The Flickr API
Flickr is a very popular photo hosting and sharing service. It is considered to be one of the leading examples of Web 2.0 applications. Users of Flickr can host hundreds of photos and share them with others. Flickr allows users to tag their photos, which make them easy to find. It has some of the best photo management features, which let users control access to photos pretty efficiently. A few of the interesting features of Flickr are the possibility of marking photos as favourites, grouping photo pool and Flickr Interestingness. Flickr also offers users the ability to release images under certain common usage licenses.
Flickr has an open API besides RSS and Atom feeds. The Flickr API offers numerous methods. It supports different popular request and response formats that should be familiar to the third party developers:
- REST
- XML-RPC
- SOAP
We choose REST because it is the simplest among others, and it is performed by simple HTTP GET or POST actions.
The Flickr Methods
The Flickr API exposes 115 methods so far. The methods are categorized in Authentication, Photos, User Activity, Photo Pool, Photo Upload and many more. Few of them are named as follows:
- flickr.photos.getInfo
- flickr.photos.search
- flickr.interestingness.getList
- flickr.photos.transform.rotate
- flickr.test.echo
A full listing can be found at: http://www.flickr.com/services/api/.
The Flickr Request, Response format
The general format of a Flickr request is:
- http://api.flickr.com/services/rest/?api_key=__API_KEY__&method=__METHOD_NAME__¶m1=value1¶m2=value2
__API_KEY__ is replaced by the API key
- http://api.flickr.com/services/rest/?api_key=9163070a740049b1bfe553864a4f1519&method=flickr.interestingness.getList
The response of a REST query can be rendered by the browser. Simply copy the URL above and paste it into the browser's address bar; then hit enter. You will see a response text somewhat like the following:
- <?xml version="1.0" encoding="utf-8" ?>
- <rsp stat="ok">
- <photos page="1" pages="5" perpage="100" total="500">
- <photo id="621909774" owner="30959251@N00" secret="70cdeec6f7" server="1411"
- farm="2" title="Yeah, holidays!" ispublic="1" isfriend="0" isfamily="0" />
- <photo id="620373432" owner="80176513@N00" secret="7c9d5769ab" server="1151"
- farm="2" title="In the Mood" ispublic="1" isfriend="0" isfamily="0" />
- <photo id="619761326" owner="50008412@N00" secret="5aec4bf2ec" server="1037"
- farm="2" title="Hear me roar!!!!" ispublic="1" isfriend="0" isfamily="0" />
- <photo id="619727916" owner="46355903@N00" secret="76680dafa6" server="1146" farm="2"
- title="Rain, rain, go away, I want to do some Sunrise photos" ispublic="1"
- isfriend="0" isfamily="0" />
- <photo id="620355782" owner="42009080@N00" secret="148cbdb6b0" server="1145" farm="2"
- title="Beneath A Black Sky" ispublic="1" isfriend="0" isfamily="0" />
- <photo id="621726130" owner="35373726@N00" secret="6b3d8fa0ca" server="1114" farm="2"
- title="" ispublic="1" isfriend="0" isfamily="0" />
- ... ...
- </photos>
- </rsp>
As you see the response is pretty straightforward. It simply has a bunch of photo
tags and each of the tags has information about that particular photo. A photo
tag has the unique identifier of the photo, owner identifier, server information and also a title. In our widget, we need to parse such XML and display the photos.
Note the rsp
tag with a stat
attribute that has ok
as value. It means the API call was completely errorless and successful. Let us make some mistakes intentionally to see how Flickr reacts. Hit the browser using the previous URL with a wrong API Key. You will receive an XML as response like the following:
- <?xml version="1.0" encoding="utf-8" ?>
- <rsp stat="fail">
- <err code="100" msg="Invalid API Key (Key not found)" />
- </rsp>
Here the stat
attribute has fail
as value, which means some kind of problem has occurred during the API call and the Flickr API notifies it so that the code can decide whether it should crawl any further or not.
The User NSID
User NSID is an alphanumeric string which uniquely identifies a user. It is often useful, especially in our case where our widget will display the photos of a particular user. In order to retrieve the NSID for a user, Flickr offers a method named flickr.people.findByUsername
which takes the Flickr screen name of the user and returns an XML like the following:
- <?xml version="1.0" encoding="utf-8" ?>
- <rsp stat="ok">
- <user id="9198206@N07" nsid="9198206@N07">
- <username>your_screen_name</username>
- </user>
- </rsp>
The Solution Structure
First of all, create a new Volta Application and name it VoltaFlickrWidgetDemo
. Then, add a new Volta Control application named VoltaFlickrWidget
to the solution. Add a class to the Volta control project named FlickrHelper.cs. This class contains very useful methods that fetch Flickr photo data and make them easily accessible by the control. Now include the VoltaFlickrWidget
project in the References of the VoltaFlickrWidgetDemo
project. The resulting solution structure will be like the one shown in the following figure.
Figure 2: Solution Structure
The Flickr Volta Control
The Flickr Volta control we are going to develop should be easy to add to the Volta page considering that there is a div element with an id of divWidgetContainer
present in the Volta page:
- var divWidgetConatiner = Document.GetById<Div>("divWidgetContainer");
- VoltaControl1 flickrWidget = new VoltaControl1("screen_name", "9149b1bfe387273833553864a4f1519", "Flickr Widget", 300, 270);
- flickrWidget.AddToDiv(divWidgetConatiner);
- flickrWidget.DownloadPhotos();
Here VoltaControl1
is the Flickr control we are going to build. Sorry for the naming, but Volta is still immature and can't rename the underlying HTML file of the Volta Control which we will discuss later. Thus, instead of making it confusing, we are keeping it called VoltaControl1
. In the above code snippet, VoltaControl1
is initialized with the screen name, API key, control's title, height and width properties. The AddToDiv
method of the control adds itself to the div passed as a parameter and then the DownloadPhotos
method starts downloading the photos. As soon as AddToDiv
is called, the control's HTML file content is injected into the DOM, and HTML elements become accessible like so:
- Document.GetById<Div>("divSomeDiv");
The FlickrHelper
The FlickrHelper class basically performs two operations. One of them is retrieving the NSID of the user against the screen name; and the other is fetching the photo collection of the specified user. The following GetNSID
method performs an Asynchronous REST call to the Flickr API and receives the NSID back:
- public void GetNSID()
- {
- IHttpRequest request = HttpRequestFactory.Create();
- request.AsyncSend("POST", URL_USER_NSID + ScreenName, string.Empty,
- delegate(string response)
- {
- OnNsidLoaded(new NsidLoadedEventArgs(response));
- });
- }
Both the IHttpRequest
interface and the HttpRequestFactory
class can be found in the Microsoft.LiveLabs.Volta.MultiTier
namespace. The AsyncSend
method performs the asynchronous call and then calls back the delegate, inside of which the OnNsidLoaded
event is fired to notify the user of the FlickrHelper class that the NSID data has just arrived. An instance of the NsidLoadedEventArgs
is passed to the subscriber of that event to make the NSID available after parsing the necessary XML:
- public class NsidLoadedEventArgs : EventArgs
- {
- public string Nsid { get; set; }
- public NsidLoadedEventArgs(string response)
- {
- var xdocument = new XmlDocument();
- xdocument.LoadXml(response);
- var xnUser = xdocument.GetElementsByTagName("user")[0];
- if (xnUser == null)
- throw new Exception("Incorrect screenName");
- else
- {
- var xelUser = xnUser as XmlElement;
- Nsid = xelUser.GetAttribute("nsid");
- }
- }
- }
Similarly, an asynchronous call is made for fetching photo feed:
- public void DownloadPhotos(string nsid)
- {
- IHttpRequest request = HttpRequestFactory.Create();
- request.AsyncSend("POST", URL_PHOTOS + nsid, string.Empty,
- delegate(string response)
- {
- OnPhotosLoaded(new PhotosLoadedEventArgs(response, nsid));
- });
- }
In the above code snippet, an instance of PhotoLoadedEventArgs
is passed to the subscriber. In this case the photo URL collection is sent back using a Dictionary
object:
- public class PhotosLoadedEventArgs : EventArgs
- {
- public Dictionary<int, string> PhotoPool { get; set; }
- public PhotosLoadedEventArgs(string response, string nsid)
- {
- ...
- // code edited to save space
- }
- }
The Control Logic
The contents of VoltaControl1.cs file is basically HTML manipulation, so most of it is self-explanatory and doesn't need further discussion. Yet there are few points to ponder. The most important part is the DownloadPhotos
method:
- public void DownloadPhotos()
- {
- _WidgetContent.InnerHtml = "<br /><center><i>Downloading photos...</i></center>";
- flickrHelper.NsidLoaded += new NsidLoadedEventHandler(flickrHelper_NsidLoaded);
- flickrHelper.GetNSID();
- }
It registers the NsidLoaded
event of FlickrHelper, which is handled by flickrHelper_NsidLoaded
. Then, the GetNSID
method is called. Therefore, as soon as the NSID data is available, it will call the flickrHelper_NsidLoaded
method to handle the data:
- void flickrHelper_NsidLoaded(object sender, NsidLoadedEventArgs e)
- {
- if (e.Nsid == null)
- throw new Exception("Invalid NSID supplied.");
- else
- {
- _Nsid = e.Nsid;
- flickrHelper.PhotosLoaded += new PhotosLoadedEventHandler(flickrHelper_PhotosLoaded);
- flickrHelper.DownloadPhotos(_Nsid);
- }
- flickrHelper.NsidLoaded -= flickrHelper_NsidLoaded;
- }
Unlike the NSID, the DownloadPhotos
method of FlickrHelper returns a Dictionary of photos URLs and the LoadPhotos
method iterates through the photos and displays them in a 3x3 grid using a typical logic for pagination.
Construction of the Volta Page
The construction of the Volta page is simple. The default page would do, but for our project we need an extra div with an id of divWidgetContainer
. Moreover, we will add some other HTML code to beautify it. As for the Volta control, we are keeping the Volta page called VoltaPage1
. We will use some CSS classes, and add a CSS file named Style.css in the root of the Volta application. In the current release of Volta, CSS files are not automatically discovered even if you add it in the page's HTML as links. To make the Style.css file usable by the Volta page, perform the following steps:
- Right click on the Style.css from the Solution Explorer and choose Properties
- Set the Build Action as Embedded Resource
- Open the VoltaPage1.Designer.cs file and add the following line before
namespace
VoltaFlickrWidgetDemo
:
- [assembly: VoltaFile("Style.css")]
As stated before, the control is very convenient to use:
- VoltaControl1 flickrWidget = new VoltaControl1("ajaxwidget",
- "9163070a740049b1bfe553864a4f1519", "Flickr Widget", 300, 270);
- flickrWidget.AddToDiv(divWidgetConatiner);
- flickrWidget.DownloadPhotos();
This is pretty much it. When you download and run this project, you will see Flickr REST calls and photo navigation all performed within an AJAX application created without writing any JavaScript code. Volta generated the necessary client code for us to run the application in multiple browsers.
Summary
You have learned how to create a Volta control around the Flickr API. The code was purely written in .NET, yet we achieved complete AJAX functionality without writing a single line of JavaScript code introducing typical ContentProxy kind of things.
Source: http://dotnetslackers.com/articles/aspnet/BuildingAVoltaControlAFlickrWidget.aspx
No comments:
Post a Comment