none
MessageBuffer.CreateMessage does not allways create an exact copy RRS feed

  • Question

  • We have a scenario where we have an IDispatchMessageInspector configured as a WCF service behavior. The purpose of this behavior is to log both incoming and outgoing requests when configured to do so.

    We are seeing some strange behavior when the messageinspector is doing its work and the service page is opened in a browser. The service page normally shows some usage information about the service, and how to use a client.

    http://localhost:50000/<the_wcf_service>.svc

    The page looks different when the outgoing message is processed by the messageinspector: our code:

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var messageBuffer = reply.CreateBufferedCopy(int.MaxValue);
        reply = messageBuffer.CreateMessage();
        var clone = messageBuffer.CreateMessage();
    
        // the rest of the code works with the clone but
        // a return at this spot also causes the issue.
        return;
    }

    When we open the .svc file in the browser, the output seems to have been altered compared to the normal output:

    Output without messageinspector:

    HTTP/1.1 200 OK
    Cache-Control: private
    Content-Type: text/html; charset=UTF-8
    Server: Microsoft-IIS/10.0
    X-AspNet-Version: 4.0.30319
    X-SourceFiles: =?UTF-8?B?RDpcUHJvamVjdHNcTG9rYWFsXFJlY2h0c3ByYWFrLkxvZ2dpbmcuUHJvb2ZPZkNvbmNlcHRcTXZjTW92aWUuU2VydmljZXMuRXh0ZXJuYWxcRXh0ZXJuYWxEYXRhU2VydmljZS5zdmM=?=
    X-Powered-By: ASP.NET
    Date: Wed, 14 Nov 2018 13:05:05 GMT
    Content-Length: 3125
    
    <HTML><HEAD><link rel="alternate" type="text/xml" href="http://localhost:50130/ExternalDataService.svc?disco"/><STYLE type="text/css">#content{ FONT-SIZE: 0.7em; PADDING-BOTTOM: 2em; MARGIN-LEFT: 30px}BODY{MARGIN-TOP: 0px; MARGIN-LEFT: 0px; COLOR: #000000; FONT-FAMILY: Verdana; BACKGROUND-COLOR: white}P{MARGIN-TOP: 0px; MARGIN-BOTTOM: 12px; COLOR: #000000; FONT-FAMILY: Verdana}PRE{BORDER-RIGHT: #f0f0e0 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #f0f0e0 1px solid; MARGIN-TOP: -5px; PADDING-LEFT: 5px; FONT-SIZE: 1.2em; PADDING-BOTTOM: 5px; BORDER-LEFT: #f0f0e0 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #f0f0e0 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e5e5cc}.heading1{MARGIN-TOP: 0px; PADDING-LEFT: 15px; FONT-WEIGHT: normal; FONT-SIZE: 26px; MARGIN-BOTTOM: 0px; PADDING-BOTTOM: 3px; MARGIN-LEFT: -30px; WIDTH: 100%; COLOR: #ffffff; PADDING-TOP: 10px; FONT-FAMILY: Tahoma; BACKGROUND-COLOR: #003366}.intro{MARGIN-LEFT: -15px}</STYLE><TITLE>Service ExternalDataService</TITLE></HEAD><BODY><DIV id="content"><P class="heading1">Service ExternalDataService</P><BR/><P class="intro">U hebt een service gemaakt.<P class='intro'> Om deze service te testen moet u een client maken en daarmee de service aanroepen. U kunt dit vanuit de opdrachtregel doen met het hulpprogramma svcutil.exe. Gebruik hiervoor de syntaxis:</P> <BR/><PRE>svcutil.exe <A HREF="http://localhost:50130/ExternalDataService.svc?wsdl">http://localhost:50130/ExternalDataService.svc?wsdl</A></PRE><P>U kunt de servicebeschrijving ook als één bestand openen:<BR/><PRE><A HREF="http://localhost:50130/ExternalDataService.svc?singleWsdl">http://localhost:50130/ExternalDataService.svc?singleWsdl</A></PRE></P></P><P class="intro"/>Hiermee wordt een configuratiebestand gegenereerd en een codebestand dat de clientklasse bevat. Voeg de twee bestanden toe aan de clienttoepassing en gebruik de gegenereerde clientklasse om de service aan te roepen. Bijvoorbeeld:<BR/><P class='intro'><B>C#</B></P><PRE><font color="blue">class </font><font color="teal">Test
    </font>{
    <font color="blue">    static void </font>Main()
        {
            <font color="teal">ExternalDataServiceClient</font> client = <font color="blue">new </font><font color="teal">ExternalDataServiceClient</font>();
    
    <font color="green">        // Gebruik de variabele 'client' om bewerkingen voor de service aan te roepen.
    
    </font><font color="green">        // Sluit de client altijd af.
    </font>        client.Close();
        }
    }
    </PRE><BR/><P class='intro'><B>Visual Basic</B></P><PRE><font color="blue">Class </font><font color="teal">Test
    </font><font color="blue">    Shared Sub </font>Main()
    <font color="blue">        Dim </font>client As <font color="teal">ExternalDataServiceClient</font> = <font color="blue">New </font><font color="teal">ExternalDataServiceClient</font>()
    <font color="green">        ' Gebruik de variabele 'client' om bewerkingen voor de service aan te roepen.
    
    </font><font color="green">        ' Sluit de client altijd af.
    </font>        client.Close()
    <font color="blue">    End Sub
    </font><font color="blue">End Class</font></PRE></DIV></BODY></HTML>

    Output with the message inspector active:

    HTTP/1.1 200 OK
    Cache-Control: private
    Content-Type: text/html; charset=UTF-8
    Server: Microsoft-IIS/10.0
    X-AspNet-Version: 4.0.30319
    X-SourceFiles: =?UTF-8?B?RDpcUHJvamVjdHNcTG9rYWFsXFJlY2h0c3ByYWFrLkxvZ2dpbmcuUHJvb2ZPZkNvbmNlcHRcTXZjTW92aWUuU2VydmljZXMuRXh0ZXJuYWxcRXh0ZXJuYWxEYXRhU2VydmljZS5zdmM=?=
    X-Powered-By: ASP.NET
    Date: Wed, 14 Nov 2018 13:05:20 GMT
    Content-Length: 3224
    
    <HTML><HEAD><link rel="alternate" type="text/xml" href="http://localhost:50130/ExternalDataService.svc?disco"></link><STYLE type="text/css">#content{ FONT-SIZE: 0.7em; PADDING-BOTTOM: 2em; MARGIN-LEFT: 30px}BODY{MARGIN-TOP: 0px; MARGIN-LEFT: 0px; COLOR: #000000; FONT-FAMILY: Verdana; BACKGROUND-COLOR: white}P{MARGIN-TOP: 0px; MARGIN-BOTTOM: 12px; COLOR: #000000; FONT-FAMILY: Verdana}PRE{BORDER-RIGHT: #f0f0e0 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #f0f0e0 1px solid; MARGIN-TOP: -5px; PADDING-LEFT: 5px; FONT-SIZE: 1.2em; PADDING-BOTTOM: 5px; BORDER-LEFT: #f0f0e0 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: #f0f0e0 1px solid; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e5e5cc}.heading1{MARGIN-TOP: 0px; PADDING-LEFT: 15px; FONT-WEIGHT: normal; FONT-SIZE: 26px; MARGIN-BOTTOM: 0px; PADDING-BOTTOM: 3px; MARGIN-LEFT: -30px; WIDTH: 100%; COLOR: #ffffff; PADDING-TOP: 10px; FONT-FAMILY: Tahoma; BACKGROUND-COLOR: #003366}.intro{MARGIN-LEFT: -15px}</STYLE><TITLE>Service ExternalDataService</TITLE></HEAD><BODY><DIV id="content"><P class="heading1">Service ExternalDataService</P>&lt;BR/&gt;<P class="intro">U hebt een service gemaakt.&lt;P class='intro'&gt; Om deze service te testen moet u een client maken en daarmee de service aanroepen. U kunt dit vanuit de opdrachtregel doen met het hulpprogramma svcutil.exe. Gebruik hiervoor de syntaxis:&lt;/P&gt; &lt;BR/&gt;<PRE>svcutil.exe <A HREF="http://localhost:50130/ExternalDataService.svc?wsdl">http://localhost:50130/ExternalDataService.svc?wsdl</A></PRE><P>U kunt de servicebeschrijving ook als één bestand openen:&lt;BR/&gt;<PRE><A HREF="http://localhost:50130/ExternalDataService.svc?singleWsdl">http://localhost:50130/ExternalDataService.svc?singleWsdl</A></PRE></P></P><P class="intro"></P>Hiermee wordt een configuratiebestand gegenereerd en een codebestand dat de clientklasse bevat. Voeg de twee bestanden toe aan de clienttoepassing en gebruik de gegenereerde clientklasse om de service aan te roepen. Bijvoorbeeld:&lt;BR/&gt;&lt;P class='intro'&gt;&lt;B&gt;C#&lt;/B&gt;&lt;/P&gt;<PRE><font color="blue">class </font><font color="teal">Test
    </font>{
    <font color="blue">    static void </font>Main()
        {
            <font color="teal">ExternalDataServiceClient</font> client = <font color="blue">new </font><font color="teal">ExternalDataServiceClient</font>();
    
    <font color="green">        // Gebruik de variabele 'client' om bewerkingen voor de service aan te roepen.
    
    </font><font color="green">        // Sluit de client altijd af.
    </font>        client.Close();
        }
    }
    </PRE>&lt;BR/&gt;&lt;P class='intro'&gt;&lt;B&gt;Visual Basic&lt;/B&gt;&lt;/P&gt;<PRE><font color="blue">Class </font><font color="teal">Test
    </font><font color="blue">    Shared Sub </font>Main()
    <font color="blue">        Dim </font>client As <font color="teal">ExternalDataServiceClient</font> = <font color="blue">New </font><font color="teal">ExternalDataServiceClient</font>()
    <font color="green">        ' Gebruik de variabele 'client' om bewerkingen voor de service aan te roepen.
    
    </font><font color="green">        ' Sluit de client altijd af.
    </font>        client.Close()
    <font color="blue">    End Sub
    </font><font color="blue">End Class</font></PRE></DIV></BODY></HTML>

    The link just after the HEAD tag now has a separate close tag and the html after the PRE tag is encoded

    I expect both pages to be identical.

    Wednesday, November 14, 2018 2:12 PM

