Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IDispatchMessageInspector: Improving BeforeSendReply functionality


In my WCF project I need to use custom headers in responses so I implemented IDispatchMessageInspector. Honestly all works pretty fine, but I'm disturbing about one little thing.
The thing is that both BeforeSendReply and AfterReceiveRequest fires even when I just open my .svc as page, or load service into WCF Test Client.
So, the first question: Is that behavior normal? Are there some ways to handle that declaratively (maybe some web.config trick)?
Currently I use next code:

    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);          
    }

So now I handle all calls which aren't service calls by using that:

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

But I'm pretty sure there some other and better way to handle that problem. So my main question: please suggest me a better way to handle described situation.
Thanks in advance!

UPDATE 1
My system.serviceModel section

<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>

UPDATE 2 (ACCEPTED SOLUTION)
I spent some time investigation source of problem and finally I've found acceptable for me solution.
So what have I found:
First of all Message is a abstract class. So BeforeSendReply each time receive defferent types of concrete messages.
Most used are:
1) System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.MetadataOnHelpPageMessage - means that client opens svc as page. Result = well known html formatted page with common information about svc service. For this type reply.Version.Envelope is EnvelopeVersion.None.
2) Get metadata request. This is slightly tricky part and it depends if we use MEX or not. So if we use MEX then request performs to .svc/mex endpoint and its Message type will be System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage with reply.Version.Envelope equal to EnvelopeVersion.Soap12.
In case if we don't use MEX then client performs few requests for obtaining wsdl data. Message type will be XMLSchemaMessage.
3) Execute web method request. This only useful for me type of requests. It is System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage and has reply.Version.Envelope equal to EnvelopeVersion.Soap11.

I'm using basicHttpBinding so SOAP version is 1.1. So my final code should just check is reply has SOAP envelope and check version of it. In case if envelope exists and has version 1.1 then we may be pretty sure that we have web method call and custom header might be added:

        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);          
        }
    }
like image 377
Igor V Savchenko Avatar asked Nov 05 '22 04:11

Igor V Savchenko


1 Answers

I seem to remember that an IDispatchMessageInspector will run for all messages, including HTTP requests to metadata (WSDL), exposed at the same endpoint. You don't mention how you're registering your inspector, so that might also be related.

Besides checking that, have you tried checking out what the message contains? For example, a message containing the service HTML page would likely have MessageVersion == MessageVersion.None. Likewise, the action associated with the message might also be useful.

like image 191
tomasr Avatar answered Nov 15 '22 13:11

tomasr