Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

18 November 2009

A light-weight .NET framework for publishing Layar layers using WCF and Unity (C#)

Thus speaks Wikipedia:

Augmented reality (AR) is a term for a live direct or indirect view of a physical real-world environment whose elements are merged with (or augmented by) virtual computer-generated imagery - creating a mixed reality.

Amen. Fact is that AR is currently as hot a nuclear reactor core making its way to China, and that everyone and his aunt are scrambling to get a piece of the action. So why not me ;-)

On November 9th this year, my colleague Jeroen Prins, who did some prototyping with Layar, pushed a HTC Hero in my hands with the words “see if you can do something nice with it”. So in a few evenings I created a little framework for making Layar layers in an easier and consistent way. It is based upon some of Jeroen’s prototype, but since he insisted on not having credits for this I won’t give him any ;-). The framework uses the Enterprise Library, most notably Unity, and I assume you are familiar with it.

Since WCF can be bent in almost every direction as far as generating content is concerned, I decided to use it for my solution. I started, as you always start, with the data contract. The object model is pretty simple: a Layer object has Point-Of-Interest (Poi) objects, a Poi has Action objects. If you study the Layar GetPointsOfInterest page for a few minutes you will see the implementation is WCF 101. Maybe 102 ;-). Contrary to my habits, I forego on the comments – those are all on the GetPointsOfInterest page. First, the Action object:

using System.Runtime.Serialization;

namespace LocalJoost.Layar
{
  [DataContract(Name = "Action")]
  public class Action
  {
    [DataMember(Name = "uri")]
    public string Uri { get; set; }

    [DataMember(Name = "label")]
    public string Label { get; set; }
  }
}

The member name is “Uri” (following the .NET coding guidelines) but with adding “Name=uri” in the DataMember attribute I tell WCF to serialize the member as “uri”, without the capital “U”, thus following exactly the Layer API description. This is standard WCF stuff. Then, the Poi class:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace LocalJoost.Layar
{
  [DataContract (Name="POI")]
  public class Poi
  {
    public Poi()
    {
      Actions = new List();
    }
    [DataMember(Name = "actions")]
    public List Actions { get; set; }

    [DataMember(Name = "attribution")]
    public String Attribution { get; set; }

    [DataMember(Name = "distance")]
    public double Distance { get; set; }

    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "imageURL")]
    public string ImageUrl { get; set; }

    [DataMember(Name = "lat")]
    public int Latitude { get; set; }

    [DataMember(Name = "lon")]
    public int Longitude { get; set; }

    [DataMember(Name = "line2")]
    public string Line2 { get; set; }

    [DataMember(Name = "line3")]
    public string Line3 { get; set; }

    [DataMember(Name = "line4")]
    public string Line4 { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "type")]
    public int Type { get; set; }
  }
}

and finally, the Layer object itself:

using System.Collections.Generic;
using System.Runtime.Serialization;

namespace LocalJoost.Layar
{
  [DataContract]
  public class Layer
  {
    public Layer()
    {
      Hotspots = new List();
    }

    [DataMember(Name = "nextPageKey")]
    public string NextPageKey { get; set; }

    [DataMember(Name = "morePages")]
    public bool MorePages { get; set; }

    [DataMember(Name = "hotspots")]
    public List Hotspots { get; set; }

    [DataMember(Name = "layer")]
    public string LayerName { get; set; }

    [DataMember(Name = "errorCode")]
    public int ErrorCode { get; set; }

    [DataMember(Name = "errorString")]
    public string ErrorString { get; set; }
  }
}

I move on to the whopping complex service contract:

using System.ServiceModel;
using System.ServiceModel.Web;

namespace LocalJoost.Layar
{
  [ServiceContract(Namespace = "www.yournamespacehere.nl/layar")]
  public interface ILayarService
  {
    [OperationContract]
    [WebGet(UriTemplate = "Layar/{layerName}/*", 
      ResponseFormat=WebMessageFormat.Json)]
    Layer GetLayerData(string layerName);
  }
}

which defines the output for this as being JSON, and a custom URI matching pattern which allows us to put the actual layer name in the URL. The * at the end means "and the rest is also accepted". Now the title of this posting says I was doing something with Unity, and here it comes: I define an equally complex interface for a Layar "provider" which will be used by the service implementation:

using System.Collections.Generic;

namespace LocalJoost.Layar
{
  public interface ILayarProvider
  {
    Layer Get(double? lat, double? lon, 
      int? radius, int? accuracy, 
      IDictionary requestParameters);
  }
}

