Simple OData WCF Data Services Example

With WCF Data Services (formerly known as ADO.NET Data Services) we can publish any datasource with one or more IQueryable properties to the web. By using a with the Open Data Protocol (OData) formatted url we can query, update, insert and delete data from and to the database. The data output is lightweight AtomPub or JSON, instead of SOAP.

In this example we use the Hotels database from previous examples this time accessed with the Entity Framework. To host the WCF Data Service we need an ASP.NET Web Application. We call it HotelData in this case. To this ASP.NET site we add a new WCF Data Service called Service.svc. We add a reference to our Entity Framework project.

We open the Service.svc file and configure the DataService initialization with the Entity Framework ObjectContext we want to use; in this case HotelEntities.In the InitializeService method we specify the access rules for the entities we want to expose. In our example we only want to read some hotel and city data, so we set the SetEntitySetAccessRule to AllRead for both entities.

using System.Data.Services;
using System.Data.Services.Common;
using Remondo.Entities;
 
namespace HotelData
{
    public class Service : DataService<HotelEntities>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("Hotels", EntitySetRights.AllRead);
            config.SetEntitySetAccessRule("Cities", EntitySetRights.AllRead);
 
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }
}

Since we do not have a repository in the example, we need to copy the connection string from our Entity Framework project to the Web.config of our ASP.NET Website. And we’re done… ;-)

<configuration>
  <connectionStrings>
    <add name="HotelEntities" connectionString="metadata=res://*/DataModel.csdl|r .....
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
</configuration>

If we browse to the Service.svc on our website we get an AtomPub Workspace with links to our published collections; Hotels and Cities.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
 
<service xml:base="http://localhost:11017/Service.svc/" 
         xmlns:atom="http://www.w3.org/2005/Atom"
         xmlns:app="http://www.w3.org/2007/app" 
         xmlns="http://www.w3.org/2007/app">
 
  <workspace>
    <atom:title>Default</atom:title>
    <collection href="Cities">
      <atom:title>Cities</atom:title>
    </collection>
    <collection href="Hotels">
      <atom:title>Hotels</atom:title>
    </collection>
  </workspace>
</service>

From there we can go to a specific entity, lets say, a City with an ID of 2 by browsing to http://[servername]/Service.svc/Cities(2). This City happens to be Amsterdam.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
 
<entry xml:base="http://localhost:11017/Service.svc/" 
       xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
       xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
       xmlns="http://www.w3.org/2005/Atom">
  
  <id>http://localhost:11017/Service.svc/Cities(2)</id>
  <title type="text"></title>
  <updated>2012-04-15T10:55:52Z</updated>
  <author>
    <name />
  </author>
  <link rel="edit" title="City" href="Cities(2)" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Hotels" 
        type="application/atom+xml;type=feed" 
        title="Hotels" 
        href="Cities(2)/Hotels" />
  
  <category term="RemondoModel.City"
            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <content type="application/xml">
    <m:properties>
      <d:ID m:type="Edm.Int32">2</d:ID>
      <d:Name>Amsterdam</d:Name>
    </m:properties>
  </content>
</entry>

The highlighted url above is an association from City to Hotels. So browsing to this link gives us an Atom feed with a resultset of all the hotels in Amsterdam stored in the database. We have only three hotels registered in this city, being Hotel de L’Europe, The Exchange and the InterContinental Amstel.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes"?>
 
