你的位置:首页 > ASP.net教程

[ASP.net教程]实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法


关于ajax跨域调用WCF服务的方法很多,经过我反复的代码测试,认为如下方法是最为简便的,当然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义还是延用上次的,如:

namespace WcfService1{  [ServiceContract]  public interface IAddService  {    [OperationContract]    [WebInvoke(Method="GET",RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,BodyStyle=WebMessageBodyStyle.WrappedRequest)]    int Add2(int a,int b);  }}namespace WcfService1{  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  //[JavascriptCallbackBehavior(UrlParameterName="jsoncallback")] //不指定的时采用默认的callback回调参数  public class AddService : IAddService  {    public int Add2(int a, int b)    {      return a + b;    }  }}

创建一个WCF服务文件,文件内容:

<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.AddService" %>

上面实现的是支持GET方法请求调用,下面就是配置WEB.CONFIG,使其支持跨域调用,注意我将standardEndpoints注释掉了,当然如果不注释也不会有什么影响,关键是bindings节点中的属性:crossDomainScriptAccessEnabled="true",如下:

 <system.serviceModel>  <!--<standardEndpoints>   <webHttpEndpoint>    <standardEndpoint crossDomainScriptAccessEnabled="true" />   </webHttpEndpoint>  </standardEndpoints>-->  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />  <bindings>   <webHttpBinding>    <binding crossDomainScriptAccessEnabled="true">    </binding>   </webHttpBinding>  </bindings>  <behaviors>   <serviceBehaviors>    <behavior>     <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->     <serviceMetadata httpGetEnabled="true"/>     <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->     <serviceDebug includeExceptionDetailInFaults="true"/>    </behavior>   </serviceBehaviors>   <endpointBehaviors>    <behavior name="AddServiceBehavior">     <enableWebScript />    </behavior>   </endpointBehaviors>  </behaviors>  <services>   <service name="WcfService1.AddService">    <endpoint address="" binding="webHttpBinding" contract="WcfService1.IAddService" behaviorConfiguration="AddServiceBehavior" ></endpoint>   </service>  </services> </system.serviceModel>

创建Global.asax文件并添加如下的代码:

    protected void Application_BeginRequest(object sender, EventArgs e)    {      HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);      HttpContext.Current.Response.Cache.SetNoStore();      EnableCrossDmainAjaxCall();    }    private void EnableCrossDmainAjaxCall()    {      HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");      if (HttpContext.Current.Request.HttpMethod == "OPTIONS")      {        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();      }    }

下面是实现WEB端跨域调用WCF服务代码

1.采用原生的

//简单封装    var $ = function (id) {      return document.getElementById(id);    };    function get

 

 

2.通过动态以JS方式请求WCF地址资源实现原始的跨域方法,虽然可以实现跨域调用,但只支持GET方式,如果需要支持POST这个方案就无解:

    $("btnGet").onclick = function () {      var querystr = "a=" + $("num1").value + "&b=" + $("num2").value;      var script =document.getElementById("crossDomainScript_wcf") || document.createElement("script");      script.type = "text/javascript";      script.id = "crossDomainScript_wcf";      script.src = "http://localhost:30348/addservice.svc/Add2?callback=success_callback&" + querystr;      document.getElementsByTagName("head")[0].appendChild(script);    }    //回调方法    function success_callback(data) {      $("result").value = data;    }

以下是POST调用:

    $("btnGet").onclick = function () {      var 

2.采用jQuery.ajax来调用:

    var jq = jQuery.noConflict();    jq("#btnGet").click(function () {      jq.ajax("http://localhost:30348/AddService.svc/Add2", {        type: "get",        dataType: "jsonp",        data: 'a=' + jq("#num1").val() + '&b=' + jq("#num2").val(),        success: function (data) {          jq("#result").val(data);        },        error: function (x, textStatus, errorThrown) {          alert("error:" + textStatus);        }      });    });

其实可按正常方式直接调用,无需采用JSONP,因为WCF服务端已支持跨域调用:

    var jq = jQuery.noConflict();    jq("#btnGet11").click(function () {      jq.ajax("http://localhost:30348/AddService.svc/Add2", {        type: "GET",        dataType: "json",        data: 'a=' + jq("#num1").val() + '&b=' + jq("#num2").val(),        success: function (data) {          jq("#result").val(data.d);        },        error: function (x, textStatus, errorThrown) {          alert("error:" + textStatus);        }      });    });

  

当然传参时也可以用JSON的写法(注意POST与GET的JSON写法有所不同,POST时键值必需是严格的JSON字符串,GET时是一个JS对象),再此就不作说明

POST调用:(注意上述JQUERY.AJAX 采用JSONP+GET模式不适用于POST模式,因为经调试,发现采用JSONP模式,终始发起的是GET请求,采用的原理是上面我写的原始跨域调用方法)

    var jq = jQuery.noConflict();    jq("#btnGet").click(function () {      jq.ajax("http://localhost:30348/AddService.svc/Add2", {        type: "POST",        dataType: "json",        contentType: "application/json",        data: '{"a":' + jq("#num1").val() + ',"b":' + jq("#num2").val() + '}',        success: function (data) {          jq("#result").val(data.d);        },        error: function (x, textStatus, errorThrown) {          alert("error:" + textStatus);        }      });    });

这里针对跨域再特别说明一下,若采用AJAX跨域调用时,会发送两次请求,第一次为OPTIONS,用于服务器进行预检,第二次才会发出真正的请求,这也就是为什么WCF服务的Global.asax需要添加EnableCrossDmainAjaxCall的原因。本人在研究跨域调用WCF时,走了很多弯路,也尝试过很多方法,但最终还是弄明白了,希望大家能从这篇博文中受益,文中不足之处,敬请指出,谢谢!