Как отправить вызов XDomainRequest в метод службы WCF с параметрами
Я думаю, что прочитал каждый пост Stackru в XDomainRequest и еще несколько десятков в AJAX и WCF, но у меня все еще возникают проблемы с получением вызова XDomainRequest AJAX. Я реализовал CORS ("Access-Control-Allow-Origin") в моей службе WCF, и мой код прекрасно работает с xmlHttpRequest в Chrome и Firefox, но я делаю вызовы междоменными, и поэтому для IE мне нужно использовать Объект XDomainRequest. Мой xdr работает нормально, когда я получаю или POST метод, у которого нет аргументов, и я даже могу успешно использовать глагол GET для метода с аргументами, используя строку запроса, но когда я пытаюсь POST к методу с аргументами, мой xdr выдает ошибка, несмотря на то, что я поставил точку останова в методе BeginRequest и вижу, что Ответ от сервера - "200 OK". Я хотел бы думать, что я попробовал каждую комбинацию настроек файла конфигурации, но я должен что-то упустить. Любая помощь в указании меня в правильном направлении очень ценится.
Вот соответствующие части моего кода:
WCF - Global.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
//for CORS
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
}
WCF - IService1.cs
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST")]
string GetData();
[OperationContract]
[WebInvoke(Method = "POST")]
string GetData2(string param);
}
WCF - Service1.svc
public class Service1 : IService1
{
public string GetData()
{
return "Hello";
}
public string GetData2(string param)
{
return string.Format("Hello - {0}", param);
}
}
WCF - Web.config
<?xml version="1.0"?>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="WcfService1.Service1Behavior" name="WcfService1.Service1">
<endpoint address="AjaxEndpoint" behaviorConfiguration="AjaxBehavior" contract="WcfService1.IService1" bindingConfiguration="AjaxBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<!--<serviceMetadata httpGetEnabled="true" />-->
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="AjaxBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="AjaxBinding"/>
</webHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Клиентский AJAX звонок
var WcfURL = "http://localhost/WcfService1/Service1.svc/AjaxEndpoint"
if (window.XDomainRequest) {
//IE - use cross-domain request
xdr = new XDomainRequest();
xdr.onprogress = function () { alert("onprogress: " + xdr.responseText) };
xdr.onload = function () { updateText(xdr.responseText) };
xdr.onerror = function () { alert("xdr error") };
xdr.timeout = 7500;
xdr.ontimeout = function () { alert("xdr timeout") };
var data = "passedInParam";
//var method = "/GetData"; //this works
var method = "/GetData2"; //this throws an error
xdr.open("POST", WcfURL + method);
xdr.send(data);
}
1 ответ
Я нашел решение. Благодаря Fiddler, я смог увидеть больше ответов, которые я получал от сервиса. Ошибка была
Входящее сообщение имеет неожиданный формат сообщения "Raw". Ожидаемые форматы сообщений для операции: "Xml", "Json". Это может быть связано с тем, что в привязке не настроен WebContentTypeMapper.
Вооружившись этой информацией, я начал изучать WebContentTypeMapper. Я нашел эту статью полезной, и после добавления метода WebContentTypeMapper я смог увидеть, что contentType моего запроса, поступающего из XDomainRequest, имел тип "application/json" (как и ожидалось), когда я не включил аргумент в XDomainRequest. Метод send(), но изменился на тип "application/octet-stream" при передаче аргумента. (т.е. xdr.send(data)) Я не знаю, почему он изменяется на octet-stream, но при этом это приведет к тому, что сервисный метод выдаст ошибку 500 (с сообщением сверху) и, следовательно, вызовет ошибку запроса xdr. Но имя WebContentTypeMapper удачно названо, и использовать его для изменения contentType достаточно просто. После исправления этого типа Json мой xdr работает хорошо.
Вот метод:
public class CustomContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
if (contentType == "application/octet-stream")
{
return WebContentFormat.Json;
}
else
{
return WebContentFormat.Default;
}
}
}
И вот части файла конфигурации, которые были обновлены:
<endpoint address="AjaxEndpoint" behaviorConfiguration="AjaxBehaviour" contract="WcfService1.IService1" binding="customBinding" bindingConfiguration="CustomMapper"/>
...
<bindings>
<customBinding>
<binding name="CustomMapper">
<webMessageEncoding webContentTypeMapperType="WcfService1.CustomContentTypeMapper, WcfService1" />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>