Announcement: WCF Web API is now ASP.NET Web API! ASP.NET Web API released with ASP.NET MVC 4 Beta. The WCF Web API and WCF support for jQuery content on this site wll removed by the end of 2012.

Building a JavaScript AJAX widget with a service

Sometimes you want to create a tailored client-side experience for your API, to make it very easy to access the API from webpages. The difference between this scenario and the JavaScript SDK scenario, is that in this case your customers don't even have to learn JavaScript. In this scenario you provide a self-contained widget that knows how to interact with your service: all the customer needs to know is how to copy/paste your widget reference into their page. Consider the widgets provided by WeatherBug as examples of this scenario.

Development for this scenario has just  Started, so the solution described below contains only some initial thoughts on how to address the scenario. Please be sure to provide feedback in the comments or file a bug regarding your ideas for improving it.

A sample demonstrating this scenario can be found at WCFJQuery/Samples/WeatherWidget. In this particular example, we have designed a widget which lets us embed the weather forecast for a given location.

WeatherWidget

This sample relies on the following client-side libraries – jquery, jquery-ui – and assumes you are familiar with them. Please refer to these links to look up any concepts we refer to that might be unfamiliar.

Widget framework

This sample is built based on the jQuery UI widget framework. All the user needs to do is paste the following lines into their page.

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3.     <title>Weather Widget</title>
  4.     <!-- stylesheets and script includes -->
  5.     <script type="text/javascript" src="scripts/jquery.ui.weather.js"></script>
  6.     <script type="text/javascript">
  7.         $(function () {
  8.             $("#weather").weather();
  9.         });
  10.     </script>
  11. </head>
  12. <body>
  13.     <div id="weather" />
  14. </body>
  15. </html>

Note the jquery.ui.weather.js file, which contains our widget code. In this case that file is handcrafted, but you could imagine a feature, where a web service will generate that file for you. Please let us know in the comments whether this is valuable.

The file itself follows the standard jQuery UI widget pattern and exposes some options that the user can override when they instantiate the widget.

  1. $.widget("ui.weather", {
  2.     options: {
  3.         // Service address
  4.         address: "./WeatherService.svc/GetForecast",
  5.         // WOEID of location - to find out what it is for a given location, go to http://weather.yahoo.com, look up
  6.         // the forecast for the location and then look at the URI for the WOEID
  7.         woeid: 2490383
  8.     },
  9.     _create: function () {
  10.         // create widget
  11.     },
  12.     destroy: function () {
  13.         // destroy widget
  14.     }
  15. });

Cross-domain access

In this scenario, the web service and the page where the widget is used can live on different domains. The service lives at the domain where the API is hosted (for example http://api.weatherbug.com), and the client can be a customer’s http://blogger.com account, where they decided to embed the widget. Because the two are hosted on different domains, the browser will prevent communication between the two. To get our data we have to use a technique called “JSONP”. Inside our widget we make the service requests like this:

  1. $.ajax({
  2.     url: o.address,
  3.     data: { woeid: o.woeid },
  4.     dataType: "jsonp",
  5.     success: function (result) {
  6.         // do something with the result
  7.     }
  8. });

Note the use of “jsonp” as the data type. To learn more about JSONP check out the jQuery ajax() documentation. To enable JSONP access on our service, we have to write a custom ServiceHostFactory.

  1. public class WebServiceHostFactory3WithJsonP : ServiceHostFactory
  2. {
  3.     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
  4.     {
  5.         WebServiceHost3 wsh = new WebServiceHost3(serviceType, baseAddresses);
  6.         wsh.Opening += new EventHandler(this.Wsh_Opening);
  7.         return wsh;
  8.     }
  9.  
  10.     private void Wsh_Opening(object sender, EventArgs e)
  11.     {
  12.         WebServiceHost3 host = sender as WebServiceHost3;
  13.         foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
  14.         {
  15.             if (endpoint.Binding is WebHttpBinding)
  16.             {
  17.                 WebHttpBinding binding = endpoint.Binding as WebHttpBinding;
  18.                 binding.Security = new WebHttpSecurity { Mode = WebHttpSecurityMode.None };
  19.                 binding.CrossDomainScriptAccessEnabled = true;
  20.             }
  21.         }
  22.     }
  23. }

We are aware this is a complex user experience for enabling JSONP and we are looking at ways for making it simpler.

Last edited Feb 17, 2012 at 8:08 PM by danroth27, version 6

Comments

cblack Nov 12, 2010 at 3:58 PM 
Looks interesting.. any plans to support WCF Message or TransportWithMessageCredential modes?