简体   繁体   中英

WCF CORS is set but still getting No 'Access-Control-Allow-Origin' header is present

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?

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 ;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM