Sunday, July 15, 2012

Access WCF service from JQuery and get a JSON typed object

I recently wanted to access wcf service from client side, so I browse through internet and found the following article extremely useful.
http://www.codeproject.com/Articles/132809/Calling-WCF-Services-using-jQuery

I have followed the steps listed in the article and the solution functioned well in IE but not in firefox because of a cross domain issue. However I was able to overcome that issue. This blog post will include all steps  to create a solution which calls a wcf service from client side and gets a JSON typed object, works in any browser.


First create a basic WCF Service Application,


Set "AspNetCompatibilityRequirementsMode" to "Allowed" in Service1.svc.cs,




[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 : IService1
    {


Add a method named 'GetUser' which returns a String array to the "IService1" interface. Set "WebInvoke" attributed to given values as in the following code block,


[ServiceContract]
    public interface IService1
    {

        [OperationContract]
        [WebInvoke(Method = "POST",
         BodyStyle = WebMessageBodyStyle.Wrapped,
         ResponseFormat = WebMessageFormat.Json)]
        string[] GetUser(string Id);



Add a public class named "User" and insert a method to return a string array of users according to the Id as following,



public class User
    {

        Dictionary<int, string> users = null;
        public User()
        {
            users = new Dictionary<int, string>();
            users.Add(1, "pranay");
            users.Add(2, "Krunal");
            users.Add(3, "Aditya");
            users.Add(4, "Samir");
        }

        public string[] GetUser(int Id)
        {
            var user = from u in users
                       where u.Key == Id
                       select u.Value;

            return user.ToArray<string>();
        }

    }



Implement the "GetUser" method in the Service1.svc.cs to return a User according to ID as following,



[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 : IService1
    {
        public string[] GetUser(string Id)
        {
            return new User().GetUser(Convert.ToInt32(Id));
        }



Now we have to edit the configuration file. First add following "ServiceBehavior" and "EndBehavior" under behaviors,


<behaviors>
   <serviceBehaviors>
    <behavior name="ServiceBehavior">
     <serviceMetadata httpGetEnabled="true"/>
     <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
   </serviceBehaviors>
   <endpointBehaviors>
    <behavior name="EndBehavior">
     <webHttp/>
    </behavior>
   </endpointBehaviors>
  </behaviors>


then add following "service" and "endpoint" under Service,



<services>
   <service behaviorConfiguration="ServiceBehavior" name="Service1">
    <endpoint address="" binding="webHttpBinding" 
        contract="IService1" behaviorConfiguration="EndBehavior"/>
   </service>
  </services>



Edited entire web.config will be something like following,



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

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="EndpBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="WcfServiceDan.Service1">
        <endpoint address="" binding="webHttpBinding"
            contract="WcfServiceDan.IService1" behaviorConfiguration="EndpBehavior"/>
      </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>


WCF service is ready to go. Now add following JQuery code block to your client application,


<script type="text/javascript">

        function WCFJSON() {

            $.ajax({
                type: "POST", //GET or POST or PUT or DELETE verb
                url: "http://localhost:58055/Service1.svc/GetUser", // Location of the hosted service
                crossDomain: true,
                data: '{"Id": "3"}',
                contentType: "application/json; charset=utf-8", // content type sent to server
                dataType: "json", //Expected data format from server
                processdata: true, //True or False
                success: function (msg) {//On Successfull service call
                    alert(msg.GetUserResult[0]);
                },
                error: function (msg) {//On Successfull service call
                    console.log(msg);
                }
            });
        }

        $(document).ready(
         function () {
             WCFJSON();
         }
         );

    </script>


Now application will be working in IE but not in Mozilla since the cross domain issue. Add "Global.asax" file to the WCF service and insert following code block under the "Application_BeginRequest" method to overcome the issue,


protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {

                HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");

                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");

                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");

                HttpContext.Current.Response.End();

            }
        }


If you followed the steps correctly, you will get the following alert as the output,


Enjoy..!!

No comments:

Post a Comment