<feed xml:base="http://localhost:10013/Hotel.svc/" 
      xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
      xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
      xmlns="http://www.w3.org/2005/Atom">
  
  <title type="text">Hotels</title>
  <id>http://localhost:10013/Hotel.svc/Cities(2)/Hotels</id>
  <updated>2012-04-15T11:03:38Z</updated>
  <link rel="self" title="Hotels" href="Hotels" />
  <entry>
    <id>http://localhost:10013/Hotel.svc/Hotels(5)</id>
    <title type="text"></title>
    <updated>2012-04-15T11:03:38Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Hotel" href="Hotels(5)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/City" 
          type="application/atom+xml;type=entry" 
          title="City" href="Hotels(5)/City" />
    <category term="RemondoModel.Hotel" 
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">5</d:ID>
        <d:Name>Hotel de L'Europe</d:Name>
        <d:City_ID m:type="Edm.Int32">2</d:City_ID>
        <d:Stars m:type="Edm.Int32">5</d:Stars>
      </m:properties>
    </content>
  </entry>
  <entry>
    <id>http://localhost:10013/Hotel.svc/Hotels(7)</id>
    <title type="text"></title>
    <updated>2012-04-15T11:03:38Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Hotel" href="Hotels(7)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/City" 
          type="application/atom+xml;type=entry" 
          title="City" href="Hotels(7)/City" />
    <category term="RemondoModel.Hotel" 
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">7</d:ID>
        <d:Name>The Exchange</d:Name>
        <d:City_ID m:type="Edm.Int32">2</d:City_ID>
        <d:Stars m:type="Edm.Int32">4</d:Stars>
      </m:properties>
    </content>
  </entry>
  <entry>
    <id>http://localhost:10013/Hotel.svc/Hotels(8)</id>
    <title type="text"></title>
    <updated>2012-04-15T11:03:38Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="Hotel" href="Hotels(8)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/City" 
          type="application/atom+xml;type=entry" 
          title="City" href="Hotels(8)/City" />
    <category term="RemondoModel.Hotel" 
              scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:ID m:type="Edm.Int32">8</d:ID>
        <d:Name>InterContinental Amstel</d:Name>
        <d:City_ID m:type="Edm.Int32">2</d:City_ID>
        <d:Stars m:type="Edm.Int32">4</d:Stars>
      </m:properties>
    </content>
  </entry>
</feed>

Of course there’s a lot more we can do with OData and WCF Data Services, but these are the basics.

Simple RESTful Service with WFC

Representational State Transfer (REST) is a Resource Oriented Architecture (ROA) style based on the existing design of HTTP. We call resources instead of operations (as we do with SOAP). REST has a hypertext driven API with a predefined set of operations (GET, PUT, POST, or DELETE) for each uri. The message format for REST in WCF is XML by default, but the current implementation can produce HTML, RSS and JSON as well.

In this example we publish a simple RESTful todolist webservice for handling TodoItems.

using System;
using System.Runtime.Serialization;
 
namespace WcfServiceLibrary.Todo
{
    [DataContract(Namespace = "http://www.remondo.net/services")]
    public class TodoItem : ITodoItem
    {
        public TodoItem()
        {
            DateCreated = DateTime.Now;
        }
 
        #region ITodoItem Members
 
        [DataMember]
        public int Id { get; set; }
 
        [DataMember]
        public DateTime DateAdded { get; set; }
 
        [DataMember]
        public DateTime DateCreated { get; set; }
 
        [DataMember]
        public string Title { get; set; }
 
        #endregion
    }
}

The service only handles some basic operations: Add, Delete and List. The WebGet attribute enables a GET request on the specified UriTemplate (mapped to the operation from the base address). For operations other than GET the attribute WebInvoke is used, explicitly specifying the method to use.

using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
 
namespace WcfServiceLibrary.Todo
{
    [ServiceContract]
    public interface ITodoService
    {
        [WebGet(UriTemplate = "/list")]
        [OperationContract]
        List<TodoItem> GetAll();
        
        [WebInvoke(UriTemplate = "/add", Method = "POST")]
        [OperationContract]
        TodoItem Add(TodoItem todoItem);
 
        [WebInvoke(UriTemplate = "/delete?id={todoItemId}",
            Method = "DELETE")]
        [OperationContract]
        void Delete(int todoItemId);
    }
}

The TodoService has a pretty straightforward implementation to handle these mapped operations.

using System;
using System.Collections.Generic;
using System.ServiceModel;
 
namespace WcfServiceLibrary.Todo
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class TodoService : ITodoService
    {
        private readonly List<TodoItem> _todoItems;
        private int _lastId;
 
        public TodoService()
        {
            _todoItems = new List<TodoItem>();
        }
 
        public TodoService(List<TodoItem> todoItems)
        {
            _todoItems = todoItems;
        }
 
        #region ITodoService Members
 
        public TodoItem Add(TodoItem todoItem)
        {
            todoItem.DateAdded = DateTime.Now;
            todoItem.Id = _lastId++;
            _todoItems.Add(todoItem);
 
            return todoItem;
        }
 
        public List<TodoItem> GetAll()
        {
            return _todoItems;
        }
 
        public void Delete(int todoItemId)
        {
            TodoItem todoItem =
                _todoItems.Find(ti => ti.Id == todoItemId);
 
            _todoItems.Remove(todoItem);
        }
 
        #endregion
    }
}

Hosting the TodoService in a Console App is a breeze by using the WebServiceHost class.

using System;
using System.ServiceModel.Web;
using WcfServiceLibrary.Todo;
 
namespace TodoSelfHostConsole
{
    internal class Program
    {
        private static void Main()
        {
            var host = new WebServiceHost(
                typeof (TodoService),
                new Uri("http://localhost:8080/todo"));
 
            try
            {
                host.Open();
                Console.ReadLine();
                host.Close();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
                Console.ReadLine();
                host.Abort();
            }
        }
    }
}

Finally we can consume the REST webservice by using the WebChannelFactory to create a TodoService channel. From this channel we can call Add, Delete and List.

using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using WcfServiceLibrary.Todo;
 
namespace TodoClientConsole
{
    internal class Program
    {
        private static void Main()
        {
            var channelFactory = new WebChannelFactory<ITodoService>(
                new Uri("http://localhost:8080/todo")
                );
 
            ITodoService channel = channelFactory.CreateChannel();
 
            var todoItem1 = new TodoItem {Title = "Feed the cat"};
            var todoItem2 = new TodoItem {Title = "Paint the house"};
            var todoItem3 = new TodoItem {Title = "Call your mother"};
            var todoItem4 = new TodoItem {Title = "DELETE me"};
 
            channel.Add(todoItem1);
            channel.Add(todoItem2);
            channel.Add(todoItem3);
 
            TodoItem todoItemToDelete = channel.Add(todoItem4);
            channel.Delete(todoItemToDelete.Id);
 
            foreach (TodoItem todoItem in channel.GetAll())
            {
                Console.WriteLine("Id {0}: {1}",
                                  todoItem.Id,
                                  todoItem.Title);
            }
 
            Console.ReadLine();
            ((IClientChannel) channel).Close();
        }
    }
}

WCF REST Todo Client Console

Pointing a browser at the TodoService list resource gives the XML representation of the TodoList.

WCF REST Todo List Web Browser

Simple WCF Binding Configuration example

In the previous post we moved the config code into a App.config file. Now let’s configure the bindings for the EchoService. A WCF binding for a Service Endpoint, combines the transport protocol (MSMQ, HTTP, TCP…), message format (JSON, XML, MTOM…) and message protocol (none, WS, SOAP…). WCF ships with the most common binding scenarios and a CustomBinding for creating your own binding. Here’s an overview of the most common configuration elements.

Configuration Element Description

<basicHttpBinding>

Basic SOAP like ASP.NET Web services (ASMX)-based services.

<wsHttpBinding>

Full fledged SOAP and WS protocols

<netNamedPipeBinding>

Named Pipes. A secure, reliable, optimized binding that is suitable for on-machine communication between WCF applications.

<netMsmqBinding>

MSMQ. A queued binding that is suitable for cross-machine communication between WCF applications.

<netPeerTcpBinding>

TCP peer-to-peer. Secure, multi-machine communication.

<webHttpBinding>

RESTful web service.

The configuration example of the EchoService sets the BasicHttpSecurityMode to Transport. This sends all service communication over SSL/HTTPS, so the service need some kind of SSL certificate (not shown here).

<?xml version="1.0" encoding="utf-8"?>
 
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBindingConfig">
          <security mode="Transport">
            <transport clientCredentialType="Certificate" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="BehaviourMetaData">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="BehaviourMetaData" 
               name="WcfServiceLibrary.Echo.EchoService">
        <endpoint address="http://localhost:8080/EchoService" 
                  binding="basicHttpBinding"
                  contract="WcfServiceLibrary.Echo.IEchoService" 
                  bindingConfiguration="BasicHttpBindingConfig" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

Getting started with NoSQL and Raven DB

I started playing around with Raven DB today. Raven DB is a document database, also knows as non-relational, cloud or NoSQL database. It stores schema-less JSON documents/objects (nice).

Raven is an Open Source (with a commercial option) document database for the .NET/Windows platform. Raven offers a flexible data model design to fit the needs of real world systems. Raven stores schema-less JSON documents, allow you to define indexes using Linq queries and focus on low latency and high performance.

Time for a little documentation on my first steps towards NoSQL guruship. Let’s install Raven DB first. We need to download the latest build in a zip file. Unzip it somewhere and start Raven by executing Start.cmd.

The Raven DB command window and Studio start up. By default, Raven DB is listening on port 8080.

One empty index is created by default as you can see here in Raven Studio.

Let’s fire up Visual Studio and create a new Console Application. To add Raven DB functionality to our project, we need to add a reference to Raven.Client.Lightweight.dll found in the RavenDB/Client directory.

To store and Load documents/objects from the database, we simply add code like the one below. Given a Person class we add Friends to the persons friend list and store it in the database. Later we retrieve and output the contents of the Name, Age and Friends properties.

using System;
using System.Collections.Generic;
using Raven.Client;
using Raven.Client.Document;
 
namespace RavenDbPlayground
{
    class Program
    {
        static void Main(string[] args)
        {
            var store =
                new DocumentStore { Url = "http://l040:8080" };
            store.Initialize();
 
            using (IDocumentSession session = store.OpenSession())
            {
                StorePerson(session);
                LoadPerson(session);
            }
        }
 
        private static void StorePerson(IDocumentSession session)
        {
            Person leon = new Person { Name = "Leon", Age = 42 };
            Person manon = new Person { Name = "Manon", Age = 40 };
            
            session.Store(leon);
            session.Store(manon);
 
            leon.Friends.Add(manon.Id);
            manon.Friends.Add(leon.Id);
 
            session.Store(leon);
            session.Store(manon);
 
            session.SaveChanges();
        }
 
        private static void LoadPerson(IDocumentSession session)
        {
            Person leon = session.Load<Person>("people/1");
            Console.WriteLine(
                "Person: {0}, age {1}", leon.Name, leon.Age);
 
            foreach (var friendId in leon.Friends)
            {
                Person friend = session.Load<Person>(friendId);
                Console.WriteLine(
                    "Friend: {0}, age {1}", friend.Name, friend.Age);
            }           
 
            session.SaveChanges();
            Console.ReadLine();
        }
    }
 
    public class Person
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public List<string> Friends { get; set; }
 
        public Person()
        {
            Friends = new List<string>();
        }
    }
}

Et voila :-)

Calling a WCF Service from jQuery

For this example I build a simple WCF service that registers your mood for today in a MoodLog; called Moodr. There are five different mood states, with corresponding emoticons in the database. I use the Entity Framework for my Moodr model.

Each entity gets his own Repository class and a corresponding Data Transfer Object (DTO) class. DTOs are used as return types between the webservice and the AJAX client.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Moodr.Repositories
{
    public class MoodLogRepository
    {
        public static void UpsertMoodLog(MoodLog moodLog)
        {
            var context = new MoodrEntities();
            var today = DateTime.Now.Date;
            var query = from l in context.MoodLogs 
                        where l.Date == today select l;
 
            if (query.Any())
            {
                var existingMoodLog = query.First();
                existingMoodLog.MoodId = moodLog.MoodId;
            }
            else
            {
                context.MoodLogs.AddObject(moodLog);
            }
 
            context.SaveChanges();
        }
 
        public static IEnumerable<DtoMoodLog> GetAll()
        {
            var context = new MoodrEntities();
            var query = from l in context.MoodLogs
                        orderby l.Date descending
                        select new DtoMoodLog
                        {
                            Date = l.Date,
                            Emoticon = new DtoEmoticon
                            {
                                Symbol = l.Mood.Emoticon.Symbol,
                            }
                        };
 
            return query.ToList();
        }
    }
 
    public class DtoMoodLog
    {
        public DateTime Date { get; set; }
        public DtoEmoticon Emoticon { get; set; }
    }
}

The Moodr WCF service has two methods for retrieving Mood (GetMoods) and MoodLog (GetMoodLogs) data, and one to store the mood of the day (WriteMoodLog) accepting a moodId parameter.

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Moodr.Repositories;
 
