Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

JSON Enabled WCF Services - Part 1

4.79/5 (14 votes)
28 Dec 2011CPOL7 min read 45.8K  
Creating a WCF service and configuring it to work with data in JSON format.

Introduction

This article describes the process of a WCF service configuration for working with data in JSON format. Although the configuring process seems to be simple, there are some particularities which cannot be ignored.

Background

As the lead developer in a multinational software company, I often develop Rich Internet Applications and do care about ensuring that an app would have a long and happy life. And lately, I have a really heavy headache when it comes to the decision about using the proper technology. From one side, the two most used ones are Silverlight and Flash. Both of them are cross-platform technologies, so an application created on Silverlight or Flash will look the same in all browsers.

From the other side, IMHO, these technologies have one serious disadvantage: they are limited in use. You can’t use a Silverlight application on Linux or a Flash application on iOS. I didn’t even mention mobile systems that are an essential part of our life. The majority of modern mobile devices and tablets don’t provide full support for Silverlight and Flash.

The use of HTML and JavaScript allows eliminating compatibility issues. All that’s needed to work with such applications is a web browser on any device.

I won’t bother you further with reasoning pros and cons of different technologies – I use them all, and the decision often depends on a particular project. But today I would like to tell you what made up my mind to choose HTML and JavaScript rather than other technologies for one of the projects I have been working on.

Creating a WCF service

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

Now, I want to tell you how we created the WCF service which passes data in JSON format.

The first step is to add a WCF service to the website.

Select the 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 along with two files: IWcfJsonService.cs and WcfJsonService.svc.cs.

Let me go a little bit deeper into these files added to the project. The IWcfJsonService.cs file defines the interface implemented by a service. It contains attributes which specify to WCF how to use the service. The implementation of the service is described in the code-behind file (WcfJsonService.svc.cs). This file is added to the .svc file. You can use both these files, but I prefer removing them and creating a library of classes instead. This library contains interface and service implementations. As a result, we come to a more convenient way to manage the code of our WCF services, because of:

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

Further, you will see that the approach doesn’t complicate development, it only requires adding the reference to the library with the class.

Changing the Service Declaration File

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

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

And below, you can see a new version of the 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:

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

Creating the Service Interface

The next step is to add a class for the service implementation. The first file I add is a service interface. In my example, I display a list of continents with population size. And I name this service interface IContinentsPopulation.cs. Now 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.

C#
[ServiceContract]
public interface IContinentsPopulation

Now I can add method signatures to the interface. I add two methods for the application:

  • GetContinents which gets a list of continents with population;
  • GetContinentDetails which returns data for the continent with specified name.

Below you can see the method descriptions:

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

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

Implementing the Service

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 did this on purpose in order that all the messages about exceptions are sent to the client and serialized in the required form. In my case, jQuery gets the JSON data.

Now, I should have references to the classes which don’t exist. They are ContinentsListResponse, ContinentDetailsResponse, and ContinentDetailRequest. But first I need to create them. Each of these classes is a message class. The ContinentsListResponse and ContinentDetailsResponse classes are the message classes for messages between the server and the client. To be more specific, they are classes which include data about responses from the server. The ContinentDetailRequest class is a message class from a client to a server, that is the class that includes data about responses to the server.

Now let’s create a separate library of classes. This library allows separating the data model from the service implementation. I add my classes to it. Besides, I can use the message classes in other projects when implementing a client part.

Message classes are serialized using 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 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 a 0 index in a serialized object.

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

The message classes are shown below. They contain the continent name and population size values:

C#
[cc lang="Csharp" escaped="true"][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; }
}
[/cc]

It contains the detailed data about the continent: a continent name, area, percentage of the total land area, value of population size, and percentage to the total population of the Earth.

C#
[cc lang="Csharp" escaped="true"][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; }
}[/cc]

It contains the continent name for which the detailed data should be obtained:

C#
[cc lang="Csharp" escaped="true"][DataContract(Name = "ContinentDetailRequest")]
public class ContinentDetailRequest
{
[DataMember(Name = "ContinentName", IsRequired = true, Order = 0)]
public string ContinentName { get; set; }
}
[/cc]

It is a class that represents the response from the server with detailed data about the continent.

C#
[cc lang="Csharp" escaped="true"][DataContract(Name = "ContinentDetailsResponse")]
public class ContinentDetailsResponse
{
[DataMember(Name = "Details", IsRequired = true, Order = 0)]
public ContinentDetails Details { get; set; }
}
[/cc]

It is a class that represents the response from the server with a list of continents and population size.

C#
[cc lang="Csharp" escaped="true"][DataContract(Name = "ContinentsListResponse")]
public class ContinentsListResponse
{
[DataMember(Name = "Continents", IsRequired = true, Order = 0)]
public List Continents { get; set; }
}[/cc]

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

The implementation of the ContinentsPopulation class is represented below:

C#
[cc lang="Csharp" escaped="true"][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,
            }
        };
    }
}[/cc]

Conclusion

We now have a WCF service that gets and returns JSON objects which can be used on the client-side of an application. You can easily configure such a service to use in your applications. A WCF service that passes and receives data in JSON format is universal and can be used in both Web and Windows Forms applications. In the next article, I would like to describe the infrastructure and implementation of AJAX calls which use JSON to a WCF service.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)