如何从JavaScript调用WCF服务?

7

我正在尝试使用jQuery从ajax调用中调用WCF服务。 我设法从SOAP-UI和Excel/VBA中调用WCF。 我的问题来自发送的OPTIONS请求,但没有POST请求:

  • 如果我将URL设置为http://mywcf/service.svc,则会发送OPTIONS并获得400 Bad Request状态,并且不会发送POST请求。在这种情况下,标头中缺少HTTP/1.1(与SOAP-UI标头相比)。
  • 如果我将URL设置为http://mywcf/service.svc HTTP/1.1,则会发送OPTIONS并获得200 OK状态,但不会发送POST请求。在这种情况下,HTTP/1.1似乎被解释为文件名。

有人能告诉我如何从javascript调用WCF的POST操作并添加HTTP/1.1标头,而不破坏服务URL吗?

这是我ajax调用的摘录:

var soapData = ''
        +'<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:mic="http://microsoft.wcf.documentation">'
        +'    <soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsrm="http://docs.oasis-open.org/ws-rx/wsrm/200702">'
        +'        <wsrm:Sequence>'
        +'            <wsrm:Identifier>s:Sender a:ActionNotSupported</wsrm:Identifier>'
        +'            <wsrm:MessageNumber>1</wsrm:MessageNumber>'
        +'        </wsrm:Sequence>'
        +'        <wsa:Action>http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</wsa:Action>'
        +'        <wsa:ReplyTo>'
        +'            <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>'
        +'        </wsa:ReplyTo>'
        +'        <wsa:MessageID>uuid:'+ MsgUid +'</wsa:MessageID>'
        +'        <wsa:To>'+ Url +'</wsa:To>'
        +'    </soap:Header>'
        +'    <soap:Body xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm">'
        +'        <wsrm:CreateSequence>'
        +'            <wsrm:AcksTo xmlns:wsa="http://www.w3.org/2005/08/addressing">'
        +'                <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>'
        +'            </wsrm:AcksTo>'
        +'            <wsrm:Offer>'
        +'                <wsrm:Identifier>urn:soapui:'+ SeqUid +'</wsrm:Identifier>'
        +'            </wsrm:Offer>'
        +'        </wsrm:CreateSequence>'
        +'    </soap:Body>'
        +'</soap:Envelope>';

$.ajax({
    type: 'POST',
    url: 'http://mywcf/service.svc', // with or without +' HTTP/1.1'
    data: soapData,
    contentType: 'application/soap+xml;charset=UTF-8',
    dataType: 'xml'
});

我 WCF 的 web.config 中的值:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="POST, OPTIONS" />
            <add name="Access-Control-Allow-Headers" value="*" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

1
一个明显的问题是您调用中的网址。您需要在网址中包含WCF方法名称。 - Sparrow
请问能否解释一下为什么要点踩,谢谢。 - sinsedrix
通常,一个服务(.svc文件)有多个Web服务方法,你对服务的调用应该定义目标方法,所以在大多数应用中,目标方法名是URL的一部分。我在你的SOAP中看到了一个奇怪的代码,定义了'action'和'reply to'。也许你的服务使用这些字段来定义服务方法。我不确定'reply to'是什么用途。可能是问题所在吗? - Sparrow
我使用SOAP-UI生成了“action”和“replyTo”元素,它们是WS-Addressing所需的。因此,我将它们复制到我的SOAP信封中,以进行AJAX调用。另一方面,在URL中设置方法名称会给我相同的“400 Bad Request”状态。 - sinsedrix
&sinsedrix,你可能会在这里找到答案:https://www.aspsnippets.com/Articles/Make-AJAX-JSON-call-to-ASP.Net-WCF-Service-using-jQuery-and-Javascript.aspx - Ramankingdom
显示剩余4条评论
3个回答

3
使用jQuery调用Web服务,也就是向WCF服务发出调用请求,您可以使用jQuery.ajax()或jQuery.getJSON()。本文中我使用了jQuery.ajax()方法。
要设置请求,首先定义一个变量。当您调用多个方法并创建不同的js文件来调用WCF服务时,这将非常有用。
<script type="text/javascript">

    var Type;
    var Url;
    var Data;
    var ContentType;
    var DataType;
    var ProcessData;

以下函数初始化在上面定义的变量,以便调用服务。
function WCFJSON() {
    var userid = "1";
    Type = "POST";
    Url = "Service.svc/GetUser";
    Data = '{"Id": "' + userid + '"}';
    ContentType = "application/json; charset=utf-8";
    DataType = "json"; varProcessData = true; 
    CallService();
}

CallService函数通过在$.ajax中设置数据来向服务发送请求。
// 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
    });
}

function ServiceFailed(result) {
    alert('Service call failed: ' + result.status + '' + result.statusText);
    Type = null;
    varUrl = null;
    Data = null; 
    ContentType = null;
    DataType = null;
    ProcessData = null;
}

注意:以下代码检查result.GetUserResult语句,因此您的结果对象将获得属性your service method name + Result。否则,在Javascript中会出现“对象未找到”的错误。
function ServiceSucceeded(result) {
    if (DataType == "json") {
        resultObject = result.GetUserResult;

        for (i = 0; i < resultObject.length; i++) {
            alert(resultObject[i]);
        }

    }

}

function ServiceFailed(xhr) {
    alert(xhr.responseText);

    if (xhr.responseText) {
        var err = xhr.responseText;
        if (err)
            error(err);
        else
            error({ Message: "Unknown server error." })
    }

    return;
}

$(document).ready(
    function() {
        WCFJSON();
    }
);
</script>

1
添加 webHttpBinding 终结点。
    <services>
  <service name="Contract">
    <endpoint address="json" binding="webHttpBinding"  contract="IContract" bindingConfiguration="ActionsHttpBinding" behaviorConfiguration="ActionrestfulBehavior"/>
  </service>

然后通过ajax调用端点,使用post或get方法,如下所示:

    var data = JSON.stringify({
    param1: val1,
    param2: val2
});
$.ajax({
    url: "http://mywcf/service.svc/json/FunctionName",
    type: "POST",
    data: data,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    processData: true
}).then(function (rsutlt) {

}).fail(function (fail) {
});

0
请将以下代码添加到您的global.asax.cs文件中,并从您的Web配置中删除customHeaders。
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, PUT, DELETE");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }

    }

同时,您需要删除OPTIONSVerbHandler以启用跨域资源共享。

 <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接