不允许使用自托管WCF REST服务JSON POST方法

本文关键字:服务 REST JSON POST 方法 WCF 不允许 | 更新日期: 2023-09-27 18:09:51

到目前为止,我已经在互联网上看到了数千个这样的"WCF"问题,但我开始认为这是不可能的。请告诉我,我错了。

背景:我正在使用一个自托管的WCF服务(因此Global.asax.cs在这里没有帮助)。端点也是通过编程方式定义的。合同是用WebInvoke(Method="POST")装饰的,我正在对服务进行JQuery调用。

preflight最初使用OPTIONS方法工作,但POST方法失败,使用405 method Not Allowed。GET函数也可以很好地工作。

我已经在网上搜索和实验了大约一个月了,它就是不会改变。这个服务已经可以很好地响应另一个通过TCP调用它的客户端…请找个天才帮帮我。由于

PS:我认为真正奇怪的是POST响应,是允许:选项…那肯定不应该在那里吧?

歌珥

    public class CORSEnablingBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        var requiredHeaders = new Dictionary<string, string>();
        requiredHeaders.Add("Access-Control-Allow-Origin", "*");
        requiredHeaders.Add("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS");
        requiredHeaders.Add("Access-Control-Allow-Headers", "Origin, Cache-Control, Connection, Pragma, Content-Length, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, User-Agent");
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CORSHeaderInjectingMessageInspector(requiredHeaders));
    }

app.config

  <system.serviceModel>
<behaviors>
  <endpointBehaviors>
    <behavior name="SOAPDemoEndpointBehavior">
    </behavior>
    <behavior>
      <webHttp/>
      <crossOriginResourceSharingBehavior/>
    </behavior>
  </endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<extensions>
  <behaviorExtensions>
    <add name="crossOriginResourceSharingBehavior" type="Application.Host.CORSEnablingBehavior, Application.Host, Version=1.0.0.0, Culture=neutral"/>
  </behaviorExtensions>
</extensions>
<bindings>
  <basicHttpBinding>
    <binding name="OrdersMappingSoap"/>
  </basicHttpBinding>
  <!--2015-08-26-->
  <webHttpBinding>
    <binding name="webHttpBindingWithJson"
          crossDomainScriptAccessEnabled="true" />
  </webHttpBinding>

界面

[OperationContract(Name = "Relational")] 
[FaultContract(typeof(ValidationFault))]
[WebInvoke(Method = "POST", UriTemplate = "GetCustomerRelational", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]
CustomerFullModel GetCustomerRelational(int clientHandle, object customerID, bool loadRelationalData);
JQuery

jQuery.ajax({
  crossDomain: true,
  type: "POST",
  contentType: "application/json",
  url: "http://localhost:8086/CustomerService/rest/GetCustomerRelational/",
  data: JSON.stringify({
    "clientHandle": 1824,
    "customerID": "ABB029",
    "loadRelationalData": true
  }),
  dataType: "json",
  success: function(result) {
    console.log("Success...");
    document.getElementById("lblResponse").innerHTML = "Success: " + JSON.stringify(result.NormalResult);
  },
  error: function(x, s, t) {
    console.log("Error...");
    document.getElementById("lblResponse").innerHTML = x.responseText;
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<

起飞前的请求/strong>

OPTIONS http://localhost:8086/CustomerService/rest/GetCustomerRelational/ HTTP/1.1
Host: localhost:8086
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://stacksnippets.net/js
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

<

起飞前的反应/strong>

HTTP/1.1 200 OK
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, Cache-Control, Connection, Pragma, Content-Length, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, User-Agent
Date: Wed, 26 Aug 2015 13:13:59 GMT

POST请求

POST http://localhost:8086/CustomerService/rest/GetCustomerRelational/ HTTP/1.1
Host: localhost:8086
Connection: keep-alive
Content-Length: 69
Accept: application/json, text/javascript, */*; q=0.01
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36
Content-Type: application/json
Referer: http://stacksnippets.net/js
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
{"clientHandle":1824,"customerID":"ABB029","loadRelationalData":true}

<

后反应/strong>

HTTP/1.1 405 Method Not Allowed
Allow: OPTIONS
Content-Length: 1565
Content-Type: text/html; charset=UTF-8
Server: Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, Cache-Control, Connection, Pragma, Content-Length, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, User-Agent
Date: Wed, 26 Aug 2015 13:14:02 GMT
<p>Method not allowed.</p>

不允许使用自托管WCF REST服务JSON POST方法

我明白了。

这个WCF和其他人的主要区别在于,我的WCF是自托管的,而其他的WCF都托管在IIS上(大部分)。

感谢这篇文章ASP。NET兼容模式下,答案在于拦截飞行前请求。IIS托管的WCF要求在全局中进行拦截。文件格式如下:

protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            //These headers are handling the "pre-flight" OPTIONS call sent by the browser
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE,OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            HttpContext.Current.Response.End();
        }
    }

然而,这在自托管WCF中是不可能的。但是,我们仍然可以使用ASP。. NET功能,使用app.config

中的这一行
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

然后最后在服务类中使用它:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class TestService : ValidationModel, ITestService
{

我意识到仅仅把它设置为"允许"是没有用的,它必须是"要求"。

最后,为了启动预飞行,需要在接口和服务中包含以下代码:

[OperationContract]
    [FaultContract(typeof(ValidationFault))]
    [WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
    void GetOptions();
public void GetOptions()
    {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
    }

现在,具有复杂参数的POST方法将通过飞行前测试,并执行带有响应的方法。

如果您在自托管服务中处理这种情况,下面的过程对我来说是有效的:

  1. 在你的界面中添加OPTIONS方法(浏览器在调用POST方法之前,调用OPTIONS来验证CORS)

    [OperationContract][WebInvoke(Method = "OPTIONS", UriTemplate = "*")]

    空白GetOptions ();
  2. 在ServiceBehavior类中实现

    public void GetOptions()
    {           
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");    
    WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
    

    }

  3. 类可能必须有这个属性:

    [AspNetCompatibilityRequirements(requirementmode = aspnetcompatibilityrequirementmode . allowed)]