Pranay Rana: Calling Cross Domain WCF service using Jquery/Javascript

Thursday, June 23, 2011

Calling Cross Domain WCF service using Jquery/Javascript

This post is about to call the cross domain WCF service from you page i.e Calling WCF service hosted on one domain and calling the service form jquery/javascript of page which is hosted on some other domain.
But before we start its better to get understand about the format of the data get exchange from one server to other server.

JSONP
Ajax allows to get data in the background without interfering with the display. Ajax call done by using XMLHttpRequest object, which is allow the client side javascript code to make HTTP connections.

But Ajax call does not allow to get data from cross-domain because of restrictions imposed by the browser. Security error get issued when requesting data from a other domain. one way to avoid security errors is to control remote server where data resides and every request goes to the same domain, that rise question what's the fun if data come form own server only? What to do if data require to get form the other server?

There is one way to come out form this limitation is to insert a dynamic script element in the Web page, one whose source is pointing to the service URL in the other domain and gets the data in the script itself. When the script loads, it executes. It works because the same-origin policy doesn't prevent dynamic script insertions and treats the scripts as if they were loaded from the domain that provided the Web page. But if this script tries to load a document from yet another domain, it will fail. Fortunately, you can improve this technique by adding JavaScript Object Notation (JSON) to the mix.

JSONP or "JSON with padding" is a complement to the base JSON data format, a pattern of usage that allows a page to request data from a server in a different domain. As a solution to this problem, JSONP is an alternative to a more recent method called Cross-Origin Resource Sharing.

Under the same origin policy, a web page served from server1.example.com cannot normally connect to or communicate with a server other than server1.example.com. An exception is the HTML <script> element. Taking advantage of the open policy for <script> elements, some pages use them to retrieve Javascript code that operates on dynamically-generated JSON-formatted data from other origins. This usage pattern is known as JSONP. Requests for JSONP retrieve not JSON, but arbitrary JavaScript code. They are evaluated by the JavaScript interpreter, not parsed by a JSON parser.

Calling Cross Domain WCF service
Now in following discuss I am going to show you how easily you can call the WCF service hosted on the other domain from the page hosted on the other domain.

Following is list of article you should look first before moving further

Create, Host(Self Hosting, IIS hosting) and Consume WCF servcie
Steps to Call WCF Service using jQuery

To start first create new solution and Add new Project which is WCF service and follow below steps

Step 1
In new release of .net 4.0 the WCF developer team added support for JSONP. There is a new property added which enable to call WCF service from other domain by setting its true.
CrossDomainScriptAccessEnabled - Gets or sets a value that determines if cross domain script access is enabled.

Change your WCF servcie config file as below


  
    
    
  
  
    
  
  
    
    
      
        
      
    
  

As you can see in above config code I have set crossdomainscriptaccessenabled to true and aspnetcompatibilityenabled is to true so that the WCF service works as a normal ASMX service and supports all existing ASP.NET features.
Step 2

SVC file of the service should be like as below

<%@ ServiceHost Language="C#" Debug="true" 
Service="WcfService1.Service1" 
CodeBehind="Service1.svc.cs"
Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"  %> 
Don't forget to add Factory attribute because it cause error if you remove it. Following are the reason to add Factory attribute
1. Service host factory is the mechanism by which we can create the instances of service host dynamically as the request comes in.
2. This is useful when we need to implement the event handlers for opening and closing the service.
3. WCF provides ServiceFactory class for this purpose.
Step 3

CS file for the WCF file is

