JSON-Enabled WCF Services (Part 1)

Sergey Piskov

In my work I often get task to develop Rich Internet Application. After such task I have a terrible headache with the choice of technology. The two most used ones are Silverlight and Flash. But the question which is better comes up; and it is very hard to objectively consider all pros and cons of them. Both of them are cross-platform technologies, so the application, created on Silverlight or Flash, will look the same in all browsers.

But, unfortunately, nothing is perfect… These technologies have one serious (to my mind) disadvantage: they are limited in use. This means that you won’t be able to fully use Silverlight application on Linux or Flash application on iOS. I even don’t mention mobile systems that are essential part of our life. Majority of up-to-date mobiles and pads don’t provide full support for Silverlight and Flash.

At the same time, the use of HTML and JavaScript in applications allows you to avoid problems with compatibility. All you need to work with such applications is web browser, which is available for all OS and mobiles. And various JavaScript libraries and frameworks make your application functionality as good as Silverlight and Flash ones.

But, I won’t reason of advantages and disadvantages of all these technologies. There are a lot of articles on this topic in the internet and it is up to you to choose the best one as it was in one of our projects.

In one of our projects (PerpetuumSoft products), we decided to use the HTML+JavaScript binding as a client part of an application. The client’s application interacts with server to get data. It is possible to use WCF service, the controllers which MVC framework provides and Web Handlers as a service. In this case, we need to use general format of data with which the client’s application and the service will interact. So, we had to choose what to use: XML or JSON. And we decided to use JSON. We had several reasons which determined the use of JSON:

  1. it is more compact than XML and is more convenient for serialization of complex structures;
  2. it is a subset of JavaScript language’s syntax and can be quickly deserialized by the embedded eval() function;
  3. it is easy to set up controllers and webhandlers for receiving and passing the data in the JSON format.

Now, I will speak about how to create the WCF service which passes data in the JSON format.

The first step is to add the WCF service to web site.
Select WCF Service in the Add New Item dialog window (I add the service with the WcfJsonService name). After this the WcfJsonService.svc file is added to the application, and also two more files:IWcfJsonService.cs and WcfJsonService.svc.cs.

Let’s start from the files added to the project. The IWcfJsonService.cs file defines the interface implemented by the service. It contains attributes which specifies to WCF how to use the service. The implementation of the service is described on the code-behind file (WcfJsonService.svc.cs). This file is added to the .svc file. You can use both these files, but I prefer to remove them. Instead of these files, I create a library of classes. This library contains interface and service implementation. As a result, this is the more convenient way to manage the code of your WCF services, because of:

  1. flexibility during the addition of the other providers which implement service interface;
  2. easy creation of unit tests.

Further, you will see that such way doesn’t complicate the development, but just requires the addition of reference to the library with the class.

We need to change the .svc file to correctly implement our service. Here is the example of directive which is created in the .svc file by default:

<%@ ServiceHost Language=”C#” Debug=”true” Service=”WebApplication.WcfJsonService” CodeBehind=”WcfJsonService.svc.cs” %>