The final piece of real code is the implementation of the ILayarService service contract, with apologies for the crappy layout, but some WCF class names are a wee bit long:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.ServiceModel.Web;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using LocalJoost.Utilities.Unity;

namespace LocalJoost.Layar
{
  /// <summary>
  /// Layar service implementation
  /// </summary>
  public class LayarService : ILayarService
  {
    /// <summary>
    /// Request parameters
    /// </summary>
    private static NameValueCollection RequestParams
    {
      get
      {
        return WebOperationContext.Current != null ?          WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters
: null;
      }
    }

    private static readonly List<string> KeyWordsProcessed = 
      new List<string> { "lat", "lon", "radius", "accuracy" };

    /// <summary>
    /// Gets the layer data.
    /// </summary>
    /// <param name="layerName">Name of the layer.</param>
    /// <returns></returns>
    public Layer GetLayerData(string layerName)
    {
      try
      {
        if (WebOperationContext.Current != null )
        {
          Logger.Write("Layar call: " +             WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri);
        }
        // Note: layername is lowercase
        var provider =
          new UnityResolver(
             layerName.ToLowerInvariant()).Resolve<ILayarProvider>();

        // Collect the other parameters
        var reqParms = new Dictionary<string, string>();
        foreach( var key in RequestParams.Keys)
        {
          var keyS = key.ToString();
          if (!KeyWordsProcessed.Contains(keyS))
            reqParms.Add(keyS, RequestParams[keyS]);
        };
        
        return provider.Get(
          GetRequestDouble("lat"), GetRequestDouble("lon"),
          GetRequestInt("radius"), GetRequestInt("accuracy"),
          reqParms);
      }
      catch( Exception ex)
      {
        Logger.Write(ex,"Exceptions");
        return null;
      }
    }

    #region Utility methods
    private double GetRequestDouble(String keyname)
    {
      if (!(RequestParams == null || 
         string.IsNullOrEmpty(RequestParams[keyname])))
      {
        return Convert.ToDouble(RequestParams[keyname], 
         CultureInfo.InvariantCulture);
      }
      return -1;
    }

    private int GetRequestInt(String keyname)
    {
      if (!(RequestParams == null || 
         string.IsNullOrEmpty(RequestParams[keyname])))
      {
        return Convert.ToInt32(RequestParams[keyname],
          CultureInfo.InvariantCulture);
      }
      return -1;
    }
    #endregion
  }
}

Here comes my little UnityResolver into play, which was described earlier in this blog. What this LayarService basically does is accept a layer name, burp the call into a log file, get the lat, lon, radius, and accuracy from the query string, dump the rest of the query string parameters into a dictionary, use Unity to determine which ILayerProvider implementation is to be loaded, call it’s Get method with the collected data, and return the result.

Now there are only six steps to make this actually work. First, you define a web application project. You reference the LocalJoost.Layar project, System.ServiceModel.dll, System.Runtime.Serialization, every file in the Enterprise Library that starts with "Microsoft.Practices.Unity" (I have 5), and Microsoft.Practices.EnterpriseLibrary.Logging.dll.

The second step is: add a text file to the web application, for instance "LayarService.txt". You enter the following text in it:

<%@ ServiceHost Language="C#" 
    Debug="true" Service="LocalJoost.Layar.LayarService" %>

and rename this the file to "LayerService.svc". The third step is some WCF configuration in the web.config of your web application to host the service as a webHttpBinding, thus making it accept calls via http get:

<services>
  <service name="LocalJoost.Layar.LayarService">
    <endpoint address="" binding="webHttpBinding"
 behaviorConfiguration="WebHttpBehavior"
 contract="LocalJoost.Layar.ILayarService" 
 bindingNamespace="http://whatever/layar">
    </endpoint>
   </service>
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="WebHttpBehavior">
      <webHttp/>
    </behavior>
  </endpointBehaviors>
</behaviors>

The fourth step is to map your implementations of ILayarProvider to your layers. The LayerService class works in such a way that a layer maps directly to a Unity container, so a configuration might look like this:

