В моем проекте 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);
}
}