locked
Using JSON as an alternative to XML RRS feed

  • Question

  • Hi I've seen examp[les of calling rest services and how to enable rest services.  My need is simply to use JSON instead of XML as the encoder of my data but still use the rich programming model of WCF.  Is this possible ideally I don't want to doing string manipulations to built URL's etc but I don't know if what i want is possible.  It would be nice to just to change the endpoint config and return either JSON or XML again is this even possible.

    Any advise on the approach to take would be great, c#client calling wcf service but minimising network traffic by returning JSON encoded data.

    Cheers,


    Darren Baldwin

    Tuesday, March 6, 2012 6:06 PM

Answers

  • There are a few ways where you can control the serialization format based on the client request without having to duplicate the operations. One possibility is to have two endpoints, one where the default response format is XML, the other JSON - you'd set the DefaultOutgoingResponseFormat property on the WebHttpBehavior for that.

    Another possibility is to enable the automatic format selection, by setting the AutomaticFormatSelectionEnabled property to true on the behavior. This way the client can send an Accept header specifying which format it accepts, and the response will vary based on that.

    The code below shows both ways to do that.

        public class Post_1ea8ba3a_6fc2_4d28_b136_3a5435192eaf
        {
            public class Person
            {
                public string Name { get; set; }
                public int Age { get; set; }
            }
            [ServiceContract]
            public class Service
            {
                [WebGet]
                public Person Get()
                {
                    return new Person { Name = "John", Age = 33 };
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "alwaysJson").
                    Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Json });
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "alwaysXml").
                    Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Xml });
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "autoFormat").
                    Behaviors.Add(new WebHttpBehavior { AutomaticFormatSelectionEnabled = true });
                host.Open();
                Console.WriteLine("Host opened");
    
                Console.WriteLine("JSON, specific endpoint");
                WebClient c = new WebClient();
                Console.WriteLine(c.DownloadString(baseAddress + "/alwaysJson/Get"));
                Console.WriteLine();
    
                Console.WriteLine("XML, specific endpoint");
                c = new WebClient();
                Console.WriteLine(c.DownloadString(baseAddress + "/alwaysXml/Get"));
                Console.WriteLine();
    
                Console.WriteLine("JSON, automatic response format");
                c = new WebClient();
                c.Headers[HttpRequestHeader.Accept] = "text/json";
                Console.WriteLine(c.DownloadString(baseAddress + "/autoFormat/Get"));
                Console.WriteLine();
    
                Console.WriteLine("XML, automatic response format");
                c = new WebClient();
                c.Headers[HttpRequestHeader.Accept] = "text/xml";
                Console.WriteLine(c.DownloadString(baseAddress + "/autoFormat/Get"));
                Console.WriteLine();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
    


    Carlos Figueira

    Thursday, March 8, 2012 2:32 PM