namespace Moodr
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode = 
        AspNetCompatibilityRequirementsMode.Allowed)]
    public class MoodrService
    {
        [OperationContract]
        [WebGet(RequestFormat = WebMessageFormat.Json)]
        public IEnumerable<DtoMood> GetMoods()
        {
            var result = MoodRepository.GetAll();
 
            return result;
        }
 
        [OperationContract]
        [WebGet(RequestFormat = WebMessageFormat.Json)]
        public void WriteMoodLog(int moodId)
        {
            try
            {
                MoodLog moodLog = new MoodLog 
                { 
                    MoodId = moodId, 
                    Date = DateTime.Now 
                };
 
                MoodLogRepository.UpsertMoodLog(moodLog);
            }
            catch (Exception)
            {
                WebOperationContext.Current.OutgoingResponse.StatusCode = 
                    System.Net.HttpStatusCode.NotAcceptable;
            }
        }
 
        [OperationContract]
        [WebGet(RequestFormat = WebMessageFormat.Json)]
        public IEnumerable<DtoMoodLog> GetMoodLogs()
        {
            var result = MoodLogRepository.GetAll();
 
            return result;
        }
    }
}

Finally some jQuery magic behind the scene to wire it all up.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="Moodr._Default" %>
 
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $.ajax({
                type: "GET",
                url: '/MoodrService.svc/GetMoods',
                dataType: 'json',
                contentType: "application/json; charset=utf-8",
                success: function (moodList) {
                    var moodPicker = $('div#MoodPicker');
                    $(moodList.d).each(function () {
                        moodPicker.html(moodPicker.html() +
                            "<input type='radio' name='moodradio' id='moodradio'" +
                                this.ID + " value=" + this.ID + " />" +
                            "<label for='moodradio'" + this.ID + ">" +
                                this.Name + "</label><br/>"
                        );
                    });
                },
                error: onError
            });
 
            $('#enterButton').click(function () {
                var checkedMood = $('input[name=moodradio]:checked');
                $.ajax({
                    type: "GET",
                    url: '/MoodrService.svc/WriteMoodLog',
                    data: { 'moodId': checkedMood.val() },
                    dataType: 'json',
                    contentType: "application/json; charset=utf-8",
                    success: function (moodLogList) {
                        var MoodLogs = $('div#MoodLogs');
                        MoodLogs.html('Your mood the last ' + $(moodLogList.d).length + ' days<br/><table>');
                        $(moodLogList.d).each(function () {
                            MoodLogs.append(
                            "<tr><td>" + this.Emoticon.Symbol +
                            "</td></tr/>");
                        });
                        MoodLogs.append('</table>');
                        $('#resultDiv').html('So you feel ' + checkedMood.next().text());
                    },
                    error: onError
                });
            });
        });
 
        function onError(error) {
            alert("Error: " + error.status);
        }
    </script>
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <div id="MoodPicker">
    </div>
    <br />
    <div>
        <input id='enterButton' type='button' value='Enter mood' />
        <span id="resultDiv"></span>
    </div>
    <hr />
    <div id="MoodLogs"></div>
</asp:Content>


 

Explicit JSON serialization with DataContractJsonSerializer

If you somehow need to serialize a CLR object to JSON in your Microsoft .Net project, you can use the DataContractJsonSerializer. For this snippet you need to reference System.Runtime.Serialization and System.Servicemodel.Web.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
 
