繁体   English   中英

将WCF CORS宁静服务从.Net 4.5转换为3.5会导致预检请求中断

[英]Converting WCF CORS restful service from .Net 4.5 to 3.5 causes preflight request to break

我有一个使用CORS的WCF服务,该服务托管在.Net 4.5中运行正常的控制台应用程序上。 现在需要该应用程序在.Net 3.5中工作,并且对于任何POST请求,预检OPTIONS请求现在都失败

这是服务的接口:

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    BiometricCaptureResponse Start(BiometricCaptureRequest biometricRequest);

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

实际服务:

    public BiometricCaptureResponse Start(BiometricCaptureRequest biometricRequest)
    {
        //Stuff and things
    }

    public void Options()
    {
        return;
    }

应用于请求和响应的CORS行为

    public string clientOrigin;       

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        HttpRequestMessageProperty requestProperty = request.Properties[HttpRequestMessageProperty.Name]
                      as HttpRequestMessageProperty;

        if (requestProperty != null && requestProperty.Headers.AllKeys.Contains("Origin") && !string.IsNullOrEmpty(requestProperty.Headers["Origin"]))
        {
            clientOrigin = requestProperty.Headers["Origin"];
        }

        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        HttpResponseMessageProperty httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;

        if (httpHeader != null)
        {
            httpHeader.ApplyCrossOriginSupport(clientOrigin); 
        }
    }

    public static void ApplyCrossOriginSupport(this HttpResponseMessageProperty message, string origin)
    {
        message.Headers.Add("Access-Control-Allow-Origin", origin);
        message.Headers.Add("Access-Control-Allow-Method", ConfigurationManager.AppSettings["Access-Control-Allow-Method"]);
        message.Headers.Add("Access-Control-Allow-Headers", ConfigurationManager.AppSettings["Access-Control-Allow-Headers"]);
    }

这一切都在4.5中起作用了,这是将要发生的过程:

  1. AfterReceiveRequest()
  2. Options()服务命中
  3. BeforeSendReply()
  4. AfterReceiveRequest()
  5. 开始()
  6. BeforeSendReply()

现在在3.5中,Ooptions服务将不会被命中,这将导致整个请求失败。为使它在3.5下工作,我还缺少什么吗?

我从Chrome控制台收到的错误是:

OPTIONS http://localhost:8502/testservice.svc/rest/Start net::ERR_CONNECTION_RESET 

这可能与WebInvoke属性有关吗? 它在MSDN页面上将其描述为4.5 / 3.5客户端技术,而我仅使用.Net 3.5。

更新:更改以下选项服务的属性以使用所有方法

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

如果允许选项请求进入服务,则应用程序可以像这样正常工作,但这仍然不是最佳解决方案,因为它不是特定于OPTIONS请求的原因,这背后的原因是什么?

恐怕WebHttpDispatchOperationSelector的.Net 3.5版本中存在一个小错误。

选择器无法识别与* UriTemplate结合使用的方法选项。

解决方法是将默认的WebHttpBehavior替换为自定义版本。

public class CorsWebHttpDispatchOperationSelector : WebHttpDispatchOperationSelector
{

    private WebHttpDispatchOperationSelector target;
    private ServiceEndpoint endpoint;

    OperationDescription optionOperation;

    public CorsWebHttpDispatchOperationSelector(ServiceEndpoint endpoint, WebHttpDispatchOperationSelector target)
    {
        this.target = target;
        this.endpoint = endpoint;

        foreach (var item in this.endpoint.Contract.Operations) {
            var webInvoke = item.Behaviors.OfType<WebInvokeAttribute>().FirstOrDefault();
            if (webInvoke != null && webInvoke.Method.Equals("options",StringComparison.OrdinalIgnoreCase) && webInvoke.UriTemplate == "*") {
                optionOperation = item;
                break;
            }
        }
    }
    #region IDispatchOperationSelector Members

    protected override string SelectOperation(ref Message message, out bool uriMatched)
    {
        var result = target.SelectOperation(ref message);

        var matched = message.Properties["UriMatched"] as bool?;
        message.Properties.Remove("UriMatched");
        message.Properties.Remove("HttpOperationName");
        uriMatched = matched.HasValue && matched.Value;

        var httpRequest = message.Properties["httpRequest"] as HttpRequestMessageProperty;

        var cond = string.IsNullOrEmpty(result) && 
                        httpRequest != null && 
                        httpRequest.Method.Equals("options",StringComparison.OrdinalIgnoreCase);

        if (cond && optionOperation != null) {
            result = optionOperation.Name;
            uriMatched = true;
        }

        return result;
    }
    #endregion
}

public class CorsWebHttpBehavior : WebHttpBehavior {
    protected override WebHttpDispatchOperationSelector GetOperationSelector(ServiceEndpoint endpoint)
    {
        return new CorsWebHttpDispatchOperationSelector(endpoint, base.GetOperationSelector(endpoint));
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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