IDispatchMessageInspector: Улучшение функциональности BeforeSendReply - PullRequest
5 голосов
/ 20 января 2011


В моем проекте WCF мне нужно использовать пользовательские заголовки в ответах, поэтому я реализовал IDispatchMessageInspector. Честно говоря, все работает довольно хорошо, но меня беспокоит одна мелочь.
Дело в том, что BeforeSendReply и AfterReceiveRequest срабатывает даже тогда, когда я просто открываю свою страницу .svc как или загружаю службу в тестовый клиент WCF.
Итак, первый вопрос : нормально ли это поведение? Есть ли какие-то способы справиться с этим декларативно (возможно, с трюком web.config)?
В настоящее время я использую следующий код:

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        if (reply.Properties.Any(x => x.Key == "httpResponse"))
            return;

        MessageHeader header = MessageHeader.CreateHeader("Success", "NS", !reply.IsFault);
        reply.Headers.Add(header);          
    }

Так что теперь я обрабатываю все вызовы, которые не являются вызовами службы, используя это:

if (reply.Properties.Any(x => x.Key == "httpResponse"))
    return;

Но я почти уверен, что есть какой-то другой и лучший способ справиться с этой проблемой. Итак, мой главный вопрос : пожалуйста, предложите мне лучший способ справиться с описанной ситуацией.
Заранее спасибо!

ОБНОВЛЕНИЕ 1
Мой раздел system.serviceModel

<system.serviceModel>       
    <services>          
        <service behaviorConfiguration="someBehavior" name="serviceName">
            <endpoint address="" binding="basicHttpBinding" contract="my contract" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        </service>
    </services>     
    <behaviors>
        <serviceBehaviors>              
            <behavior name="someBehavior">
                <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>                  
                <serviceDebug includeExceptionDetailInFaults="false"/>
                <exceptionInspector/>                   
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <extensions>
        <behaviorExtensions>
            <add name="exceptionInspector" type="class which implements BehaviorExtensionElement" />
        </behaviorExtensions>
    </extensions>

</system.serviceModel>

ОБНОВЛЕНИЕ 2 (ПРИНЯТО РЕШЕНИЕ)
Я потратил некоторое время на изучение источника проблемы и, наконец, нашел приемлемое для меня решение.
Итак, что я нашел:
Прежде всего Message - это абстрактный класс. Так что BeforeSendReply каждый раз получает разные типы конкретных сообщений.
Наиболее используемые:
1) System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.MetadataOnHelpPageMessage - означает, что клиент открывает svc как страницу. Результат = хорошо известная страница в формате html с общей информацией о сервисе svc. Для этого типа reply.Version.Envelope есть EnvelopeVersion.None.
2) Получить запрос метаданных. Это немного сложная часть, и это зависит от того, используем мы MEX или нет. Поэтому, если мы используем MEX, тогда запрос выполняется для конечной точки .svc / mex, и его тип сообщения будет System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage с reply.Version.Envelope, равным EnvelopeVersion.Soap12.
В случае, если мы не используем MEX, клиент выполняет несколько запросов на получение данных wsdl. Тип сообщения будет XMLSchemaMessage.
3) Выполнить запрос веб-метода. Это только полезный для меня тип запросов. Это System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage и reply.Version.Envelope равно EnvelopeVersion.Soap11.

Я использую basicHttpBinding, поэтому версия SOAP - 1.1. Итак, мой окончательный код должен просто проверить, что ответ имеет конверт SOAP и проверить его версию. В случае, если конверт существует и имеет версию 1.1, мы можем быть уверены, что у нас есть вызов веб-метода и может быть добавлен специальный заголовок:

        public void BeforeSendReply(ref Message reply, object correlationState)
    {   
        if(reply.Version.Envelope == EnvelopeVersion.Soap11)
        {               
            MessageHeader header = MessageHeader.CreateHeader("Success", "NS", !reply.IsFault);
            reply.Headers.Add(header);          
        }
    }

1 Ответ

2 голосов
/ 20 января 2011

Кажется, я помню, что IDispatchMessageInspector будет работать для всех сообщений, включая HTTP-запросы к метаданным (WSDL), представленные в одной конечной точке.Вы не упоминаете, как регистрируете своего инспектора, так что это также может быть связано.

Помимо проверки, пытались ли вы проверить, что содержится в сообщении?Например, сообщение, содержащее служебную HTML-страницу, вероятно, будет иметь MessageVersion == MessageVersion.None.Аналогично, действие, связанное с сообщением, также может быть полезным.

...