WCF 4,JSONP和jQuery导致parsererror

时间:2012-03-27 03:08:53

标签: jquery ajax wcf jsonp parse-error

我已经尝试了几乎所有我能想到的东西,但是我仍然遇到了对我的ajax调用WCF服务的问题。

我的WCF服务有如下方法:

//[WebInvoke(ResponseFormat = WebMessageFormat.Json, Method = "POST")]
[WebGet]    
public string Test(int value)
{
    return string.Format("You entered: {0}", value);
}

正如Twitter by Patrick Thomas所述,我也尝试过使用[WebGet(BodyStyle = WebMessageBodyStyle.Wrapped)][WebGet(BodyStyle = WebMessageBodyStyle.WrappedResponse)]而没有运气。

配置如下:

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior>
                <serviceMetadata httpGetEnabled="true" />
                <serviceDebug includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="RestEndpoint">
                <enableWebScript/>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <bindings>
        <webHttpBinding>
            <binding name="NoSecurityRestBinding" crossDomainScriptAccessEnabled="true">
                <security mode="None" />
            </binding>
        </webHttpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
        <service name="WebServices.TestService">
            <endpoint address="" binding="webHttpBinding" contract="WebServices.ITestService" bindingConfiguration="NoSecurityRestBinding" behaviorConfiguration="RestEndpoint" />
        </service>
    </services>
</system.serviceModel>

该服务位于不同的域上,因此我将数据格式化为JSONP:

$.ajax({
    cache: false,
    async: true,
    type: "GET", // Was "POST"
    dataType: "jsonp",
    url: "http://mydomain.com/TestService.svc/Test?callback=?",
    data: dataToPost,
    contentType: "application/json;charset=utf-8",
    success: function (msg) {
        var testMsg = JSON.parse(msg);
        var status = testMsg.TestResult;
        alert(status);
    },
    error: function (msg) {
        alert('Please email Jason with this exception: ' + msg.statusText);
    }
});

我得到了:

  

“parsererror”

     

“jQuery16408722478272714725_1332817261195未被调用”

我可能做错了什么?我确实验证了所有WCF二进制文件都是4.0。

提前感谢您的帮助!

6 个答案:

答案 0 :(得分:2)

您不希望将enableWebScript行为应用于端点。这特别支持Microsoft的ASP.NET AJAX客户端堆栈,该堆栈具有针对所有请求/响应的特定JSON编码。只用webHttp替换它,看看是否能解决您的问题。其他一切看起来都不错。

我建议的下一步是将webHttp行为元素的the automaticFormatSelection attribute设置为true。这样,当它检测到HTTP请求的接受内容类型是JSON时,它确保将响应序列化为JSON。

<强>更新

我刚才记得的是,由于这是JSONP,请求将来自<script/>标记,因此WCF可能默认为XML响应。因此, 也希望在="Json"行为上设置defaultOutgoingResponseFormat webHttp,以便默认情况下使用JSON格式化响应。

作为旁注,在jQuery AJAX请求上设置contentType是没有意义的,因为JSONP请求没有正文,因为它基于所有查询字符串。

答案 1 :(得分:2)

如果您想避免WCF web.config麻烦,那么您可以将“Factory”属性添加到您的WCF标记中。

如果您还想进行JSONP调用并避免出现parsererror问题,请使用此类:

<%@ ServiceHost Language="C#" Service="MyWebApp.MyWCFService" Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"  %>

使用以下类覆盖工厂

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel.Activation;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;

public class JSONPEnabledWebServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new JSONPEnabledWebServiceHost(serviceType, baseAddresses);
    }

    private class JSONPEnabledWebServiceHost : WebServiceHost
    {
        public JSONPEnabledWebServiceHost(Type serviceType, Uri[] baseAddresses) : base(serviceType, baseAddresses)
        {
        }

        protected override void OnOpening()
        {
            base.OnOpening();
            foreach (ServiceEndpoint endpoint in this.Description.Endpoints) {
                WebHttpBinding webBinding = endpoint.Binding as WebHttpBinding;
                if (webBinding != null) {
                    webBinding.CrossDomainScriptAccessEnabled = true;
                }
            }
        }
    }
}

所以现在你的工厂属性将是

<%@ ServiceHost Language="C#" Service="MyWebApp.MyWCFService" Factory="MyWebApp.JSONPEnabledWebServiceHostFactory"  %>