using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace WcfService1
{
    
    [DataContract]
    public class Customer
    {
        [DataMember]
        public string Name;

        [DataMember]
        public string Address;
    }


    [ServiceContract(Namespace = "JsonpAjaxService")]
    [AspNetCompatibilityRequirements(RequirementsMode =   AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1
    {
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public Customer GetCustomer()
        {
            return new Customer() { Name = "Pranay", Address = "1 Ahmedabad" };
        }
    }

}
As you can see in the above code I have created Service class which is service contract which servs data and Customer class is DataContract which get served as respose.
In the service class GetCustomer method service data in Json format.

Once the WCF service created to move further Add new project >> Asp.Net service. So that both the WCF service and website runs on tow different like both hosted on different domain.

There is two solution to call the Cross Domain WCF service.

Solution 1 : Call WCF service by using JQuery
Jquery already have support to handle the jsonp. Jquery library provided function ajax and getJson which can allow to call the WCF service which send jsonp data in response.

CallService - Generic function is used to call the WCF servcie, which get called by other javascript function to get and display data

var Type;
        var Url;
        var Data;
        var ContentType;
        var DataType;
        var ProcessData;
        var method;
        //Generic function to call WCF  Service
        function CallService() {
            $.ajax({
                type: Type, //GET or POST or PUT or DELETE verb
                url: Url, // Location of the service
                data: Data, //Data sent to server
                contentType: ContentType, // content type sent to server
                dataType: DataType, //Expected data format from server
                processdata: ProcessData, //True or False
                success: function (msg) {//On Successfull service call
                    ServiceSucceeded(msg);
                },
                error: ServiceFailed// When Service call fails
            });
        }
ServiceFailed - is get called when call to service fail.

function ServiceFailed(xhr) {
            alert(xhr.responseText);
            if (xhr.responseText) {
                var err = xhr.responseText;
                if (err)
                    error(err);
                else
                    error({ Message: "Unknown server error." })
            }
            return;
        }
ServiceSucceeded - is get called when the service successfully return response. As you can see in the function I am checking DataType is jsonp which is just to demonstrate that service is returning jsonp data.

function ServiceSucceeded(result) {
            if (DataType == "jsonp") {
                
                    resultObject = result.GetEmployeeResult;
                    var string = result.Name + " \n " + result.Address ;
                    alert(string); 
            }
        }
GetEmployee - is function that get called to request data from WCF service hosted on other domain. As you can see in code DataType value is get set to jsonp.

function GetEmployee() {
            var uesrid = "1";
            Type = "GET";
            Url = "http://localhost:52136/Service1.svc/GetCustomer"; 
            DataType = "jsonp"; ProcessData = false;
            method = "GetCustomer";
            CallService();
        }

        $(document).ready(
         function () {
            
             GetEmployee();
         }
);
Solution 2 : Call WCF Service by Javascript

To call the service using javascript make use of ScriptManager


        
            
        
    
in above code I set the servicereferance to the WCF service hosted on other domain.
makeCall - is function that get called to request data from WCF service hosted on other domain.

function makeCall() {
                      var proxy = new JsonpAjaxService.Service1();
                     proxy.set_enableJsonp(true);
                     proxy.GetCustomer(onSuccess, onFail, null);
                 }
onSuccess - is called when the result from the service call is received and display data.

function onSuccess(result) {
                     alert( result.Name + " " +result.Address);
                 }
onFail - is called if the service call fails

function onFail(){
                     alert("Error");
                 }
Summary
So after the addition to the special property by the WCF team its quite easy to call cross domain WCF service.
References
JSONP - WIKI
Cross-domain communications with JSONP


29 comments:

  1. can you provide a sample of this please i cant seem to get it working. something about the callback

    ReplyDelete
  2. Pranay,
    The Get method works per you example. Do you have any example where 'POST' works on a cross domain environment?

    Thanks
    Mani

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. That seems to be quite confusing while working with the call function in JQuery.Ur blog was interesting with the simple steps explanation.
    web design company

    ReplyDelete
  5. Hello... I think you'll have the javascript loaded from the first page to do everything. If you bookmark the page and then come back to it the iframe loads the correct page (via a little script on domain1.com to process the location.href )

    Thanks,
    Jackie

    ReplyDelete
  6. Hi..
    Why did you put it in a jQuery? it would've worked the same if you dropped the $(), and wrote it as a simple JavaScript function. and this way you couldve called it easily as well.
    Anyways, i think you could call it from your JavaScript if you just put the call in the $() as well.

    Thanks,
    JavaScript Countdown Timer

    ReplyDelete
  7. This method only works with GET, and not POST.

    what is the reason of this line? var uesrid = "1"; is it passed to your service method?!

    ReplyDelete
  8. Nice tutorial but it seems there is something missing.

    I created a wcf service and a html page to consume that wcf service. I can track the response back from the wcf service but call back function for success or error doesn't trigger.

    Can you please suggest me anything I need to change??

    Regards,
    Chirag

    ReplyDelete
  9. try this:
    http://jasonkelly.net/2009/05/using-jquery-jsonp-for-cross-domain-ajax-with-wcf-services/

    ReplyDelete
  10. Certainly helpful for me and other readers also as I am finding so many good comments here.I hope that I can love it as much as you.

    ReplyDelete
  11. Great information on your site here. I love this post because we can get some useful information from your blog. I expect more post from you guys.

    ReplyDelete
  12. Your blog has importance changes at WCF servcie config file. Thanks for sharing those changes using scripts.

    ReplyDelete
  13. I do not even know how I ended up here, but I thought
    this post was great. I do not know who you are but certainly you are going
    to a famous blogger if you are not already ;) Cheers!
    My page - goedkope last minute

    ReplyDelete
  14. Thanks for your great info...really informative and more stuff on

    ReplyDelete
  15. Great source of information to share with the readers that's awesome i will take advantage from this and will these stuffs will be available for the users.

    ReplyDelete
  16. I really need this information about calling cross domain wcf. I definitely bookmark this blog and share with my close friends. Waiting for your next post to live.

    ReplyDelete
  17. hello, i gave the url
    "http://localhost:52136/Service1.svc/GetCustomer" its working fine. but when i give the system name(or domain name) instead of the localhost
    it is not working. below is the url what i gave http://inhydpadigoppul.agilitylogistics.in:81/Service.svc

    ReplyDelete
  18. Hi,
    this program works fine in the firefox but does not work in IE 8.0
    ?
    could you help me?

    ReplyDelete
  19. Cannot access methods with Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" in Service.svc Markup and having an error of empty /jsdebug without it.

    Please any body tell me what to do.

    ReplyDelete
  20. Hi Pranay,
    Thanks for creating excelent example. But when I host the service in my iis, that Jquery is not working. After hosting I get the URL http://localhost:84/Service1.svc. How can i get response from the above mentioned URL.

    Thanks in advance
    Santanu Biswas

    ReplyDelete
  21. I am sendingrequest like this https://api.subtledata.com/v1/locations?api_key=SlcrNFg0

    response (Output)like this

    [{"revenue_centers": [{"default_center": true, "revenue_center_id": 1909, "name": "Unassigned Revenue"}], "receipt_number_instructions": null, "employee_request_through_app": false, "menu_ordering_available": true, "payment_via_credit_card_available_message": null, "postal_code": "78701", "user_rating": "0", "location_id": 918, "app_specials": false, "city": "Austin", "location_name": "notous Test Dinerware System", "tender_types": [], "process_new_credit_cards": false, "table_number_instructions": null, "state": "TX", "color_theme": null, "latitude": 30.26652, "logo_url": "http://www.subtledata.com/I/Logo/?918", "website_url": null, "cross_streets": null, "ordering_available_message": null, "phone": "8143628149", "terminals": [], "location_picture_url": "http://www.subtledata.com/I/Results/?918", "favorites_ordering_available": true, "neighborhood_name": null, "discount_types": [{"default_discount": false, "discount_type_id": 939, "name": "Employee"}, {"default_discount": false, "discount_type_id": 940, "name": "Two Dollar Tuesday"}], "longitude": -97.7429367, "price_rating": 0, "process_pre_authed_cards": false, "address_line_2": null, "address_line_1": "401 Congress Avenue"}]
    Using ASP.net
    I am doing like this how can do using .NET
    please help me

    ReplyDelete
  22. Its Working fine in FireFox But not in IE 9 and Chrome.

    ReplyDelete
  23. hi Pranay,

    Great Article !! however i am facing issue when i am referring some dlls.
    1. Common.dll (which is 64 bit dll and in-turn refer Networking.dll--> "HIDClient.dll"(32-bit) some where in our WPF application)
    It gives a "System.BadImageFormatException" as it is not able to load the 32-bit HIDCLient.dll
    To solve this :
    "Enable 32-bit Application=True" in IIS Manager -->Application pools -done
    Change applicationhost.config http://stackoverflow.com/questions/14844293/command-to-rebuild-applicationhost-config-in-iis-7 -done
    not able to do :-http://stackoverflow.com/questions/5229310/system-badimageformatexception-could-not-load-file-or-assembly
    I am getting Error: No public installers with the RunInstallerAttribute.
    can you please give some guidance here?
    how to add installer/or use installutil.exe:
    Regards,
    Kamal

    ReplyDelete
  24. I am implementing same logic but getting parse error in my program

    ReplyDelete
  25. I tried this code but geeting parse error

    ReplyDelete
  26. Hello, i am glad to read the whole content of this blog and am very excited and happy to say that the webmaster has done a very good job here. mainan anak edukatif jual mainan edukatif,
    jual kostum anak

    ReplyDelete
  27. Excellent explanation with example! Thanks for your amazing jQuery tips on cross domain calling!!
    Website Redesign Services in Chennai

    ReplyDelete
  28. أهلاً بكم في ريفيرا إنفست ® للعقارات في ألانيا - الوسيط العقاري المحترف لشراء العقارات في تركيا

    ReplyDelete