Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Consume WCF Service with JSONP and SOAP endpoints

4.86/5 (15 votes)
27 Jul 2012CPOL4 min read 89.4K   2.9K  
Simple application that consumes a WCF Service with both jQuery/JSONP and XML/SOAP implementations.

Introduction  

A couple of months ago I started to play with some of the features of JSON objects when being consumed from a webservice. I decided to implement WCF to test the good integration with JSON data.

The outstanding article of Gary Stafford helped to configure my first JSON cross domain application consuming a REST/JSONP WCF service. That included the settings of a cross domain "JSONP endpoint" in the service.

The example covered part of the needs but it took me a week of research to configure the same WCF service for being consumed from a usual Service Reference SOAP proxy. At that stage, I required a second "endpoint" configuration. 

Background 

Remember first of all that JSONP or "JSON with padding" complements the JSON data format. It is used to request data from a server that is deployed in a different domain, something forbidden by many web browsers.  

WCF services are used in enterprise application development. Among many advantages, WCF can offer several endpoints on the same service (HTTP, TCP etc).  

By configuring a WCF service with JSONP and SOAP endpoints, you can make it accessible from different types of client. This is useful for the clients who can consume the WCF proxy and for the ones who run HTTP communication with JSONP data.  

The Representational State Transfer (REST) provides a direct response from the service in several plain formats. If the WCF service is using REST/JSONP, then it is not necessary for the client to consume the WCF service proxy.  

The REST/JSONP performance is relevant in Ajax applications that require JSON data to handle the front end presentation. Now it's possible to get that data with a simple HTTP communication.

The example

This example is basically a server application MyService that runs a WCF service with two different enpoints to be consumed by a web client application MyClient:

  • The SOAP endpoint is used from a client method loadDropDownSOAP() that populates an ASP dropdown list server control.   
  • The second REST/JSONP endpoint is also used by a JavaScript method loadDropDownJSONP() that attempts to populate another dropdown list. This time, the method only requires a HTTP call to get the data from the service.  

The client application look and feel is quite simple. Just press over "Load with JSONP call" and "Load with SOAP call" to launch both operations.  

Image 1

Using the code    

The zip folder contains both website applications implemented on Visual Studio 2010 (framework 4.0). MyService and MyClient are ready to be compiled and tested in local environment:   

  • MyClient. You can build and run the application. The client application will be executed on http://localhost:7726/
  • MyService. Also ready to be executed. The service will be running over http://localhost:6573/Service.svc

Below you can read further implementation details of the most relevant files.

MyService - Web.config     

Take a look at both endpoint and binding configuration. The SOAP request will have to handle with the address="soap" endpoint setting. 

Important to use binding="webHttpBinding" for the REST/JSONP endpoint and binding="basicHttpBinding" on the SOAP endpoint  

XML
<?xml version="1.0"?>
<configuration>

  <appSettings>
  </appSettings>
  <system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />

    <services>
      <service behaviorConfiguration="WebServiceBehavior" name="MyService.Service">
        <endpoint address="" behaviorConfiguration="jsonBehavior" binding="webHttpBinding"
          bindingConfiguration="webHttpBindingWithJsonP" contract="MyService.IService" />
        <endpoint address="soap" binding="basicHttpBinding" contract="MyService.IService" />
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp helpEnabled="true"/>
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior name="WebServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP"
                 crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
  </system.serviceModel>

  <system.web>
    <compilation debug="false" targetFramework="4.0" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

MyService - Iservice.cs (Service Contract)

The format of the response is set in both operation contract. Either WebMessageFormat.Json or WebMessageFormat.Xml.

C#
[ServiceContract]
public interface IService
{
    [OperationContract]     
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare,
    RequestFormat = WebMessageFormat.Json,
    ResponseFormat = WebMessageFormat.Json,
    UriTemplate = "/GetTourListJSONP/")]
    cTourList GetTourListJSONP();
             
    [OperationContract]       
    [WebGet(BodyStyle = WebMessageBodyStyle.Bare,
    RequestFormat = WebMessageFormat.Xml,
    ResponseFormat = WebMessageFormat.Xml,
    UriTemplate = "/GetTourListXML/")]
    cTourList GetTourListXML();
}