答案 2 :(得分:1)

JSONP和跨域调用不支持POST请求。 JSONP返回由填充(回调函数)包装的JSON片段。在后面,这被处理为页面DOM中动态添加的script元素,该元素指向跨域地址。加载目标脚本资源后,将执行回调函数。因此,您只能使用GET请求 - script元素无法执行POST。

答案 3 :(得分:1)

添加jsonpCallback选项

$.ajax({

    jsonpCallback: 'yourCallbackFunctionName',

    cache: false,
    async: true,
    type: "GET", // Was "POST"
    dataType: "jsonp",
    url: "http://mydomain.com/TestService.svc/Test?callback=?",
    data: dataToPost,
    contentType: "application/json;charset=utf-8",
    success: function (msg) {
        var testMsg = JSON.parse(msg);
        var status = testMsg.TestResult;
        alert(status);
    },
    error: function (msg) {
        alert('Please email Jason with this exception: ' + msg.statusText);
    }
});

答案 4 :(得分:1)

这个问题在过去的3年里曾多次被我误认。每次我遇到它并修好它然后忘了记笔记。下次它发生时,我开始抓挠并再次寻找解决方案。所以,让我在这里记录我的解决方案并与可能处理此问题的人分享。按照以下步骤确保您使用的是JQuery 1.8或更高版本的.net framework 4.0,它将起作用。

  • 在system.serviceModel注释下的行为记录中,设置为webHttp:
<behaviors>
  <endpointBehaviors>
    <behavior name="webHttpBehavior">
      <webHttp />
    </behavior>
  </endpointBehaviors>
</behaviors>
  • 定义JsonP绑定:
<bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
      </webHttpBinding>
    </bindings>
  • 将您的服务bindingConfiguration设置为刚刚定义的绑定
<services>
  <service name="dpRestService.qcmmsService">
    <endpoint address="" behaviorConfiguration="webHttpBehavior"
      binding="webHttpBinding" bindingConfiguration="webHttpBindingWithJsonP"
      contract="gwsRestService.qcmmsService" />
  </service>
</services>
  • 将Jaon添加为ResponseFormat属性的响应格式
  

[WebGet(UriTemplate =“您的服务模板”,ResponseFormat =   WebMessageFormat.Json)]

  • Jquery请求:
  

$。AJAX({               url:url,               type:'GET',// ajax调用的类型               数据:{},               contentType:'application / json',               crossDomain:true,               dataType:'jsonp',
              成功:callBackFun,               错误:errorFun           });

我希望这会有所帮助。

答案 5 :(得分:-1)

经过多次的痛苦,我设法得到一个简单的jquery / ajax调用一个简单的休息服务返回带回调的jsonp。在尝试在url中设置回调后我终于来了 设法通过将“jsonpCallback”和回调名称添加到参数来使其工作。

$.ajax({
        type : 'GET',
        url : 'http://localhost:8080/RestimpleApp/report/extract',
        dataType : 'jsonp',
        jsonpCallback : "jsoncallback",
        success : function(json) {
            alert('success');

        },
        error : function(jqXHR, status) {
            alert("Failed " + status + jqXHR);
        }
    });

在服务器端,我必须将回复JSON包装在回调名称中(“jsoncallback”)。

@GET
@Produces({ MediaType.APPLICATION_JSON })
public String extractData() {
    System.out.println("Incoming call = ");
    StringBuilder json = new StringBuilder("jsoncallback(");

    json.append("{\"sEcho\": 7,");
    json.append("\"iTotalRecords\": \"600\",");
    json.append("\"iTotalDisplayRecords\": \"12\",");
    json.append("\"aaData\": [");
    json.append("{");
    json.append("\"engine\": \"Gecko\",");
    json.append("\"browser\": \"Firefox 1.0\",");
    json.append("\"platform\": \"Win 98+ / OSX.2+\",");
    json.append("\"version\": \"1.7\",");
    json.append("\"grade\": \"A\"");
    json.append("},");
    json.append("{");
    json.append("\"engine\": \"Gecko\",");
    json.append("\"browser\": \"Firefox 1.5\",");
    json.append("\"platform\": \"Win 98+ / OSX.2+\",");
    json.append("\"version\": \"1.8\",");
    json.append("\"grade\": \"A\"");
    json.append("}  ]");
    json.append("}");
    json.append(");");


    return json.toString();
}
浪费了很多时间试图让它发挥作用:(