Ho un servizio Web WCF/SVC che viene utilizzato da una chiamata JavaScript tramite AJAX. Si accede alla pagina tramite un proxy SSL (https://gate.company.com/MyPage
) ubicato nella DMZ che inoltra la richiesta al server Web interno (http://myLocalWebServer/MyPage
).La callback JavaScript javascript non è supportata nei servizi autenticati. Richiesta AJAX al servizio WCF tramite proxy SSL
Dopo tanto googeling e tentativi, sono riuscito a farlo funzionare, giocando con i parametri crossDomainScriptAccessEnabled
e Access-Control-Allow-Origin
. Anche se funziona solo se la modalità di autenticazione è impostata su false o se l'utente non ha ancora effettuato l'accesso. Non appena la chiamata viene effettuata da una pagina in cui è necessario accedere (autenticazione dei moduli), non funziona più. Il messaggio di errore ottengo allora è:
cross domain javascript callback is not supported in authenticated services
E funziona ancora, tuttavia, una volta logout e fare la chiamata da una pagina non protetta.
Il mio servizio assomiglia a questo
namespace MyNameSpace
{
[ServiceContract(Namespace = "MyNameSpace")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service
{
[OperationContract]
public string[] GetDropDownData(string id)
{
List<string> resultList = new List<string>();
...
return resultList.ToArray();
}
}
}
La chiamata di servizio ed il metodo di callback in JavaScript:
function fillDropdwon(dropId){
jQuery.ajax({
type: "POST",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
cache: true,
url: "Service.svc/GetDropDownData",
data: '{"dropId":"' + dropId + '"}',
jsonpCallback: "onDone",
error: function (a,b,c) {
alert("error");
}
});
}
// Callback-Methode after ServiceCall
function onDone(result) {
var theDropDown = jQuery("#<%= cboSelection.ClientID %>");
if (theDropDown.length > 0) {
//Clear the old entries
theDropDown.empty();
//Add an empty entry
if ("<%= cboSelection.ShowEmptyRow %>".toLowerCase() == "true") {
theDropDown.append($('<option></option>'));
}
// Add the found items
for (var i = 0; i < result.length; i++) {
var text = result[i];
theDropDown.append($('<option></option>').val(text).html(text));
}
}
}
Il web.config parte che riguarda il servizio:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="MyNameSpace.ServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="true" name=""/>
</webScriptEndpoint>
</standardEndpoints>
<services>
<service name="MyNameSpace.Service">
<!-- Service endpoint for HTTPS -->
<endpoint address="" behaviorConfiguration="MyNameSpace.ServiceAspNetAjaxBehavior" binding="webHttpBinding" bindingConfiguration="jsonpBinding" contract="MyNameSpace.Service" /> -->
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="jsonpBinding" crossDomainScriptAccessEnabled="true">
<security mode="None" />
</binding>
<binding name="jsonpSslBinding" crossDomainScriptAccessEnabled="true">
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
Per prima cosa ho provato a utilizzare il proxy AJAX di ASP.NET per chiamare il servizio, ma ciò non ha funzionato perché la chiamata w come fatto al server web direttamente, che non è SSL e l'errore che ho ottenuto era più o meno: 'Pagina https://gate.company.com/MyPage
provato a caricare non salvare il contenuto dalla pagina http://myLocalWebServer/MyPage
...'. Ecco perché ho usato la chiamata AJAX sopra elencata.
function fillDropdwon(dropId){
var service = new MyNameSpace.Service();
service.GetDropDownData(dropId, onDone);
}
Ho anche cercato di aggiungere quanto segue nel web.config
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- Enable Cross Domain AJAX calls -->
<remove name="Access-Control-Allow-Origin" />
<add name="Access-Control-Allow-Origin" value="https://gate.company.com"/>
</customHeaders>
</httpProtocol>
</system.webServer>
ho controllato le intestazioni inviate al server e ho visto che quando non sono entrato, l'intestazione è simile al seguente:
Request URL:`https://gate.company.com/MyPage/Servic.svc/GetDropDownData?callback=onDone`
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,fr-CH;q=0.2,fr;q=0.2
Connection:keep-alive
Content-Length:161
Content-Type:application/json; charset=UTF-8
Cookie:__utma=174172730.1157990369.1360852643.1381229705.1383150435.9; __utmc=174172730; __utmz=174172730.1369635484.4.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); promopost=oaezz3fzzj0o4l3fccxh0ss1;
ASP.NET_SessionID=
Host:`gate.company.com`
Origin:`https://gate.company.com`
Referer:`https://gate.company.com/MyPage/QuickCalculator.aspx?ObjectIdentity=47a93f52-6be6-4bd6-9600-e8eb9c8ff360`
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parametersview sourceview URL encoded
callback:onDone
Request Payloadview source
{dropId:123}
dropId: "123"
Response Headersview source
Cache-Control:private
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1339
Content-Type:application/x-javascript
Date:Sun, 01 Dec 2013 15:14:25 GMT
Keep-Alive:timeout=15, max=97
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-Powered-By
e la risposta è simile a questa.
onDone(["result1","result2"]);
Quando chiamo il servizio all'interno di una pagina protetta, ottengo questo:
Request URL:`https://gate.company.com/MyPage/Servic.svc/GetDropDownData?callback=onDone`
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,fr-CH;q=0.2,fr;q=0.2
Connection:keep-alive
Content-Length:161
Content-Type:application/json; charset=UTF-8
Cookie:__utma=174172730.1157990369.1360852643.1381229705.1383150435.9; __utmc=174172730; __utmz=174172730.1369635484.4.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); promopost=oaezz3fzzj0o4l3fccxh0ss1;
**ASP.NET_SessionID=; .ASPXAUTH=AB5ADCE12C7847CA452DD54D903E6787C7D1F0009B9E3277D2EC50DE9C421D1331B87A6DCA2432993933794AB9BDE833E44EC58E217D5AA1D588132C6E1C67D4AD7692840359D9A719EC2A53826CF54FDC0943B4E0AB29093920143E1E987080AC7C35E63594FD678535972D06AEC0AAF74AF8BE8DFC3746B499CB032E7771F10B924110DB344824B3253F9BECB3CDD8**
Host:`gate.company.com`
Origin:`https://gate.company.com`
Referer:`https://gate.company.com/MyPage/QuickCalculator.aspx?ObjectIdentity=47a93f52-6be6-4bd6-9600-e8eb9c8ff360`
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parametersview sourceview URL encoded
callback:onDone
Request Payloadview source
{dropId:123}
dropId: "123"
Response Headersview source
Cache-Control:private
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1339
Content-Type:application/x-javascript
Date:Sun, 01 Dec 2013 15:14:25 GMT
**jsonerror:true**
Keep-Alive:timeout=15, max=97
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
**X-Powered-By:ASP.NET**
e la risposta assomiglia a questo.
onDone({"ExceptionDetail":{"HelpLink":null,"InnerException":null,"Message":"Cross domain javascript callback is not supported in authenticated services.","StackTrace":" bei System.ServiceModel.Dispatcher.JavascriptCallbackMessageInspector.AfterReceiveRequest(Message& request, IClientChannel channel, InstanceContext instanceContext)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.AfterReceiveRequestCore(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)","Type":"System.NotSupportedException"},"ExceptionType":"System.NotSupportedException","Message":"Cross domain javascript callback is not supported in authenticated services.","StackTrace":" bei System.ServiceModel.Dispatcher.JavascriptCallbackMessageInspector.AfterReceiveRequest(Message& request, IClientChannel channel, InstanceContext instanceContext)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.AfterReceiveRequestCore(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)"},500);
La differenza principale è che c'è un SessionID e la jsonerror: true per la versione "login".
C'è un modo per risolvere questo problema?
Non è possibile "disabilitare" l'autenticazione per la richiesta AJAX cambiando l'intestazione prima della chiamata o qualcosa del genere. O c'è qualche errore nel mio codice, web.config?
Apprezzo qualsiasi suggerimento, visto che ci provo da molto tempo.
rimuovere la proprietà 'crossDomainScriptAccessEnabled' nel bind di configurazione è stato risolto per me. – Seany84