[英]Self Hosted WCF REST service JSON POST Method Not Allowed
到目前为止,我已经在 inte.net 上看到了数千个这样的“WCF”问题,但我开始认为这是不可能的。 请有人告诉我我错了...
背景:我正在使用自托管 WCF 服务(因此 Global.asax.cs 在这里无济于事)。 端点也是以编程方式定义的。 合同用 WebInvoke(Method="POST") 修饰,我正在调用该服务的 JQuery。
预检最初适用于 OPTIONS 方法,但 POST 方法失败并显示 405 Method Not Allowed。 GET 函数也能完美运行。
我已经搜索了 inte.net 并进行了大约一个月的试验,但它就是不动。 该服务已经对另一个通过 TCP 调用它的客户做出了很好的响应......请一些天才帮助我。 谢谢
PS:我认为 POST 响应真的很奇怪,是 Allow: OPTIONS ......当然不应该在那里?
CORS
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));
}
应用配置
<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>
预检请求
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
飞行前响应
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}
POST 响应
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与其他所有WCF之间的主要区别在于,我的数据库是自托管的,而其他所有文件则托管在IIS上(大多数情况下)。
感谢本文的ASP.NET兼容模式 ,答案就在于拦截预检请求。 IIS托管的WCF要求在global.asax文件中进行拦截,如下所示:
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中是不可能的。 但是,我们仍然可以使用app.config中的这一行使用ASP.NET功能
<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方法将通过预检测试并通过响应执行该方法。
如果您在自托管服务中处理这种情况,则以下过程对我有用:
将 OPTIONS 方法添加到您的界面中(浏览器在调用您的 POST 方法之前调用 OPTIONS 来验证 CORS)
[OperationContract] [WebInvoke(Method = "OPTIONS", UriTemplate = "*")] void GetOptions();
在您的 ServiceBehavior 中实施 class
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;
}
class 可能必须具有此属性:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.