namespace ConsoleExplicitJson
{
    class Program
    {
        static void Main(string[] args)
        {
            Garage garage = new Garage();
 
            garage.Cars.Add(new Car
            {
                Name = "Saab",
                Color = "Red",
                PurchaseDate = new DateTime(1975, 4, 12)
            });
            garage.Cars.Add(new Car
            {
                Name = "Opel",
                Color = "Blue",
                PurchaseDate = new DateTime(1988, 9, 4)
            });
            garage.Cars.Add(new Car
            {
                Name = "Fiat",
                Color = "Silver metalic",
                PurchaseDate = new DateTime(1999, 2, 21)
            });
            garage.Opened = true;
 
            DataContractJsonSerializer jsonSerializer =
                new DataContractJsonSerializer(typeof(Garage));
 
            MemoryStream memoryStream = new MemoryStream();
            jsonSerializer.WriteObject(memoryStream, garage);
            memoryStream.Flush();
            memoryStream.Position = 0;
            StreamReader streamReader = new StreamReader(memoryStream);
 
            string jsonGarage = streamReader.ReadToEnd();
 
            // Returns the object in JSON:
            //
            //	{"Cars":
            //		[
            //			{"Color":"Red","Name":"Saab",
            //				"PurchaseDate":"\/Date(166485600000+0200)\/"},
            //			{"Color":"Blue","Name":"Opel",
            //				"PurchaseDate":"\/Date(589327200000+0200)\/"},
            //			{"Color":"Silver metalic","Name":"Fiat",
            //				"PurchaseDate":"\/Date(919551600000+0100)\/"}
            //		],
            //	"Opened":true}
 
        }
    }
 
    [DataContract]
    class Car
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Color { get; set; }
        [DataMember]
        public DateTime PurchaseDate { get; set; }
    }
 
    [DataContract]
    class Garage
    {
        public Garage()
        {
            Cars = new List<Car>();
        }
 
        [DataMember]
        public List<Car> Cars { get; set; }
        [DataMember]
        public bool Opened { get; set; }
    }
}

Create a simple Ajax enabled WCF service in ASP.Net

To create a simple WCF service callable from client side AJAX script, first add a new WCF item to your project called “AJAX-enabled WCF Service”. For the purpose of this tutorial I’ll create a birthday service. Given a name the service returns a date of birth if found. See this simple implementation in the BirthdayService.svc. The namespace provided can be anything you want. To expose the method in the webservice give it the [OperationContract] attribute.

using System.ServiceModel;
using System.ServiceModel.Activation;
 
namespace AjaxWeb
{
    [ServiceContract(Namespace = "http://remondo/ws/")]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class BirthdayService
    {
        [OperationContract]
        public string GetDateOfBirthFor(string name)
        {
            string result;
 
            switch (name)
            {
                case "Leon":
                    result = "March 29, 1969";
                    break;
                case "Manon":
                    result = "January 13, 1972";
                    break;
                case "Curry":
                    result = "August 24, 2011";
                    break;
                default:
                    result = "I don't know this person";
                    break;
            }
 
            return result;
        }
    }
}

Add a ScriptManager component to the Default.aspx and a ServiceReference to our BirthdayService. Now add a textbox to input a name and a submit button to call the webservice. Put a blank div in the page to show the result coming back from the webservice.

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ScriptManager ID="ScriptManager" runat="server">
        <Services>
            <asp:ServiceReference Path="~/BirthdayService.svc" />
        </Services>
    </asp:ScriptManager>
    <h2>
        Get the birthday!
    </h2>
    <input id="callServiceWithText" type="text" />
    <input id="callServiceButton" type="button" value="Call webservice" onclick="onCallService()" />
    <hr />
    <div id="outputService">
    </div>
</asp:Content>

Let’s hook up our service to the pagecontrols with some JavaScript in the head section. The onCallService() function gets called by the submit button and calls the webservice with the contents of our callServiceWithText textbox. Prefix the whole namespace to call the method on our webservice; “remondo.ws.BirthdayService.GetBirthDateFor” and pass it the value of our textbox. Since this is an async call you need to provide a completion-function to handle the result and an error-function to handle errors if they occur. This is what the onCallServiceComplete and onCallServiceError are for. We provide the inputText yet another time in the call, to get out initial value back from the webservice.

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
    <script type="text/javascript">
 
        function onCallService() {
            var inputText = $get("callServiceWithText").value;
            remondo.ws.BirthdayService.GetDateOfBirthFor(
                inputText, onCallServiceComplete, onCallServiceError, inputText);
        }
 
        function onCallServiceComplete(result, inputText) {
            $get("outputService").innerHTML = "Search for " + inputText + " returns " + result;
        }
 
        function onCallServiceError(error) {
            alert(error.get_message());
        }
 
    </script>
</asp:Content>

And we’re good to go… let’s query Manon’s day of birth.