文章出處

關于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.采用原生的XMLHttpRequest跨域調用WCF服務:

//簡單封裝
        var $ = function (id) {
            return document.getElementById(id);
        };

        function getXMLHTTPRequest() {
            var req = false;
            try {
                req = new XMLHttpRequest();
            } catch (err) {
                try {
                    req = new ActiveXObject("Msxml2.XMLHTTP");
                } catch (err) {
                    try {
                        req = new ActiveXObject("Microsoft.XMLHTTP");
                    } catch (err) {
                        req = false;
                    }
                }
            }
            return req;
        }

//以下為按鈕的點擊事件,我采用的同步調用,當然也可以采用回調方式,回調方式的話就需要在請求的URL中加入:callback=回調方法,然后再定義一個回調方法即可
        $("btnGet").onclick = function () {
            var querystr = "a=" + $("num1").value + "&b=" + $("num2").value;
            var xmlhttp = getXMLHTTPRequest();
            xmlhttp.open("GET", "http://localhost:30348/addservice.svc/Add2?" + querystr, false);
            xmlhttp.send();
            var r = eval("(" + xmlhttp.responseText + ")"); 
            $("result").value = r.d;
        }

 

 

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 xmlhttp = getXMLHTTPRequest();
            xmlhttp.open("POST", "http://localhost:30348/addservice.svc/Add2", true);
            xmlhttp.setRequestHeader("Content-Type", "application/json");
            xmlhttp.onreadystatechange = function () {
                alert(xmlhttp.status);
                if (xmlhttp.readyState == 4) {
                    if (xmlhttp.status == 200) {
                        var r = eval("(" + xmlhttp.responseText + ")");
                        $("result").value = r.d;
                    }
                }
            };
            xmlhttp.send('{"a":' + $("num1").value + ',"b":' + $("num2").value + '}');
        }

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時,走了很多彎路,也嘗試過很多方法,但最終還是弄明白了,希望大家能從這篇博文中受益,文中不足之處,敬請指出,謝謝!


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()