<unity>
  <typeAliases>
   <typeAlias alias="ILayarProvider" 
        type="LocalJoost.ILayarProvider,LocalJoost.Layar"/>
   <typeAlias alias="SampleProvider" 
        type="SomeAssembly.SampleProvider,SomeAssembly"/>
   <typeAlias alias="AnotherProvider"
         type="SomeotherAssembly.AnotherProvider, SomeotherAssembly"/>
  </typeAliases>
  <containers>
   <container name="mylayer">
    <types>
     <type type="ILayarProvider" 
     mapTo="SampleProvider"/>
    </types>
   </container>
   <container name="someotherlayer">
    <types>
     <type type="ILayarProvider"
        mapTo="AnotherProvider"/>
    </types>
   </container>
  </containers>
</unity>

Here I have defined two sample containers, thus layers. If, for instance, your service is hosted as “http://mydomain.com/LayarServer/LayerService.svc” you can register your Layer with the Layar developer portal (which is, incidentally, the fifth step) as “http://mydomain.com/LayarServer/LayerService.svc/Layar/mylayer/” (mind the trailing slash!) and the framework will do the rest.

Now the sixth and final step is the real hard part: writing actual implementations of the ILayarProvider. This depends or what you are actually wanting to show. And this it where my help ends ;-).

18 July 2009

Calling a service relative to the Silverlight XAP (improved)

In my previous post I showed a way to call a service defined with a full path, as created by the designer, relative to that of the location of your XAP, by means of an extension to a user control. I developed that during a training and while blogging it I alreadly realized that there was room for improvement. And here it is:
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Windows;

namespace LocalJoost.Utilities.Silverlight
{
  public static class ServiceEndpointExtension
  {
    public static void MakeRelative(
      this ServiceEndpoint endpoint)
    {
      var clientbinLocation = 
        Application.Current.Host.Source.ToString().Substring(0,
        Application.Current.Host.Source.ToString().LastIndexOf("/"));
      var rootLocation = 
        clientbinLocation.Substring(0, 
        clientbinLocation.LastIndexOf("/"));
      endpoint.Address = new EndpointAddress(
        new Uri(string.Concat(rootLocation, 
          endpoint.Address.Uri.AbsolutePath)));
    }
  }
}
In stead of extending the user control I now extend the ServiceEndpoint. If you now want to call a service that is sitting in the root of your web application that is hosting you can call it like this:
var client = new CloudMapperDataServiceClient();
client.Endpoint.Address.MakeRelative();
Substitute "CloudMapperDataServiceClient" by your own client proxy class and you are go for launch (Sorry, currently listening to wechoosethemoon.org ;-)

15 July 2009

Calling a service relative to the Silverlight XAP

This post is deprecated and left here for link reference only. See this post or a better way to do this. A small tidbit that I developed when I was following a training by Dennis van der Stelt of Class-A. One of the assigments was to consume a service and display data. The lab contained a string with a hard coded path. I thought of the following, IMHO much cleaner solution. I also discovered that WCF services are defined in a ServiceReferences.ClientConfig that contains a full path to the service. That is not nice on deployment time. This may have been caused by the fact I hosted the Silverlight App in an Azure project, I am not sure yet. But anyhow, I made an extension method to the Silverlight System.Windows.Controls.Control like this
using System;
using System.ServiceModel;
using System.Windows;
using System.Windows.Controls;

namespace LocalJoost.Utilities.Silverlight
{
  public static class UserControlExtensions
  {
    public static EndpointAddress GetRelativeEndpointAdress(
      this UserControl control, string path)
    {
      var clientbinLocation = 
          Application.Current.Host.Source.ToString().Substring(0,
          Application.Current.Host.Source.ToString().LastIndexOf("/"));
      return new EndpointAddress(new Uri(string.Format("{0}/{1}",
        clientbinLocation.Substring(0,
        clientbinLocation.LastIndexOf("/")), path)));
    }
  }
}
If you now want to call a service that is sitting in the root of your web application that is hosting you can call it like this:
var client = new CloudMapperDataServiceClient();
client.Endpoint.Address = 
 this.GetRelativeEndpointAdress("CloudMapperDataService.svc");
Substitute "CloudMapperDataServiceClient" by your own client proxy class and "CloudMapperDataService.svc" by your own svc and you are ready to roll. Seeing this again while I blog it I think it might be even better to get the name of the svc from the original Endpoint.Address setting. Well, that's something for later

29 November 2008

Writing a simple HTTP proxy using WCF

I ran into a situation with the following network topology: The intranet server served PDF documents via IIS, but was only accessible from the WCF server - which, for technical and political reasons, could not run in IIS but had to be a Windows Managed service that hosted a WCF service. Yet I needed to be able to download files from the intranet server via an ordinary URL. It turns out that you can write a WCF service mimicking a HTTP server pretty easily. If you can utilize .NET 3.5SP1, that is. 1. Data contract There are few key points to the contract:
  • Make a reference to System.ServiceModel.Web.dll
  • Add a "using System.ServiceModel.Web"
  • Define a method returning a Stream
  • Decorate that method with a WebGet attribute
