WCF REST Service to get or post JSON data and retrieve JSON data with DataContract

In this article, I will talk about creating WCF RESTful services for CRUD operations which uses JSON and DataContracts. CRUD operations are done by HTTP verbs GET, POST, PUT and DELETE.

Introduction to REST

REST stands for Representational State Transfer. It provides you architectural principles about how client and service can exchange the resources over HTTP. REST services can be accessed by any language which supports HTTP communication and help truly to heterogeneous applications.

As REST services are sessionless, stateless resource based mechanisms it significantly reduces message size and increases performance. It provides REST API for CRUD operations and transfers JSON, XML, or both. See more details on RESTful CRUD operations using ASP.NET Web API.

Introduction to JSON

JSON stands for JavaScript Object Notation. It is a lightweight data exchange format. It does not create lengthy tags like XML and produce human readable clean data. JSON is completely language independent. It gives you a collection of Name/value pair. The data member names must be a valid JSON string and included in quotation marks or apostrophes. If you are not using reserved JavaScript keyword you may omit the quotation marks or apostrophes.

Follow below steps to implement WCF RESTful service with JSON and DataContract

Create WCF RESTful service

Follow the article how to create wcf restful services to understand what is RESTful services, when to use which http verbs and nature of RESTful services.

Create Orders DataContract for your RESTful OrderService

Create a DataContract Orders which will be used for exchanging orders information between service and client. Add below OrderData contract to the RESTfulWCFService application created in the previous step.

    
using System.Runtime.Serialization;

namespace RESTFulWCFService
{
    [DataContract]
    public class OrderContract
    {
        [DataMember] 
        public string OrderID { get; set; }

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

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

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

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

Orders data store

Download Orders XML file and place it in C: drive. The CRUD operations will be performed on this XML file using REST calls.

REST OrderService

Add OrderService to your application. Right click on RESTFulWCFService application from solution explorer -> Select Add -> Select New Item -> Select WCF Service -> Name it as OrderService.

It will add two files OrderService.svc and IOrderService.cs

Order ServiceContract

Open IOrderService ServiceContract. Add below OperationContracts to OrderService with WebGet or WebInvoke to make the service as RESTful.

Notice the following attributes for WebGet or WebInvoke

  • UriTemplate: The corresponding Operation will be served with matching Uri.
  • RequestFormat: Tells the format of the request is XML or JSON.
  • ResponseFormat: Tells the format of the response is XML or JSON
  • Method: WebInvoke has the Method attribute. The value for this could be PUT, POST, DELETE. WebGet does not have this attribute as it is used only for HTTP verb GET.
    
using System.ServiceModel.Web;

namespace RESTFulWCFService
{   
    [ServiceContract]
    public interface IOrderService 
    {
        [OperationContract]
        [WebGet(UriTemplate = "/GetOrderTotal/{OrderID}",
            ResponseFormat= WebMessageFormat.Json)]
        string GetOrderTotal(string OrderID);

        [OperationContract]
        [WebGet(UriTemplate = "/GetOrderDetails/{OrderID}", 
            RequestFormat=WebMessageFormat.Json,            
            ResponseFormat = WebMessageFormat.Json)]
        OrderContract GetOrderDetails(string OrderID);

        [OperationContract]
        [WebInvoke(UriTemplate = "/PlaceOrder", 
            RequestFormat= WebMessageFormat.Json,   
            ResponseFormat = WebMessageFormat.Json, Method = "POST")] 
        bool PlaceOrder(OrderContract order);
    }
}
            

Order ServiceContract implementation

Open OrderService.cs and implement operations from IOrderService.

  • GetOrderTotal: method is WebGet operation for getting OrderTotal of particular OrderID.
  • GetOrderDetails: method is WebGet operation for getting Order Details of particular OrderID. It takes the OrderID and returns corresponding OrderDetails in form of OrderContract DataContract.
  • PlaceOrder: method is WebInvoke operation and performs the Create of CRUD operations. It takes OrderContract as input parameter and adds its details to Orders.xml
    
using System.Xml.Linq;
using System.Collections;

namespace RESTFulWCFService
{    
    public class OrderService : IOrderService
    {
        public string GetOrderTotal(string OrderID)
        {
            string orderTotal = string.Empty;

            try
            {
                XDocument doc = XDocument.Load("C:\\Orders.xml");

                orderTotal =
                (from result in doc.Descendants("DocumentElement")
                .Descendants("Orders")
                    where result.Element("OrderID").Value == OrderID.ToString()
                    select result.Element("OrderTotal").Value)
                .FirstOrDefault<string>();

            }
            catch (Exception ex)
            {
                throw new FaultException<string>
                        (ex.Message);
            }
            return orderTotal;
        }

        public OrderContract GetOrderDetails(string OrderID)
        {
            OrderContract order = new OrderContract();

            try
            {
                XDocument doc = XDocument.Load("C:\\Orders.xml");
                
                IEnumerable<XElement> orders =
                    (from result in doc.Descendants("DocumentElement")
                        .Descendants("Orders")
                    where result.Element("OrderID").Value == OrderID.ToString()
                    select result);

                order.OrderID = orders.ElementAt(0)
                                            .Element("OrderID").Value;
                order.OrderDate = orders.ElementAt(0)
                                            .Element("OrderDate").Value;
                order.ShippedDate = orders.ElementAt(0)
                                            .Element("ShippedDate").Value; 
                order.ShipCountry = orders.ElementAt(0)
                                            .Element("ShipCountry").Value; 
                order.OrderTotal = orders.ElementAt(0)
                                            .Element("OrderTotal").Value; 
            }
            catch (Exception ex)
            {
                throw new FaultException<string>
                        (ex.Message);
            }
            return order;
        }

        public bool PlaceOrder(OrderContract order)
        {
            try
            {
                XDocument doc = XDocument.Load("C:\\Orders.xml");

                doc.Element("DocumentElement").Add(
                        new XElement("Products",
                        new XElement("OrderID", order.OrderID),
                        new XElement("OrderDate", order.OrderDate),
                        new XElement("ShippedDate", order.ShippedDate),
                        new XElement("ShipCountry", order.ShipCountry),
                        new XElement("OrderTotal", order.OrderTotal)));

                doc.Save("C:\\Orders.xml");
            }
            catch (Exception ex)
            {
                throw new FaultException<string>
                        (ex.Message);
            }
            return true;
        }
    }
}
           

WCF RESTful Service endpoint Configuration

WCF RESTful Service endpoint Configuration is about similar to normal endpoints. Notice that we are using webHttpBinding.

We added the endpointBehaviors for webHttp settings. Add below service endpoints.

    
 <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />    
      
      <service behaviorConfiguration="Default" 
            name="RESTFulWCFService.OrderService">
        <endpoint address="" behaviorConfiguration="webBehavior" 
                binding="webHttpBinding" 
                contract="RESTFulWCFService.IOrderService" />
        
        <endpoint contract="IMetadataExchange" binding="mexHttpBinding" 
                        address="mex" />
      
      </service>
    </services>
    <behaviors>
        <endpointBehaviors>
            <behavior name="webBehavior">
                <webHttp helpEnabled="true" />
            </behavior>
        </endpointBehaviors>
        <serviceBehaviors>
            <behavior name="Default">
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
            <behavior name="">
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>
            

View your OrderService

Right click on OrderService.svc and select View in browser. You may enter the below URL in the browser.

http://localhost:61090/OrderService.svc/GetOrderDetails/10250

WCF RESTful Product Service result

Notice that DataMember attributes are shown in alphabetically order. You may set it using DataMembers Order property. Click here to know more about DataMember and enum member attributes.

Client application for RESTful OrderService

Add a console application to your solution. Add a reference to WCFServices where OrderService is. Add below client code in the console application.

    
using System.Net;
using System.Runtime.Serialization.Json;
using RESTFulWCFService;

namespace DotnetmentorsClient
{
    class Program
    {
        static void Main(string[] args)
        {
            GetOrderDetails("10248");
            GetOrderTotal("10250");
            PlaceOrder(); 
            Console.ReadKey(true);
        }

        private static void GetOrderDetails(string orderID)
        {
            WebClient proxy = new WebClient();
            string serviceURL = 
                    string.Format("http://localhost:61090/OrderService.svc
                                    /GetOrderDetails/{0}", orderID); 
            byte[] data = proxy.DownloadData(serviceURL);
            Stream stream = new MemoryStream(data);
            DataContractJsonSerializer obj = 
                        new DataContractJsonSerializer(typeof(OrderContract));
            OrderContract order = obj.ReadObject(stream) as OrderContract;
            Console.WriteLine("Order ID : " + order.OrderID);
            Console.WriteLine("Order Date : " + order.OrderDate);
            Console.WriteLine("Order Shipped Date : " + order.ShippedDate);
            Console.WriteLine("Order Ship Country : " + order.ShipCountry);
            Console.WriteLine("Order Total : " + order.OrderTotal);
        }

        private static void GetOrderTotal(string orderID)
        {
            Console.WriteLine();  
            Console.WriteLine("**** Output for GetOrderTotal ************");  
            WebClient proxy = new WebClient();
            string serviceURL = 
                    string.Format("http://localhost:61090/OrderService.svc
                                    /GetOrderTotal/{0}", orderID);
            byte[] data = proxy.DownloadData(serviceURL);
            Stream stream = new MemoryStream(data);
            DataContractJsonSerializer obj = 
                        new DataContractJsonSerializer(typeof(string));
            string order = Convert.ToString(obj.ReadObject(stream));
            Console.WriteLine(order);
        }

        private static void PlaceOrder()
        {            
            OrderContract order = new OrderContract
            {
                OrderID = "10550",
                OrderDate = DateTime.Now.ToString(),
                ShippedDate = DateTime.Now.AddDays(10).ToString(),
                ShipCountry = "India",
                OrderTotal = "781"
            };      
      
            DataContractJsonSerializer ser = 
                    new DataContractJsonSerializer(typeof(OrderContract));
            MemoryStream mem = new MemoryStream();
            ser.WriteObject(mem, order);
            string data = 
                Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
            WebClient webClient = new WebClient();            
            webClient.Headers["Content-type"] = "application/json";            
            webClient.Encoding = Encoding.UTF8;
            webClient.UploadString("http://localhost:61090/OrderService.svc
                            /PlaceOrder", "POST", data);              
            Console.WriteLine("Order placed successfully...");  
        }
    }
}    
             

The client code for Operation PlaceOrder uses POST method which sends JSON data to service. It uses DataContractJsonSerializer to serialize DataContract. We use webClient.UploadString method to post data to service

Source code on Git hub Source Code on Github

Speak your mind
Please login to post your comment!


  • geeksarray user
    10/15/2013 05:12 PM Robin

    How to Create WCFRESTFulService with jSon to perform CRUD operations on SQL Server DB . Please forward me example for it on patilrobin420@gmail.com

  • geeksarray user
    10/15/2013 09:12 PM Laxmikant

    @Robin, You can use the same methods however you have replace the actual code which talks to your SQL Server through SQLConnection and SQLCommand

  • geeksarray user
    12/04/2013 07:02 AM jagadish

    Hi Its a very good example but un fortunately i am getting an error when i post the data it give me error "The remote server returned an error: (400) Bad Request." pls can you help me out

  • geeksarray user
    01/02/2014 07:16 PM siddu

    PlaceOrder() throws the error "The remote server returned an error: (400) Bad Request."

  • geeksarray user
    01/03/2014 12:53 AM Laxmikant

    @Viii, "The remote server returned an error: (400) Bad Request." error comes because client sends data more than set for maxReceivedMessageSize, <br /> Try to change your server side config file and set maxReceivedMessageSize = 65536000

  • geeksarray user
    07/29/2014 07:16 PM sujil

    helo

  • geeksarray user
    08/19/2014 05:13 PM Mehul

    Hi, I am also facing error "The remote server returned an error: (400) Bad Request." at PlaceOrder(). does setting up value solve the problem maxReceivedMessageSize ?! How/where to set maxReceivedMessageSize in web.config?

  • geeksarray user
    10/29/2014 09:04 AM max

    If I want to just a post a string (128 characters long), which will be parsed at server, how can I pass it? Is it even possible? All I care about post the data which is string.

  • geeksarray user
    10/30/2014 12:48 PM Laxmikant

    @Max you can certainly do it ... just make a operation contract which accept a string see below operation contract [OperationContract] [WebInvoke(UriTemplate = "/PlaceOrder", RequestFormat= WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, Method = "POST")] bool PlaceOrder(string ordernumber);

  • geeksarray user
    10/31/2014 08:00 AM max

    Thanks Laxmikant for quick response. Is that also possible to pass more than 1 parameter? Also how do I add reference in client when client and service are not in single solution? Is there also a way to pass parameters other than json format? Thanks,

  • geeksarray user
    10/31/2014 09:32 AM Laxmikant

    @Max 1. you can have multiple parameters as input with this you also have to configure UriTemplate accordingly number of parameters. 2. You can update the ServiceUrl and call proxy.DownloadData() function which may be or may not be in same solution. 3. You can also have XML as Request / Response format.

  • geeksarray user
    10/31/2014 07:03 PM max

    I see that we can also set the property of object as you did in your example and that way i can set additional parameter in the property. So is it possible to pass order object from separate project? Thanks for your help.

  • geeksarray user
    11/04/2014 09:46 AM max

    Hi Laxmikant, Any suggestion for my last post? Thanks,

  • geeksarray user
    03/24/2015 05:31 AM Mohan

    how to retrieve Particular data from JSON file. Thank u

  • geeksarray user
    03/24/2015 05:32 AM Mohan

    JSON filter based upon Condition

  • geeksarray user
    04/02/2015 05:18 AM yashashishverma

    Hi, I refer your code but the problem is that i am not getting any value at service side while placing order. Please suggest some solutions. Thank you

  • geeksarray user
    04/02/2015 10:01 AM Laxmikant

    are you using the webclient and datacontract to place order or calling using jQuery Ajax calls. Please download the code and try.

  • geeksarray user
    04/02/2015 09:57 PM yashashishverma

    I did same as you except I put the service and client in different projects whereas both project have their own OrderContract class. But the issue is same, i.e. I did not get any value at the service side.

  • geeksarray user
    04/08/2015 01:33 AM Laxmikant

    if you have use different projects for web api and client then you will have to enable cors at web api and use JSONP protocol while making ajax calls

  • geeksarray user
    06/11/2015 02:05 PM FiFa

    The restful WCF integration model is really messy in terms of configuration paradigm and thus fraught with lots of if's and buts. Anyways, if anybody wants to know why you can get (400) bad request is generic error, it is because the solution is hardcoded to check for Order.xml from c:\ drive. As soon as you correct the location, the solution should work like a charm. My experience on the WWF stack was better then WCF, specially the REST on WCF is not very intuitive and defined for developers. Too many what-iff's. But this is one solution among maybe 15-20 i saw and the comments from others which helped me tackle some of the ghost in my config to support both Soap and Rest on the same Service. Kudos to the author

  • geeksarray user
    06/13/2015 07:03 PM Laxmikant

    Thanks FiFa for providing your experience. Have you change to relative path to Orders.xml?

  • geeksarray user
    06/01/2016 12:00 PM sheethal

    A very useful piece of information thank you

  • geeksarray user
    08/17/2016 12:36 PM jike

    do i need url of incoming REST JSON data before i can read it using vb.net

  • geeksarray user
    06/01/2017 02:24 PM antoniofs.sp

    A very useful piece of information thank you, congratulations...

  • geeksarray user
    10/01/2017 05:53 AM Festus

    Kindly help me understand where you have setup the port number 61090. I would like to use port 8090 instead. Kindly help me. Festus

  • geeksarray user
    10/01/2017 06:29 AM Laxmikant

    Festus, that is just random number chosen by service, if you hasted service in IIS you can change port in add site bindings or if you have not hosted you can update project properties to set port