I have a WCF / SVC web service which is consumed by a JavaScript call via AJAX.
The page is accessed via a SSL proxy (https://gate.company.com/MyPage
) located in the DMZ which then forwards the request to the internal webserver (http://myLocalWebServer/MyPage
).
After a lot of googeling and trying around, I was able to make it work, playing around with the parameters crossDomainScriptAccessEnabled
and Access-Control-Allow-Origin
. Although, it does only work if the authentication mode is set to false or if the user is not logged in yet. As soon as the call is made from within a page on which you need to be logged in (forms authentication), it does not work any more. The error message I get then is:
cross domain javascript callback is not supported in authenticated services
It does work again, however, once I logout and do the call from a non-protected page.
My service looks like this
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();
}
}
}
The service call and the callback method 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));
}
}
}
The web.config part which concerns the service:
<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>
I first tried to use the ASP.NET AJAX Proxy to call the service, but this did not work because the call was made to the webserver directly, which is not SSL and the error I got was more or less: 'Page https://gate.company.com/MyPage
tried to load not save content from page http://myLocalWebServer/MyPage
...'. That is why I used the AJAX-call listed above.
function fillDropdwon(dropId){
var service = new MyNameSpace.Service();
service.GetDropDownData(dropId, onDone);
}
I also tried to add the following in the 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>
I checked the headers sent to the server and saw that when I am NOT logged in, the header looks like this:
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
and the response looks like this.
onDone(["result1","result2"]);
When I call the service from within a protected page, I get this:
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**
and the response looks like this.
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);
The main difference is that there is a SessionID and the jsonerror:true for the version "logged in".
It there a way to fix this problem?
Is it not possible to "disable" the authentication for the AJAX request by changing the header before the call or something like that. Or is there any error in my code, web.config?
I appreciate any hint, since I am trying around for a long time.