Your datacontract could look like this:
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace ProxyService
{
    /// 
    /// Service contract for a proxy that forwards a http request
    [ServiceContract]
    public interface IHttpProxy
    {
        [OperationContract, WebGet]
        Stream GetProxyRequest(string target);
    }
}
2. Implementation class This is basically a modified version of a solution based upon an ASP.NET page I described before.
using System.IO;
using System.Net;
using System.ServiceModel.Web;
using System.Web;

namespace ProxyService
{
    /// 
    /// A proxy that forwards a http request
    /// 
    public class HttpProxy : IHttpProxy
    {
        public Stream GetProxyRequest(string target)
        {
            var urlToLoadFrom = HttpUtility.UrlDecode(target);
            HttpWebRequest webRequest = 
               HttpWebRequest.Create(urlToLoadFrom) as HttpWebRequest;

            // Important! Keeps the request from blocking after the first
            // time!
            webRequest.KeepAlive = false;
            webRequest.Credentials = CredentialCache.DefaultCredentials;
            using (var backendResponse = 
              (HttpWebResponse)webRequest.GetResponse())
            {
                using (var receiveStream = 
                  backendResponse.GetResponseStream())
                {
                    var ms = new MemoryStream();
                    var response = 
                      WebOperationContext.Current.OutgoingResponse;
                    // Copy headers
                    // Check if header contains a contenth-lenght since IE
                    // goes bananas if this is missing
                    bool contentLenghtFound = false;
                    foreach (string header in backendResponse.Headers)
                    {
                        if (string.Compare(header, 
                          "CONTENT-LENGTH", true) == 0)
                        { 
                          contentLenghtFound = true;
                        }
                        response.Headers.Add(header, 
                          backendResponse.Headers[header]);
                    }

                    // Copy contents
                    var buff = new byte[1024];
                    var length = 0;
                    int bytes;
                    while ((bytes = receiveStream.Read(buff, 0, 1024)) > 0)
                    {
                        length += bytes;
                        ms.Write(buff, 0, bytes);
                    }

                    // Add contentlength if it is missing
                    if (!contentLenghtFound) response.ContentLength = length;

                    // Set the stream to the start
                    ms.Position = 0;
                    return ms;
                }
            }
        }
    }
}
3. Configuration settings To get it all to work, you will need some configuration settings in the App.config of the hosting application:
<system.serviceModel>
  <services>
    <service name="ProxyService.HttpProxy" >
      <endpoint address="" binding="webHttpBinding"
                behaviorConfiguration="WebHttpBehavior"
                contract="ProxyService.IHttpProxy" >
      </endpoint>

      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:8002/ProxyService.HttpProxy" />
        </baseAddresses>
      </host>
    </service>

  </services>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WebHttpBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
</system.serviceModel>
Notice the endpointBehaviors section: this is really important to get the stuff to work. 4. Using the proxy You can now simply enter "http://yourhost:8002/ProxyService.HttpProxy/GetProxyRequest?target=urlencodedurl" in your browser, and the WebGet attributes will automatically make the GetProxyRequest method get called with the value of target as value for the target parameter. The code of the proxy expects target to contain an URLEncoded URL (use HttpUtility.UrlEncode to encode the actual url to something that can be passed as a parameter on an URL). Concluding remarks The magic of the WebGet attribute is barely scratched by this example, but it makes creating REST services with WCF a real piece of cake. I am not sure if it was intended to be used this way, but it sure works like hell ;-)

20 October 2008

Turning off WCF security

