Преобразование службы покоя WCF CORS из .Net 4.5 в 3.5 приводит к прерыванию предварительного запроса

У меня была служба WCF с использованием CORS, размещенная в консольном приложении, которое отлично работало в .Net 4.5. теперь приложение должно работать в .Net 3.5, а предварительный запрос OPTIONS теперь не выполняется для любого POST-запроса.

Вот интерфейс для сервисов:

    [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. ПослеПолученияЗапроса()
  2. Обращение к сервису Options()
  3. ПередОтправитьОтвет()
  4. ПослеПолученияЗапроса()
  5. Начинать()
  6. ПередОтправитьОтвет()

Теперь в 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, по какой причине?


person RichardMc    schedule 14.08.2014    source источник
comment
Какую ошибку вы получаете в 3.5?   -  person Peter    schedule 18.08.2014
comment
@peer Добавил ошибку в конец вопроса.   -  person RichardMc    schedule 18.08.2014


Ответы (1)


Боюсь, в версии WebHttpDispatchOperationSelector для .Net 3.5 есть небольшая ошибка.

Метод OPTIONS в сочетании с * 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));
    }
}
person codeworx    schedule 19.08.2014
comment
Спасибо, это намного приятнее, чем использовать *, чтобы поймать все, как вы узнаете, что это ошибка в .Net 3.5? - person RichardMc; 20.08.2014
comment
@RichardMc, это может быть ошибка или просто не поддерживается. Код WebHttpDispatchOperationSelector немного отличается от .net 3.5 до .net 4.0. Когда вы поставите точку останова на мое переопределение метода SelectOperation, вы увидите, что target.SelectOperation(ref message) дает вам действительный результат при построении против 4.5 end пуст при построении против 3.5 - person codeworx; 20.08.2014