MyService - Service.scv.cs (implementation of IService interface)

Both service methods return a list of tours implemented in a class cTourList based in a collection of objects cTour.

C#
public class Service : IService
{
    public cTourList GetTourListJSONP()
    {
        return CreateTourList();
    }

    public cTourList GetTourListXML()
    {
        return CreateTourList();
    }
    
    private cTourList CreateTourList()
    {
        cTourList oTourList = new cTourList();
        oTourList.Add(new cTour() { ID = 1, description = "Barcelona" });
        oTourList.Add(new cTour() { ID = 2, description = "Paris" });
        oTourList.Add(new cTour() { ID = 3, description = "Rome" });
        oTourList.Add(new cTour() { ID = 4, description = "London" });
        oTourList.Add(new cTour() { ID = 5, description = "Moscow" });

        return oTourList;
    }
}

Once the service is running in Visual Studio, it's possible to test both endpoints with the WCF Test Client. Recommended to do so before using the final client application.

Image 2

MyClient - Web.config

SOAP calls from the client application will require Service Reference settings on the project. You can handle that opening Visual Studio 2010 -> Project -> Add Service Reference  

Image 3

After adding the Service Reference, make sure that the text "soap" is included in the "address" of the endpoint: address="http://localhost:6573/Service.svc/soap". Otherwise, the SOAP call won't be successful.

XML
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="false" targetFramework="4.0" />
  </system.web>

  <system.webServer>
     <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
  
  <system.serviceModel>
    
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:6573/Service.svc/soap" binding="basicHttpBinding"
        bindingConfiguration="BasicHttpBinding_IService" contract="WCFReference.IService"
        name="BasicHttpBinding_IService" />
    </client>
    
  </system.serviceModel>
  
</configuration>

MyClient - Default.aspx.cs

The method loadDropDownSOAP() uses the endpoint SOAP that we commented above. The call returns an structure implemented in WCFReference.cTourList.

C#
public partial class _Default : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        // sets dropdown list empty
        DropDownListSOAP.Items.Clear();
        loadDropDownSOAP();
    }

    private void loadDropDownSOAP()
    {
        // XML-SOAP CALL TO WCF SERVICE
        WCFReference.ServiceClient oWebservice = new WCFReference.ServiceClient();
        WCFReference.cTourList oTourList = oWebservice.GetTourListXML();

        foreach (WCFReference.cTour oTour in oTourList)
        {
            DropDownListSOAP.Items.Add(new ListItem(oTour.description, Convert.ToString(oTour.ID)));
        }
    }
}

MyClient - Scripts/base.js 

This file contains the $.ajax call that will retrieve data from the WCF service in REST/JSONP mode using one specific endpoint configured on the WCF service. The var wcfServiceUrl contains the default HTTP address of the service.  

Note that the JavaScript method is populating the dropdown list using jQuery. The $.ajax call is returning a list of tours contained in the structure jsonpCallback: "tourList"

JavaScript
var wcfServiceUrl, populateDropdown;
 
// default URL WCF service
wcfServiceUrl = "http://localhost:6573/Service.svc/";


populateDropdown = function () {
    var ID, description;
    ID = this.ID;
    description = this.description;

    $("#selectJSON")
        .append($("<option></option>")
        .val(ID)
        .html(description));    
};

function loadDropDownJSONP(idDropdownJson, idDropdownSoap) {

    // sets both dropdown lists empty
    $("#" + idDropdownSoap + "").html("");
    $("#" + idDropdownJson + "").html("");

    // JSONP CALL TO WCF SERVICE
    $.ajax({
        cache: false,
        url: wcfServiceUrl + "GetTourListJSONP",
        data: "{}",
        type: "GET",
        jsonpCallback: "tourList",
        contentType: "application/javascript",
        dataType: "jsonp",
        error: function () {
            alert("list failed!");
        },
        success: function (list) {
            $.each(list, populateDropdown); // must call function as var
        }
   });
}

History 

  • 26/04/2012: First release of the article.  

License

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