Unlike ye goode ole ASMX web services, WCF comes by default with security enabled. That's a good thing: Microsoft now believes in security being integral part of the solution, so in stead of slapping it on later, it is turned on by default. This is fine of course in distributed production environments but may be a real PITA while testing or deploying in a simple point-to-point enviroment, especially when machines are not in the same domain. Fortunately, turning all these gizmos off is quite easy. The catch is that settings on server and client must exactly match You host the service like this (provided it is hosted in IIS)
<system.serviceModel>
  <services>
    <service name="MyService">
      <endpoint contract="IMyService" binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConfiguration"/>
    </service>
  </services>
  <bindings>
    <wsHttpBinding>
      <binding name="wsHttpBindingConfiguration">
       <security mode="None">
          <message clientCredentialType="None"/>
          <transport clientCredentialType="None"/>
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
</system.serviceModel>
and you configure the client like this
<system.serviceModel>
  <client>
    <endpoint name="MyDataPortal"
              address="http://someserver:2000/MyRoot/MyService.svc"
              binding="wsHttpBinding"
              contract="IMyService"
              bindingConfiguration="MyBinding"/>
  </client>

  <bindings>
    <wsHttpBinding>
      <binding name="MyBinding">
        <security mode="None">
          <message clientCredentialType="None"/>
          <transport clientCredentialType="None"/>
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
</system.serviceModel>
I emphasized the important parts. Be advised: these settings should only be used in either development environments or enviroments that are inherently safe by themselves, i.e. closed networks.

23 February 2008

Calling a WCF service from Javascript

Note - I wrote this a long time ago. While the information in this article is still valid, nowadays I would use ASP.NET MVC 4 WebAPI on the server, and jQuery on the client to do something like this. I will blog about this soon.

In a previous post I pointed out how to call an ASP.NET ASMX web service from javascript in the browser. Although this still works fine, the world has moved on to .NET 3.5 and WCF services have now replaced ASMX services. Luckily, these are also callable from javascript although the procedure is now a little bit different. In this sample I presume you can use Visual Studio 2008 and know a little about WCF.

1. Create an empty solution, and add a WCF service library to it

We'll call the solution JSONWCFTest, and the library JSONServices.

2. Add a data contract

using System.Collections.Generic;
using System.Runtime.Serialization;

namespace JSONServices
{
 [DataContract]
 public class SampleDataObject
 {
   public SampleDataObject(int NewId, string NewName)
   {
     Id = NewId;
     Name = NewName;
   }
   [DataMember]
   public int Id { get; set; }

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

3. Add service contract

Add an interface IJSONService with the following methods using System.Collections.Generic; using System.ServiceModel;
namespace JSONServices
{
 [ServiceContract(Namespace="http://DotNetByExample/JSONDemoService")]
 public interface IJSONService
 {
   [OperationContract]
   SampleDataObject GetSingleObject(int id, string name);

   [OperationContract]
   ICollection GetMultipleObjects(int number);
 }
}

4. Add an implementing class

Implement the service contract like this
System.Collections.Generic;

namespace JSONServices
{
 public class JSONService : IJSONService
 {
   public SampleDataObject GetSingleObject(int id, string name)
   {
     return new SampleDataObject(id, name);
   }