And below you can see a new version of directive. This directive indicates which class is used for the service implementation. The WebScriptServiceHostFactory (http://msdn.microsoft.com/en-us/library/bb336135.aspx) class is indicated for the factory. This class allows the use of web protocols and adds the JSON serialization which is needed for the work of the service with jQuery Ajax:

<%@ ServiceHost Language=”C#” Debug=”true” Service=”WCFImplementation.ContinentsPopulation” Factory=”System.ServiceModel.Activation.WebScriptServiceHostFactory”%>

The next step is to add a class for the service implementation.
The first file which I add is the service interface. In my example, I display a list of continents with population size. And I name this service interface: IContinentsPopulation.cs. It is necessary to define a contract for the service. I mark my interface with the ServiceContract attribute. The WCF attributes are located in the System.ServiceModel namespace and I need to add a reference to it.

[ServiceContract]
public interface IContinentsPopulation

Now, I can add signatures of methods to the interface. I add two methods for the application: GetContinents which gets a list of continents with population; and GetContinentDetails which returns data for the continent with specified name. Below you can see the methods description:

[OperationContract(Name = "GetContinents")]
ContinentsListResponse GetContinents();

[OperationContract(Name = "GetContinentDetails")]
ContinentDetailsRespnse GetContinentDetails(ContinentDetailRequest request);

So, I can add a class for the service implementation. I create the ContinentsPopulation.cs file. The ContinentsPopulation class implements the IContinentsPopulation interface. It is described with the ServiceBehavior attribute. In my example, the IncludeExceptionDetailInFaults property is set to true. I made this on purpose in order all the messages about exceptions were sent to the client and serialized in the needed form. In my case, jQuery gets the JSON data.

Now, I should have references to the classes which don’t exist (these are: ContinentsListResponse, ContinentDetailsResponse, ContinentDetailRequest). I need to create them. Each of these classes is messages class. The ContinentsListResponse and ContinentDetailsResponse classes are classes of messages between the server and client, and to be more exact, are classes which contains data about response from the server. The ContinentDetailRequest class is the class of messages from client to server, and exactly, the class which contains data about response to server.

Let’s create a separate library of classes. This library allows me to separate the data model from the service implementation. I add my classes to it. Besides that, I can use the messages classes in other projects when I realize the client part.

Messages classes are serialized with using of WCF. That’s why I need to add the DataContact attribute to the class and the DataMember attribute to each member of the class. A name of a member name is defined in this attribute. Then, I need to specify that this value is obligatory (IsRequired=true). And finally, I need to indicate the order of data positioning (Order = 0). This means that the value will be the first or with 0 index in serialized object.

The DataContact and DataMember attributes are in the System.Runtime.Serialization namespace, and I need to add reference to it.

The Messages classes are shown below. They contain the continent name and population size value

[DataContract(Name = "ContinentPopulation")]
public class ContinentPopulation
{
[DataMember(Name = "ContinentName",IsRequired = true,Order = 0)]
public string ContinentName { get; set; }

[DataMember(Name = "TotalPopulation", IsRequired = true, Order = 1)]
public int TotalPopulation { get; set; }
}

Contains a detailed data about the continent. The data includes: a name of the continent, area, percentage of the total land area, value of population size and percentage of the total population of the Earth.

[DataContract(Name = "ContinentDetails")]
public class ContinentDetails
{
[DataMember(Name = "ContinentName", IsRequired = true, Order = 0)]
public string ContinentName { get; set; }

[DataMember(Name = "Area", IsRequired = true, Order = 1)]
public long Area { get; set; }

[DataMember(Name = "PercentOfTotalLandmass", IsRequired = true, Order = 2)]
public long PercentOfTotalLandmass { get; set; }

[DataMember(Name = "TotalPopulation", IsRequired = true, Order = 3)]
public long TotalPopulation { get; set; }

[DataMember(Name = "PercentOfTotalPopulation", IsRequired = true, Order = 4)]
public long PercentOfTotalPopulation { get; set; }
}

Contains the continent name for which a detailed data should be obtained:

[DataContract(Name = "ContinentDetailRequest")]
public class ContinentDetailRequest
{
[DataMember(Name = "ContinentName", IsRequired = true, Order = 0)]
public string ContinentName { get; set; }
}

The class which represents response from the server with detailed data about the continent.

[DataContract(Name = "ContinentDetailsResponse")]
public class ContinentDetailsResponse
{
[DataMember(Name = "Details", IsRequired = true, Order = 0)]
public ContinentDetails Details { get; set; }
}

The class which represents response from the server with the list of continents and population size.

[DataContract(Name = "ContinentsListResponse")]
public class ContinentsListResponse
{
[DataMember(Name = "Continents", IsRequired = true, Order = 0)]
public List Continents { get; set; }
}

In the real projects, data, which a server gets, are taken from a data base. I won’t complicate my example with creation of classes for connection to a data base. I fill data which I need for the work from the code. I create Continents private field in the class. This field is initialized while the service instance creation and is filled in the InitializeData method.

The implementation of the ContinentsPopulation class is represented below:

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ContinentsPopulation : IContinentsPopulation
{
private List continents = null;
public ContinentsPopulation()
{
continents = new List();
InitializeData();
}

private void InitializeData()
{
continents.Add(new ContinentDetails()
{
ContinentName = "Asia",
Area = 43820000,
PercentOfTotalLandmass = 29.5,
TotalPopulation = 3879000000,
PercentOfTotalPopulation = 60,
});

continents.Add(new ContinentDetails()
{
ContinentName = "Africa",
Area = 30370000,
PercentOfTotalLandmass = 20.4,
TotalPopulation = 922011000,
PercentOfTotalPopulation = 14,
});

continents.Add(new ContinentDetails()
{
ContinentName = "North America",
Area = 24490000,
PercentOfTotalLandmass = 16.5,
TotalPopulation = 528720588,
PercentOfTotalPopulation = 8,
});

continents.Add(new ContinentDetails()
{
ContinentName = "South America",
Area = 17840000,
PercentOfTotalLandmass = 12,
TotalPopulation = 382000000,
PercentOfTotalPopulation = 6,
});

continents.Add(new ContinentDetails()
{
ContinentName = "Antarctica",
Area = 13720000,
PercentOfTotalLandmass = 9.2,
TotalPopulation = 1000,
PercentOfTotalPopulation = 0.00002,
});

continents.Add(new ContinentDetails()
{
ContinentName = "Europe",
Area = 10180000,
PercentOfTotalLandmass = 6.8,
TotalPopulation = 731000000,
PercentOfTotalPopulation = 11.5,
});

continents.Add(new ContinentDetails()
{
ContinentName = "Australia",
Area = 9008500,
PercentOfTotalLandmass = 5.9,
TotalPopulation = 31260000,
PercentOfTotalPopulation = 0.5,
});
}

public ContinentsListResponse GetContinents()
{
return new ContinentsListResponse()
{
Continents = continents.Select(p =>
new ContinentPopulation
{
ContinentName = p.ContinentName,
TotalPopulation = p.TotalPopulation
}).ToList()
};
}

public ContinentDetailsResponse GetContinentDetails(ContinentDetailRequest request)
{
ContinentDetails continentDetails = continents.First(p => p.ContinentName.Equals(request.ContinentName));
return new ContinentDetailsResponse()
{
Details = new ContinentDetails
{
Area = continentDetails.Area,
ContinentName = continentDetails.ContinentName,
PercentOfTotalLandmass = continentDetails.PercentOfTotalLandmass,
PercentOfTotalPopulation = continentDetails.PercentOfTotalPopulation,
TotalPopulation = continentDetails.TotalPopulation,
}
};
}
}

Now, I have ready WCF service which gets and returns the JSON objects which can be used on a client. In the next article I will describe the infrastructure and implementation of AJAX calls, which JSON, to the WCF service.

November 3rd, 2011

Leave a Comment