All replies

  • Hi Everttimmer,

    According to your description, I am not clear about your question. Do you mean that we compare the response returned by the server via visiting the metadata Uri?  I recommend you compare the difference by invoke the client method, the page publishing the metadata could not trigger the server-side IDispatchMessageInspector interface.

    Besides, MessageBuffer.CreateMessage will make a copy from the source message and the message state will change to Copied. If we want to send a message which has been copied. We could use the message buffer to create a new message. But you could directly log the message in here, there is no need to use the MessageBuffer to copy.

    https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.messagebuffer?view=netframework-4.7.2

    Wish it is useful to you.

    Best Regards

    Abraham

    Monday, November 19, 2018 8:14 AM
    Moderator
  • Hi Abraham,

    Thanks for reacting.

    The reason I came up with this post is that I was having a problem refreshing service reference information in a client application when I had the service behavior attached. As soon as the behavior was unloaded, the problem was gone.

    After some investigation, I noticed that:

     - The IDispatchMessageInspector DOES get triggered when you browse to the metadata provided by the service ( the page I mentioned ). I could see it was triggered because of the built-in logging from the message logger class (the main purpose of the message inspector)

    AFAIK: if I use the reply in the BeforeSendReply method to log the message, the message is read and therefore will trigger an exception when read again. So, to get around this, I create a messagebuffer from which:

     - I first create a (fresh) new message that I assign to the reply param. this is the message returned to the client.

     - I then create a clone for reading and logging.

        var messageBuffer = reply.CreateBufferedCopy(int.MaxValue);
        reply = messageBuffer.CreateMessage();
        var clone = messageBuffer.CreateMessage();

    This construct should ENSURE that the client is getting an untouched message.

    The reason for this post is that I was experiencing problems using this construct when the request to service was a metadata request instead of a regular service request and I used the approach mentioned in the post to prove that these 2 lines:

        var messageBuffer = reply.CreateBufferedCopy(int.MaxValue);
        reply = messageBuffer.CreateMessage();
    

    does not guarantee that the output is the same, in contrary to what the documentation says!

    Monday, November 19, 2018 10:10 AM
  • Hi Everttimmer,
    According to your description, I could not reproduce your problem, would you mind sharing you project with me?
    1.Minimal. Use as little code as possible that still produces the same problem.
    2.Complete. Provide all parts needed to reproduce your problem.
    3.Verifiable. Test the code you’re about to provide to make sure it reproduces the problem.
    If you provide code people can reproduce the problem so that you could get a much better answer.
    Best Regards
    Abraham
    Thursday, November 22, 2018 9:30 AM
    Moderator
  • Hi Abraham,

    I created a solution with a wcf service. The messageinspector is included in the same project. It produces the same result as discussed before. I removed pretty much all code that isn't relevant
    to the subject.

    Test project available under:

    https://1drv.ms/u/s!At0gAXCs4EcAgZpLDqRHbJMSjxRn3A

    Monday, November 26, 2018 12:53 AM