Reputation: 51
I am getting this error when attempting to consume a wcf service cross-domain:
XMLHttpRequest cannot load https://MyDomain/MyService.svc/GetData. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://CallingDomain' is therefore not allowed access. The response had HTTP status code 500.
I already have set up CORS access in the web.config file like so:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept"/>
</customHeaders>
</httpProtocol>
Here is my full web.config file:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="MyService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</sectionGroup>
</configSections>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<customErrors mode="Off"/>
<compilation targetFramework="4.5" debug="true"/>
<httpRuntime targetFramework="4.5"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
<webServices>
<protocols>
<add name="HttpPost" />
<add name="HttpSoap" />
<add name="HttpGet" />
</protocols>
</webServices>
</system.web>
<!-- Diagnostics Configuration-->
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Error,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type=""/>
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type=""/>
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="E:\MyErrorFile.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp"/>
</sharedListeners>
<trace autoflush="true"/>
</system.diagnostics>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
<add key="MajorVersion" value="1"/>
<add key="MinorVersion" value="1"/>
</appSettings>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add
name="crossOriginResourceSharingBehavior"
type="MyNameSpace.CORSEnablingBehavior, MyNameSpace, Version=1.0.0.0, Culture=neutral" />
</behaviorExtensions>
</extensions>
<services>
<service name="MyNameSpace.MyService" behaviorConfiguration="ServiceBehaviour">
<endpoint address="" binding="webHttpBinding" contract="MyNameSpace.MyService" behaviorConfiguration="web"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
<crossOriginResourceSharingBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint name="" crossDomainScriptAccessEnabled="true" />
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true"/>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS, PUT" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept"/>
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Here is my MyService.svc.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.ServiceModel.Activation;
namespace MyNameSpace
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceContract]
public class MyService
{
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/GetData"
)]
[OperationContract]
public TestData GetData(string value)
{
TestData tsd = TestData.GetTestData(value);
return tsd;
}
}
}
Here is the ajax I am using to consume the service from a different domain:
function CallService() {
var params = new Object();
params.value = "1234";
var url = "https://ServiceURL/MyService.svc/GetData";
$.ajax({
type: "POST",
contentType: "application/json;charset=utf-8",
url: url,
data: JSON.stringify(params),
dataType: "json",
success: function (response) {
var results = response.d;
$.each($(results), function (key, value) {
alert(value.Last_Name + " " + value.First_Name);
});
},
error: function (a, b, c) {
var warnmsg = "Unable to call service: " + a.responseText;
alert(warnmsg);
}
});
}
I have even also tried setting up CORS through a global.asax file like so:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Can anyone clue me in to what I am missing here in order to call this service from a different domain?
Upvotes: 2
Views: 3350
Reputation: 51
We solved this issue by adding an empty method to the MyService.svc.cs file, like so:
[OperationContract]
[WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
void GetOptions() { }
We also added a RequestFormat to the WebInvoke of the GetData POST method like this:
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json
)]
[OperationContract]
public TestData GetData(string value)
{
TestData tsd = TestData.GetTestData(value);
return tsd ;
}
Upvotes: 3