   public ICollection<SampleDataObject> GetMultipleObjects(int number)
   {
     List<SampleDataObject> list = new List<SampleDataObject>();
     for (int i = 0; i < number; i++)
     {
       list.Add(new SampleDataObject(i, "Name" + i));
     }
     return list;
   }
 }
}
So far, this is very basic WCF stuff. Nothing special here.

5. Add new web application

Add a new project of type "ASP.NET Web Application" to the solution. Call it JSONTestApp. Add a reference to the JSONWCFTest project.

6. Add a SVC file to the web application

This part is a bit awkward. Choose "Text File", and name it "AjaxService.svc". Then open the file, and enter the following code
<%@ServiceHost language="C#" debug="true"
Service="JSONServices.JSONService"
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"%>
It may be tempting to add an "Ajax-enabled WCF service" to the project but this creates its own operation contract, and in this example I want to simulate the situation in which I re-use an already existing operation contract implemented in a separate service library.

7. Check the javascript interface

Basically, you are done now. Your service is hosted callable from javascript. You can check right-clicking on AjaxService.svc, and you will now see a web page that will say something like "This is a Windows© Communication Foundation service. Metadata publishing for this service is currently disabled." and a lot things more. You can check the javascript interface by adding "/jsdebug" to the url displayed in your browser, in my case this is "http://localhost:1781/AjaxService.svc/jsdebug". This shows the dynamically generated javascript proxy that you can call in your client code:
Type.registerNamespace('dotnetbyexample.JSONDemoService');
dotnetbyexample.JSONDemoService.IJSONService=function() {
dotnetbyexample.JSONDemoService.IJSONService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
dotnetbyexample.JSONDemoService.IJSONService.prototype={
_get_path:function() {
var p = this.get_path();
if (p) return p;
else return dotnetbyexample.JSONDemoService.IJSONService._staticInstance.get_path();},
GetSingleObject:function(id,name,succeededCallback, failedCallback, userContext) {
/// <param name="id" type="Number">System.Int32</param>
/// <param name="name" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'GetSingleObject',false,{id:id,name:name},succeededCallback,failedCallback,userContext); },
GetMultipleObjects:function(number,succeededCallback, failedCallback, userContext) {
/// <param name="number" type="Number">System.Int32</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" TomayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
Note: FireFox displays the javascript directly in the browser; for security reasons, Internet Explorer wants to download it to a file rather than display it, but after saving it and opening it in a text editor you will see the text above. As you can see this contains a lot of plumbing - and this is only the top part - but I emphasized the parts that are interesting right now: the name of the object that you need to call from javascript (dotnetbyexample.JSONDemoService.IJSONService) and the methods, which have - surprise, suprise - exactly the same name as their C# server-side counterparts. From here on, the procedure is pretty much the same as we were used to when calling asmx webservices from javascript:

8. Add an Web Form to the Web Application

Call it TestForm1.aspx

9. Add a script manager and a reference

Add a script manager to the form, right below the form tag, and make a reference to the AjaxService.svc file:

<form id="form1" runat="server">
<asp:scriptmanager runat="server">
<services>
<asp:ServiceReference Path="AjaxService.svc" />
</services>
</asp:scriptmanager>

10. Add some user interface elements to call the service

Right below the script reference, add the following code:
<div>
ID<asp:TextBox ID="tbId" runat="server">21</asp:TextBox>
Name<asp:TextBox ID="tbName" runat="server">John Doe</asp:TextBox><br />
<asp:Button ID="btnSelect" runat="server" Text="SingleSelect"
   UseSubmitBehavior="False"  OnClientClick="CallSingle(); return false;"/>
</div>
<div id="result1"></div>

11. Add Javascript code

Add some javascript code to call the WCF service and process the results. Place this inside the head-tag, below the title tag:
<script type ="text/javascript">
function CallSingle()
{
dotnetbyexample.JSONDemoService.IJSONService.GetSingleObject(
    document.getElementById("tbId").value,
    document.getElementById("tbName").value,
    CallBackSingle );
}
function CallBackSingle( WebServiceResult )
{
resultDiv = document.getElementById("result1");
resultDiv.innerHTML = "You entered: id = " +
 WebServiceResult.Id + " name = " +
 WebServiceResult.Name;
}
</script>
Notice again that calling a WCF method from javascript works the same as when using asmx services: one extra parameter at the end of the list is required, which is the callback. This is a function that is called upon receiving the result from the server - the server method result is put into the single parameter of the callback.

12. Run the test page

Run Test1Form.aspx. You should be able to input and numerical id and a alphanumeric name, which are sent to the server, and returned back to you as and SampleObject.

13. Deploying WCF services in IIS

This all works fine when running it in Cassini, but when you want to host it in IIS, you will need to take care two things. First, you will need to ensure that IIS and WCF are correctly installed and registered. If IIS does not seem to want to cough up your SVC files (you can check that by trying http://<your host here>/<your sitename here>/AjaxService.svc), try running the command ServiceModelReg.exe /i /x from %WINDIR%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation. Restart IIS after running this command. Second, if you created a default ASP.NET 2.0 website, you may run into this error message:
IIS specified authentication schemes 'IntegratedWindowsAuthentication, Anonymous', but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used.
To fix this, right-click the website in your IIS manager and choose "properties". Then click the "Directory" tab, click the "Edit" button in the "Anonymous access and authentication control" area. You will see that both Anonymous access and Integrated Windows Authentication are selected. Unselect one of them, then restart IIS. After that, the application should work smoothly.

Concluding remarks

Calling WCF services from javascript is even simpler than calling asmx services - you don't even have to mark a service as [ScriptService] anymore, you just put an .svc file into your web site with four lines of code, make a reference to an existing service library and you're done. The sample described here does not use the IJSONService.GetMultipleObjects method, but you can download a the complete source code which includes a second test page that does. Notice that although GetMultipleObjects returns a ICollection, in javascript this is translated into a simple array. Thus, you can also use data and operation contract that use generic types, as long as the can simply be translated into an array. Oh - and don't forget to remove "debug=true" from "AjaxService.svc" before publishing it on production. Complete code downloadable here. Author's note: this article is my most viewed posting by far: 20% the traffic of my blog goes to this page. Apparently it meets a growing need in knowlegde. Please spread the word, (and the link) and if you find any errors of have any additions, let me know. Compliments are appreciated as well.