允许浏览器从 Windows service-hosted WCF 服务请求 JSONP

Allow browser to request JSONP from Windows service-hosted WCF service

我正在尝试安装一个托管的 windows service-hosted WCF 服务,它可以为我的网页提供一些关于安装它的机器的信息。我的想法是我页面的所有访问者都将安装此服务,并且该页面可以使用 javascript 调用本地主机服务以获取其后的数据。

我们的一位开发人员通过为服务启用 CORS 将其组合在一起 CarlosFigueira's example here。它在除 Edge 之外的所有浏览器中都运行良好,它会给出错误 SCRIPT7002: XMLHttpRequest: Network Error 0x2efd。我想不出任何原因,也找不到任何相关信息,所以我想也许我应该尝试 jsonp 方法。

我认为 jsonp 应该绕过 same-origin 政策,但我只能让它与上面的 CORS-enabled WCF 服务一起工作**还在原地。一旦我删除它并只使用常规 ServiceHost,我就开始收到 400 - 错误的请求响应。

** "work" 我的意思是浏览器成功发出请求并收到响应。但是,响应是普通的 json,而不是 jsonp。我读到 WCF 4.5 应该自动识别 "callback" 参数并将 json 包装在 "P" 中,但这似乎并没有发生。我认为这是一个不相关的次要问题。

但主要问题是,我认为 jsonp 应该是一种发出 cross-domain 请求的方式,所以为什么我必须启用所有 CORS header 东西我的 WCF 服务使其工作?

Windows 服务启动:

CorsEnabledServiceHostFactory serviceHostFactory = new CorsEnabledServiceHostFactory();
serviceHost = serviceHostFactory.GetServiceHost(typeof(LPA.MachineDataService), baseAddresses);  //Works

//LPA.MachineDataService singleton = new LPA.MachineDataService();
//serviceHost = new System.ServiceModel.ServiceHost(singleton, baseAddresses);  //Doesn't work

serviceHost.Open();

服务合同:

[ServiceContract]
public interface IMachineDataService
{
    [WebGet(UriTemplate = "GetValues", ResponseFormat=WebMessageFormat.Json)]
    LPA.MachineData GetValues();
}

服务实施:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MachineDataService : IMachineDataService
{
    public LPA.MachineData GetValues()
    {
        LPA.MachineData result = null;

        try
        {
            WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.CacheControl] = "no-cache";

            result = PcValues.GetValues();
        }
        catch (Exception ex)
        {
        }

        return result;
    }
}

来自 windows 服务 app.config:

<system.serviceModel>
<behaviors>
  <serviceBehaviors>
    <behavior name="">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<standardEndpoints>
  <webScriptEndpoint>
    <standardEndpoint crossDomainScriptAccessEnabled="true" name=""></standardEndpoint>
  </webScriptEndpoint>
  <webHttpEndpoint>
    <standardEndpoint crossDomainScriptAccessEnabled="true" name=""></standardEndpoint>
  </webHttpEndpoint>
</standardEndpoints>

</system.serviceModel>

jQuery 调用:

var valuesAddress = "http://localhost:56731/ValuesService/GetValues";

$.ajax({
    type: "GET",
    url: valuesAddress,
    dataType: "jsonp",
    success: function (result) {
        $("[data-authinfo]").val(result);
    },
    error: function (xhr, status, code) {

    }
});

我从头开始了一个自托管虚拟服务,并将问题缩小到我的配置。它需要使用 webHttpBinding 才能作为 REST 服务运行,我想,如果没有明确指定,它会使用 basicHttpBinding。我删除了标准端点并自己将端点配置为:

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webHttpBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <webHttpBinding>
      <binding name="webHttpBinding" crossDomainScriptAccessEnabled="true" />
    </webHttpBinding>
  </bindings>
  <services>
    <service name="LessonPlansAuthentication.MachineDataService">
      <endpoint address="" binding="webHttpBinding"
                bindingConfiguration="webHttpBinding"
                behaviorConfiguration="webHttpBehavior"
                contract="LessonPlansAuthentication.IMachineDataService"/>
    </service>
  </services>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>

如果我在进行此更改之前尝试在浏览器中访问 URL,它只会显示空白页面。之后,它实际上 returns JSON 数据和 jQuery 可以成功地对 URL.[=14= 进行 JSONP AJAX 调用]

我仍然不清楚使用 webHttp 绑定和端点以及 crossDomainScriptAccessEnabled=true 实际发生了什么变化以允许调用。响应的内容类型可能?如有任何意见,我们将不胜感激。

现在我只需要验证它在所有浏览器中都能正常工作。如果有人知道为什么 Edge 不支持启用 CORS 的服务,请发表评论。