AfterReceiveReply Problem (MessageInspector)
-
Wednesday, February 23, 2011 12:33 PM
Hi,
I am using the message inspector and it works. My message(request) is correct. In Fiddler I get the correct answer. But in my code where I should get the response back I get nothing. When I modify the 'AfterReceiveReply' and try to get the body of the message I get the correct response. But it is not forwarded to my request function as the response. If I try to add a Value out of the reply into a Property it does not work. The value of my property is changing to nothing as soon I step out of the Sub AfterReceiveReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object)
Public Sub AfterReceiveReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply '/// Antwort auslesen Token in String lesen Dim memStream1 As New MemoryStream() Dim quotas1 As New XmlDictionaryReaderQuotas() Dim xdr1 As XmlDictionaryReader = XmlDictionaryReader.CreateBinaryReader(memStream1, quotas1) xdr1 = reply.GetReaderAtBodyContents() Dim XMLDoc As New XmlDocument XMLDoc.Load(xdr1) Dim BarmProp As New Common.Class1 For Each node As XmlElement In XMLDoc.ChildNodes BarmProp.BiproToken = node.InnerText NextLothar
All Replies
-
Wednesday, February 23, 2011 5:24 PM
Instances of the Message class are "read-once" objects - once you consume it, you cannot use it again. Once you consume (in your example, calling GetReaderAtBodyContents), you'll need to recreate the message so that it can be passed to the caller. The code below shows how the message can be recreated, and modified after the fact.
Public Class Post_3396ffba_4e33_40f2_b8e6_9fcb7f0b3a88 <ServiceContract()> Public Interface ITest <OperationContract()> Function Add(ByVal x As Integer, ByVal y As Integer) As Integer End Interface Public Class Service Implements ITest Public Function Add(ByVal x As Integer, ByVal y As Integer) As Integer Implements ITest.Add Return x + y End Function End Class Public Class MyInspector Implements IEndpointBehavior Implements IClientMessageInspector Public Sub AddBindingParameters(ByVal endpoint As ServiceEndpoint, ByVal bindingParameters As BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters End Sub Public Sub ApplyClientBehavior(ByVal endpoint As ServiceEndpoint, ByVal clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior clientRuntime.MessageInspectors.Add(Me) End Sub Public Sub ApplyDispatchBehavior(ByVal endpoint As ServiceEndpoint, ByVal endpointDispatcher As EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior End Sub Public Sub Validate(ByVal endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate End Sub Public Sub AfterReceiveReply(ByRef reply As Message, ByVal correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply Dim xdr As XmlDictionaryReader = reply.GetReaderAtBodyContents() ' reply has been read; need to re-create it later Dim XMLDoc As XmlDocument = New XmlDocument() XMLDoc.Load(xdr) 'Recreating the reply Dim memStream As New MemoryStream Dim writer As XmlDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memStream) XMLDoc.WriteTo(writer) writer.Flush() memStream.Position = 0 Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max) Dim newReply As Message = Message.CreateMessage(reply.Version, Nothing, reader) newReply.Headers.CopyHeadersFrom(reply) newReply.Properties.CopyProperties(reply.Properties) 'Now adding a new property into the "reply" newReply.Properties.Add(name:="MyNewProperty", [property]:="Value for my property") reply = newReply End Sub Public Function BeforeSendRequest(ByRef request As Message, ByVal channel As IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest Return Nothing End Function End Class Public Shared Sub Test() Dim baseAddress As String = "http://" + Environment.MachineName+":8000/Service" Dim host As New ServiceHost(GetType(Service), New Uri(baseAddress)) host.AddServiceEndpoint(GetType(ITest), New BasicHttpBinding(), "") Dim smb As ServiceMetadataBehavior = New ServiceMetadataBehavior smb.HttpGetEnabled = True host.Description.Behaviors.Add(smb) host.Open() Dim factory = New ChannelFactory(Of ITest)(New BasicHttpBinding(), New EndpointAddress(baseAddress)) factory.Endpoint.Behaviors.Add(New MyInspector()) Dim proxy = factory.CreateChannel() Using New OperationContextScope(CType(proxy, IContextChannel)) Console.WriteLine(proxy.Add(1234, 5434)) Console.WriteLine("All response properties:") For Each prop In OperationContext.Current.IncomingMessageProperties Console.WriteLine("{0}: {1}", prop.Key, prop.Value) Next End Using Console.WriteLine("Press ENTER to close") Console.ReadLine() End Sub End Class
-
Wednesday, February 23, 2011 8:57 PM
Hi Carlos,
thanks for the answer, but I don't need to modfy the reply, I just want tu use the reply. There is a Token inside of the reply body and I need this Token,
I can see it when I use the : reply.GetReaderAtBodyContents() but how can I put this into an external property and read it later???
If I use :
Dim BarmProp As New Common.Class1
For Each node As XmlElement In XMLDoc.ChildNodes
BarmProp.BiproToken = node.InnerText
Nextand map the token inside a new property inside of class1 property BarmProb.BiproToken it is nothing when I tried to use it.
You are saying that if I don't consume the message class it will go to the caller but that is not true.
If I leave Sub AfterReceiveReply empty(no line of code) I don't get the response back to my Function, where I could read it normaly.
I am confused, I have a response but I can't us it.
Lothar
-
Wednesday, February 23, 2011 10:54 PM
The variable BarmProp which you declare in the function is local to the function AfterReceiveReply, so when the function returns, its value is discarded. If you want to save something inside that function to use later, you need to store it in a variable / property / field declared outside the scope of the function. In the (modified) example below, I added a field to the class, and saved the value for the nodes in that field. After the call is returned, the caller can then access that value.
And I don't understand when you say that 'if I leave Sub AfterReceiveReply empty i don't get the response back'; in the example below, if AfterReceiveReply is completely commented out, you'll still have the result of the function (the line where the caller prints proxy.Add(...)).
Public Class Post_3396ffba_4e33_40f2_b8e6_9fcb7f0b3a88 Private Shared allNodes As List(Of String) = New List(Of String) <ServiceContract()> Public Interface ITest <OperationContract()> Function Add(ByVal x As Integer, ByVal y As Integer) As Integer End Interface Public Class Service Implements ITest Public Function Add(ByVal x As Integer, ByVal y As Integer) As Integer Implements ITest.Add Return x + y End Function End Class Public Class MyInspector Implements IEndpointBehavior Implements IClientMessageInspector Public Sub AddBindingParameters(ByVal endpoint As ServiceEndpoint, ByVal bindingParameters As BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters End Sub Public Sub ApplyClientBehavior(ByVal endpoint As ServiceEndpoint, ByVal clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior clientRuntime.MessageInspectors.Add(Me) End Sub Public Sub ApplyDispatchBehavior(ByVal endpoint As ServiceEndpoint, ByVal endpointDispatcher As EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior End Sub Public Sub Validate(ByVal endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate End Sub Public Sub AfterReceiveReply(ByRef reply As Message, ByVal correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply Dim xdr As XmlDictionaryReader = reply.GetReaderAtBodyContents() ' reply has been read; need to re-create it later Dim XMLDoc As XmlDocument = New XmlDocument() XMLDoc.Load(xdr) 'Saving the information in a "global" variable For Each node As XmlElement In XMLDoc.ChildNodes allNodes.Add(node.InnerText) Next 'Recreating the reply Dim memStream As New MemoryStream Dim writer As XmlDictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memStream) XMLDoc.WriteTo(writer) writer.Flush() memStream.Position = 0 Dim reader As XmlDictionaryReader = XmlDictionaryReader.CreateBinaryReader(memStream, XmlDictionaryReaderQuotas.Max) Dim newReply As Message = Message.CreateMessage(reply.Version, Nothing, reader) newReply.Headers.CopyHeadersFrom(reply) newReply.Properties.CopyProperties(reply.Properties) 'Now adding a new property into the "reply" newReply.Properties.Add(name:="MyNewProperty", [property]:="Value for my property") reply = newReply End Sub Public Function BeforeSendRequest(ByRef request As Message, ByVal channel As IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest Return Nothing End Function End Class Public Shared Sub Test() Dim baseAddress As String = "http://" + Environment.MachineName+":8000/Service" Dim host As New ServiceHost(GetType(Service), New Uri(baseAddress)) host.AddServiceEndpoint(GetType(ITest), New BasicHttpBinding(), "") Dim smb As ServiceMetadataBehavior = New ServiceMetadataBehavior smb.HttpGetEnabled = True host.Description.Behaviors.Add(smb) host.Open() Dim factory = New ChannelFactory(Of ITest)(New BasicHttpBinding(), New EndpointAddress(baseAddress)) factory.Endpoint.Behaviors.Add(New MyInspector()) Dim proxy = factory.CreateChannel() Using New OperationContextScope(CType(proxy, IContextChannel)) Console.WriteLine(proxy.Add(1234, 5434)) Console.WriteLine("All response properties:") For Each prop In OperationContext.Current.IncomingMessageProperties Console.WriteLine("{0}: {1}", prop.Key, prop.Value) Next End Using Console.WriteLine("All nodes read in AfterReceiveReply:") For Each node In allNodes Console.WriteLine(" " + node) Next Console.WriteLine("Press ENTER to close") Console.ReadLine() End Sub End Class
- Marked As Answer by LOMECO Friday, February 25, 2011 7:29 AM
-
Friday, February 25, 2011 7:29 AM
Tanks Carlos,
that works perfect many thanks!!!!
Lothar

