Thursday, January 26, 2017

SharePoint Custom WCF Service with Automatic Formatting



Recently I was writing a custom SharePoint WCF service for using in client side JavaScript libraries (jquery, angular) and C# server side call HttpWebRequest without worrying adding references and proxy classes. Majority of the articles I referred to were only showing JSON output; I wanted this service to provide both JSON and Xml data formats. If the requirement is to output both JSON and Xml formats, I found people writing two method calls:one for each JSON  and Xml. Also, I have seen articles where response was driven through method or query string parameter to get requirement format (WebMessageFormat.Xml, WebMessageFormat.Json) If I follow the former approach as shown below, the amount of code will grow twice the code that I actually need which is very inefficient and demand more maintenance. 

[ServiceContract]
interface IPersonService

    {
         [WebGet(UriTemplate = "person/{id}",  ResponseFormat = WebMessageFormat.Json)]
          Person GetPersonJSON(int id); //get JSON output

         [WebGet(UriTemplate = "person/{id}",  ResponseFormat = WebMessageFormat.Xml)]
          Person GetPersonXml(int id);  //get Xml output
    }

All I wanted was automatic formating based on some configuration or flag set through code. While searching for options. I found this technet article. helpful.
WCF Web HTTP Automatic and Explicit  Formatting options
https://msdn.microsoft.com/en-us/library/ee476510(v=vs.110).aspx

(snippet from technet)

Automatic Formatting

The WCF Web HTTP programming model allows you to dynamically determine the best format for a service operation to return its response in. Two methods for determining an appropriate format are supported: automatic and explicit.
When enabled, automatic formatting chooses the best format in which to return the response. It determines the best format by checking the following, in order:
  1. The media types in the request message’s Accept header.
  2. The content-type of the request message.
  3. The default format setting in the operation.
  4. The default format setting in the WebHttpBehavior
(/snippet from technet)

Solution:
  1. Added web.config file to my custom wcf custom service. 
  2. C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\isapi\<MyCustomWCFService>
  3. Added System.ServiceModel section as show below.
         <configuration>
     <system.serviceModel>
      <behaviors>  
        <endpointBehaviors>        

          <behavior>          

            <webHttp automaticFormatSelectionEnabled="true" />
          </behavior>
        </endpointBehaviors>
      </behaviors>
      </system.serviceModel>
    </configuration>

     
Have only service contract method.


[ServiceContract]
interface IPersonService
    {
         [WebGet(UriTemplate = "person/{id}")]
          Person GetPerson(int id);
   }

Now I can the call same method through jquery/ajax by specifying the ContentType or Accept Header and get the output format that I need. 

JavaScript - JSON Output 


function getPerson() {
            var serviceUri = _spPageContextInfo.webAbsoluteUrl" + "/_vti_bin/<MyCustomService>/PersonService.svc/person/" + id;
            $.ajax({
                type: "GET",
                contentType: "application/json",
                url: serviceUri,
                dataType: "json"
            }).done(function (data) {
                //do something here
            }).fail(function (error) {
            });

        }

JavaScript - Xml Output

function getPerson() {
            var serviceUri = _spPageContextInfo.webAbsoluteUrl" + "/_vti_bin/<MyCustomService>/PersonService.svc/person/" + id;
            $.ajax({
                type: "GET",
                contentType: "application/xml",
                url: serviceUri,
                dataType: "xml"
            }).done(function (data) {
                //do something here
            }).fail(function (error) {
            });

        }

Server Side C# - HttpWebRequest - JSON Output


HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(serviceUri);
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";



Server Side C# - HttpWebRequest - Xml Output


HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(serviceUri);
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/xml;odata=verbose";