All replies

  • Yes, this is definitely possible and quite easy to do. Take a look at the WCF Web HTTP Programming Model for an introduction to what WCF offers.

    Carlos Figueira

    Tuesday, March 6, 2012 6:29 PM
  • Lots of good stuff here but not much on how to now call the service.
    I've been getting 405 errors then My latest error is "There was an error deserializing the object of type System.String. End element 'root' from namespace '' expected. Found element 'd' from namespace ''."

    I create a service supporting soap and Web Post

    ServiceHost host = new ServiceHost(typeof(Service), new Uri("http://localhost:8000/"));
    host.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), "Soap");
    ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService),new WebHttpBinding(),"Web");
    var bvr = new WebScriptEnablingBehavior();
    endpoint.Behaviors.Add(bvr);
    host.Open();

    my service implementation is simply

    public string EchoWithGet(string s)
    {
       return "You Said " + s;
    }


    then to call it.

    using (WebChannelFactory<IService> wcf = new WebChannelFactory<IService>(new Uri("http://localhost:8000/Web")))
    {
        IService channel = wcf.CreateChannel();   

        string s = channel.EchoWithGet("Hello");

    }

    would love to know what I'm doing wrong as I can type http://localhost:8000/Web/EchoWithGet?s=Hello into a browser and get back
    {"d":"You Said Hello"}

    can anybody link me to any resources to show me what I'm missing


    Darren Baldwin

    Wednesday, March 7, 2012 6:05 PM
  • ServiceHost host = new ServiceHost(typeof(Service), new Uri("http://localhost:8000/"));
    host.AddServiceEndpoint(typeof(IService), new BasicHttpBinding(), "Soap");
    ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService),new WebHttpBinding(),"Web");
    var bvr = new WebScriptEnablingBehavior();
    endpoint.Behaviors.Add(bvr);
    host.Open();


    On the service, don't use the WebScriptEnablingBehavior - use the WebHttpBehavior instead - and it should work fine.

    Carlos Figueira

    Wednesday, March 7, 2012 6:12 PM
  • Hi Darren,

    In addition to the WCF Web Programming reference(for REST service) Carlos mentioned, here is a Visual Studio pryoject template which can help you easily create WCF REST service by creating a project based on it:

    #WCF REST Service Template 40(CS)
    http://visualstudiogallery.msdn.microsoft.com/fbc7e5c1-a0d2-41bd-9d7b-e54c845394cd

    And for service operation in WCF REST service, you can use the "ResponseFormat" property of "WebGetAttribute" or "WebPostAttribute" to specify if you want the service operation to always return JSON or XML format response. e.g.

    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    [OperationContract]
    data GetData();
    
    and here is also a sample on building WCF JSON format REST service:


    #RESTful WCF JSON Service
    http://info.titodotnet.com/2011/01/restful-wcf-json-service_24.html

    In addition, if you want to consume REST service in client script, the JQuery library is a good choice: 

     

    #jQuery AJAX calls to a WCF REST Service
    http://www.west-wind.com/weblog/posts/2008/Apr/21/jQuery-AJAX-calls-to-a-WCF-REST-Service

    #Consuming a WCF / ASMX / REST Service using jQuery
    http://www.codeproject.com/Articles/59551/Consuming-a-WCF-ASMX-REST-Service-using-jQuery


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, March 8, 2012 3:05 AM
  • Thanks guys changed to webHttp behaviour and it works at a service and put the JSON response format in the attribute. 

    The only downside now is that I am tied to returning JSON all the time now aren't I.  One of the origional goals was to

    have a soap xml endpoint and a alternative JSON format endpoint.  By attributing my service aren't I now tied in to JSON only.  Is the only answer to have two methods?  Or can I control the returning format by setting somthing on the client. 


    Darren Baldwin

    Thursday, March 8, 2012 10:28 AM
  • There are a few ways where you can control the serialization format based on the client request without having to duplicate the operations. One possibility is to have two endpoints, one where the default response format is XML, the other JSON - you'd set the DefaultOutgoingResponseFormat property on the WebHttpBehavior for that.

    Another possibility is to enable the automatic format selection, by setting the AutomaticFormatSelectionEnabled property to true on the behavior. This way the client can send an Accept header specifying which format it accepts, and the response will vary based on that.

    The code below shows both ways to do that.

        public class Post_1ea8ba3a_6fc2_4d28_b136_3a5435192eaf
        {
            public class Person
            {
                public string Name { get; set; }
                public int Age { get; set; }
            }
            [ServiceContract]
            public class Service
            {
                [WebGet]
                public Person Get()
                {
                    return new Person { Name = "John", Age = 33 };
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "alwaysJson").
                    Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Json });
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "alwaysXml").
                    Behaviors.Add(new WebHttpBehavior { DefaultOutgoingResponseFormat = WebMessageFormat.Xml });
                host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "autoFormat").
                    Behaviors.Add(new WebHttpBehavior { AutomaticFormatSelectionEnabled = true });
                host.Open();
                Console.WriteLine("Host opened");
    
                Console.WriteLine("JSON, specific endpoint");
                WebClient c = new WebClient();
                Console.WriteLine(c.DownloadString(baseAddress + "/alwaysJson/Get"));
                Console.WriteLine();
    
                Console.WriteLine("XML, specific endpoint");
                c = new WebClient();
                Console.WriteLine(c.DownloadString(baseAddress + "/alwaysXml/Get"));
                Console.WriteLine();
    
                Console.WriteLine("JSON, automatic response format");
                c = new WebClient();
                c.Headers[HttpRequestHeader.Accept] = "text/json";
                Console.WriteLine(c.DownloadString(baseAddress + "/autoFormat/Get"));
                Console.WriteLine();
    
                Console.WriteLine("XML, automatic response format");
                c = new WebClient();
                c.Headers[HttpRequestHeader.Accept] = "text/xml";
                Console.WriteLine(c.DownloadString(baseAddress + "/autoFormat/Get"));
                Console.WriteLine();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
    


    Carlos Figueira

    Thursday, March 8, 2012 2:32 PM