WCF 4, JSONP и jQuery вызывают parsererror - PullRequest
2 голосов
/ 27 марта 2012

Я перепробовал почти все, что мог придумать, но у меня все еще возникают проблемы с моими вызовами ajax в службу WCF.

В моей службе WCF есть метод, подобный приведенному ниже:

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

Как уже упоминалось в Твиттере Патрика Томаса , я также пытался использовать [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 ]

2 голосов
/ 28 сентября 2012

Если вы хотите избежать хлопот WCF web.config, то можете добавить атрибут «Фабрика» в разметку 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 голосов
/ 27 марта 2012

Вы не хотите, чтобы поведение enableWebScript применялось к конечной точке.Это, в частности, обеспечивает поддержку клиентского стека Microsoft ASP.NET AJAX, который имеет специальную кодировку JSON для всех запросов / ответов.Замените это просто webHttp и посмотрите, решит ли это вашу проблему.Все остальное выглядит хорошо для меня.

Следующее, что я хотел бы предложить, это установить атрибут automaticFormatSelection элемента поведения webHttp в значение true.Таким образом, он будет проверять сериализацию ответа как JSON, когда обнаружит, что принятым типом содержимого HTTP-запроса является JSON.

Обновление

Я только что вспомнил, что, поскольку это JSONP, запрос будет поступать из тега <script/>, и поэтому WCF, вероятно, по умолчанию будетXML-ответ.Поэтому вы также хотите установить defaultOutgoingResponseFormat="Json" для поведения webHttp, чтобы оно по умолчанию форматировало ответы с использованием JSON.

В качестве примечания: бессмысленно устанавливать contentType в запросе jQuery AJAX, потому что нет тела для запросов JSONP, поскольку все это основано на строке запроса.

1 голос
/ 11 декабря 2013

Эта проблема меня несколько раз беспокоила за последние 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>
  • установите для конфигурации привязки службы значениетолько что определенная привязка
<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, тип: 'GET', // Тип данных вызова ajax: {}, contentType: 'application / json', crossDomain: true, dataType: 'jsonp',
success: callBackFun, error: errorFun});

Надеюсь, это поможет.

1 голос
/ 26 января 2013

Добавьте параметр 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);
    }
});
1 голос
/ 27 марта 2012

JSONP и междоменные вызовы не поддерживают запросы POST.JSONP возвращает фрагмент JSON, обернутый отступом (функция обратного вызова).Кроме того, это обрабатывается как динамически добавляемый элемент script в DOM вашей страницы, который указывает на междоменный адрес.Как только целевой ресурс скрипта загружен, выполняется функция обратного вызова.Из-за этого вы можете использовать только запросы GET - элемент script не может выполнить POST.

0 голосов
/ 26 марта 2014

После большой боли мне удалось получить простой вызов 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();
}

много часов потрачено впустую, пытаясь заставить это работать: (

...