Introduction:
This article is about to call the cross domain WCF service from your 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.
From last couple of days, I was trying to call a wcf service using jquery that is hosted in different domain. But every time I was failed to call wcf service from different domain. After spending much time on R&D, I found the solution and the reason why I was unable to call cross domain wcf service.
Whenever you try to call a cross domain WCF Service by javascript or jquery, it behaves differently with different browsers. When you want to perform "POST" or "GET" request on cross domain wcf service or normal service using jquery/javascript or ajax, the browser actually sends an "OPTIONS" verb call to your wcf service that is not mention in your wcf method attribute. We mention there "POST" or "GET" to call a wcf service method. Hence we get error to call cross domain wcf service. We find the following request and response headers in firefox when we try to call wcf service.
JSONP - JSON with Padding:
Ajax allows to get data in the background without interfering with the display. Ajax call done by using XMLHttpRequestobject allows 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 gets issued when requesting data from another domain. One way to avoid security errors is to control remote server where data resides and every request goes to the same domain. That gives rise to the question, what's the fun if data comes from own server only? What to do if data is required to get from the other server?
There is one way to come out from this limitation - 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.
Request Headers
Response Headers
In above request headers the method is "OPTION" not "POST" and the response headers has content-type "text/html; charset=UTF-8" instead of "json;charset=UTF-8". To change these options we need to do some changes in web.config of hosted wcf service.
Configure WCF Cross Domain service
Wcf calling using Jquery
Note:
This article is about to call the cross domain WCF service from your 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.
From last couple of days, I was trying to call a wcf service using jquery that is hosted in different domain. But every time I was failed to call wcf service from different domain. After spending much time on R&D, I found the solution and the reason why I was unable to call cross domain wcf service.
Whenever you try to call a cross domain WCF Service by javascript or jquery, it behaves differently with different browsers. When you want to perform "POST" or "GET" request on cross domain wcf service or normal service using jquery/javascript or ajax, the browser actually sends an "OPTIONS" verb call to your wcf service that is not mention in your wcf method attribute. We mention there "POST" or "GET" to call a wcf service method. Hence we get error to call cross domain wcf service. We find the following request and response headers in firefox when we try to call wcf service.
Cross Domain WCF Service Calling |
Ajax allows to get data in the background without interfering with the display. Ajax call done by using XMLHttpRequestobject allows 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 gets issued when requesting data from another domain. One way to avoid security errors is to control remote server where data resides and every request goes to the same domain. That gives rise to the question, what's the fun if data comes from own server only? What to do if data is required to get from the other server?
There is one way to come out from this limitation - 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.
Request Headers
OPTIONS http://myserver/MyService.svc/GetStates HTTP/1.1 Host: 192.168.4.156 User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Proxy-Connection: keep-alive Origin: http://192.168.4.156:90 Access-Control-Request-Method: OPTION Access-Control-Request-Headers: content-type Pragma: no-cache Cache-Control: no-cache
Response Headers
HTTP/1.0 405 Method Not Allowed Cache-Control: private Allow: POST Content-Length: 1565 Content-Type: text/html; charset=UTF-8 Server: Microsoft-IIS/7.0 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Access-Control-Allow-Origin: * Access-Control-Allow-Headers: Content-Type Date: Fri, 04 May 2012 12:05:17 GMT X-Cache: MISS from c1india.noida.in X-Cache-Lookup: MISS from c1india.noida.in:3128 Via: 1.0 c1india.noida.in:3128 (squid/2.6.STABLE21) Proxy-Connection: close
In above request headers the method is "OPTION" not "POST" and the response headers has content-type "text/html; charset=UTF-8" instead of "json;charset=UTF-8". To change these options we need to do some changes in web.config of hosted wcf service.
Configure WCF Cross Domain service
namespace CrossDomainWcfService { [DataContract] public class Supplier { [DataMember] public string Name; [DataMember] public string Email; } [ServiceContract(Namespace = "")] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class MyService { [OperationContract] [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] List GetEmpList (int OrgID) { // Fetch data from database var q= (from tbl in mobjentity.Customer where tbl.OrgID=OrgID).ToList(); Listlst= new List(); foreach(var supp in q) { Supplier msupp=new Supplier(); msupp.Name=supp.Name; msupp.Email=supp.Email //Make Supplier List to retun lst.Add(msupp); } return lst; } } }
WCF Service Web.config
<system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="*" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> </customHeaders> </httpProtocol> </system.webServer> <system.serviceModel> <behaviors> . . . </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> <standardEndpoints> <webScriptEndpoint> <standardEndpoint name="" crossDomainScriptAccessEnabled="true" /> </webScriptEndpoint> </standardEndpoints> <services> . . </service> </services> <bindings> . . </bindings> <client> . . </client> </system.serviceModel>
Global.asax Code
You can also define your hosted service web.config setting in Global.asax file. If you have defined setting in web.config then there is no need to do here.
protected void Application_BeginRequest(object sender, EventArgs e) { HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin" , ”*”); if (HttpContext.Current.Request.HttpMethod == "OPTIONS" ) { //These headers are handling the "pre-flight" OPTIONS call sent by the browser 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(); } }
Wcf calling using Jquery
$.ajax({ type: "Post" url: "http://www.yourdomain.com/MyService.svc/GetEmpList", // Location of the service data: '{"OrgID"="1"}', //Data sent to server contentType: "application/json;charset-uf8", // content type sent to server dataType: "json", //Expected data format from server success: function (msg) { //Implement get data from service as you wish }, error: function (err) { // When Service call fails } });
Note:
- You can define cross domain setting either in web.config or in global.asax file of your wcf service.
- For running the code, make a virtual directory/web application on IIS and map the code folder to it.
No comments:
Post a Comment