Tuesday, November 17, 2015

Adding ReST endpoint/webHttpBinding to an existing WCF service along with basicHttpBinding

The beginning

Long long ago, in the middle of a big system, there was a WCF service who lived happily by serving its WPF based .Net client. When the service is installed in local laptop, it served the requests via net.pipe to the requests in same machine and net.tcp to the requests coming from other machines. When it was in data centers, it was accepting requests in http(s) using basicHttpBinding. In everyplace it was secured with X509 certificates. So it never got attention of attackers. In fact there were no attackers as most of the time it was inside the boundary of corporate network.

Things were good until some crazy boys came up with the idea of converting its huge WPF based business client in to HTML. Though they were excited to create HTML application they were not brave enough to generate HTML inside browser. Instead they tried to create a MVC application from which they called this service and generated HTML to sent to client. Their strategy was to not touch anything much which are working. Just create more things around the existing. Beautiful Open-Closed principle. More than that, their aim was to prove that Yes the WPF based business application can be converted to HTML.

Half the way this leadership of the team go changed. They found that its not good to have all the HTML getting generated at the server side. Why can't we generate HTML / view at client side by calling our little service completely avoiding the intermediate MVC site which was acting like proxy and generated HTML?

It went back and forth. Many meetings held at high level. People debated at high level without looking at the code. Finally in a meeting when the code was exposed in projector, everybody agreed to have a try at client side HTML generation by calling the service.

Minimal changes for ReST

The developers were believing on the policy of "Less code less defects" so they tried to expose service via webHttpBinding with only web config changes though they new the contract needs to be changed. They simply added new endpoint with webHttpBinding.


<service name="WcfService1.Service">
  <endpoint address=""
            binding="basicHttpBinding"
            contract="WcfService1.IService"/>
  <endpoint address="rest"
            binding="webHttpBinding"
            contract="WcfService1.IService"/>
</service>


When they first called our little service via rest endpoint with only web.config changes, the gate keeper WCF framework didn't invoke the service. Instead it wrote the below details in the svclog file.


"The message with To 'http://localhost/WcfService/Service.svc/rest/GetData?value=2' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.  Check that the sender and receiver's EndpointAddresses agree."

The developers understood that they missed end point behavior configuration for the new webHttp end point added to the service. They added end point behavior as below and used this in webHttpEndPoint.

<endpointBehaviors>
        <behavior name="restBehavior">
          <webHttp />
        </behavior>
</endpointBehaviors>

After this change they tried to call the service via ReST url. But this time they got another error in the browser.

405 Method Not Allowed

There was no entries in the svclog file. The developers realized that, there is no way to expose a service via ReST using webHttpBinding without a contract change. They did that contract change and compiled the assembly and put into bin folder.

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebGet]
    string GetData(int value);
}

After that they called the service using direct url and they got the result. Everybody became happy that the service worked. The result was as follows for the URL

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You entered: 2</string>

But there was one more question. How to use this in browser application where the language is Javascript? If its in JSON, Javascript knows how to process it. They modified the contract again as follows to get in JSON.

[ServiceContract]
public interface IService
{
    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    string GetData(int value);
}

Calling from Javascript

Once they were able to call the ReST url directly from the browser, they used the same url to call from the Javascript code written inside HTML application.


<script type="text/javascript">
    var baseUrl = "http://localhost/WcfService1/Service.svc/rest";
    function testWCFReSTCall() {
        var urlToServiceMethod = getUrlToGetDataMethod();
        
        var xhr = new XMLHttpRequest();
        xhr.open("Get", urlToServiceMethod, false);
        xhr.send();
        if (xhr.status === 200) {
            alert("200" + xhr.responseText);
        }
        else {
            alert("Error on XMLHttpRequest: " + xhr.status + " " + xhr.statusText);
        }
    }
    function getUrlToGetDataMethod() {
        var urlToGetData = baseUrl + "/GetData";
        var urlToGetDataWithParameters = urlToGetData + "?value=2";
        return urlToGetDataWithParameters;
    }
</script>

No comments: