neildt
neildt

Reputation: 5352

How to modify WCF Soap Message Body Response

I have the following WCF service which accepts and SOAP Message and I'm wanting it to return a SOAP Message response.

    [ServiceContract]
    public interface IMyService
    {          
       [OperationContract(Action = "HotelAvailRQ", ReplyAction = "HotelAvailRQResponse")]
       [WebInvoke(Method = "POST",
       BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml)]
       Message HotelAvailRQ(Message message);       
    }

    public class MyService : IMyService
    {
       public Message HotelAvailRQ(Message message)
       {
           return ProcessMessage<OTA_HotelAvailRQ>(message);
       }

       public Message ProcessMessage<T>(Message message)
       {
           MessageBuffer buffer = message.CreateBufferedCopy(8192);

           // Get a copy of the original message. This will be used to read and extract the body.
           Message msgCopy = buffer.CreateMessage();

           // Take another copy of the same message. This will be used to return to the service. Returning an identical message forms part of the acknowledgement in this case.
           Message returnMsg = buffer.CreateMessage();

           XElement body = XElement.Parse(msgCopy.GetReaderAtBodyContents().ReadOuterXml());
           var instance = Deserialize<T>(body, "http://www.opentravel.org/OTA/2003/05");

           MethodInfo methodInfo = typeof(T).GetMethod("Process");
           object document = methodInfo.Invoke(instance, null);

           return returnMsg;

       }

       private static T Deserialize<T>(XElement xElement, string nameSpace)
       {
           using (MemoryStream memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(xElement.ToString())))
           {
               XmlSerializer xmlSerializer = new XmlSerializer(typeof(T), nameSpace);
               return (T)xmlSerializer.Deserialize(memoryStream);
           }
       }

       private static string Serialize(object obj)
       {
           using (MemoryStream memoryStream = new MemoryStream())
           {
               XmlSerializer xs = new XmlSerializer(obj.GetType());
               xs.Serialize(memoryStream, obj);
               return ASCIIEncoding.ASCII.GetString(memoryStream.ToArray());
           }
       }
   }  

   public partial class OTA_HotelAvailRQ
   {
       public static object Process()
       {
           try
           {
               OTA_HotelAvailRQ hotelAvailRQ = new OTA_HotelAvailRQ();
               //Do some stuff and return back new object
               return hotelAvailRQ ;
           }
           catch(Exception ex)
           {            
               return new OTA_HotelAvailRS(); //TODO Should be fault exception...
           }
       }
   }

Do I need to modify the incoming SOAP message, with my Body response ? If so, how do I modify the response, or create a new SOAP message response ?

UPDATE:

I tried what @popo suggested, which was

   var respObj = new object(); //resposneObjBody
   var settings = new XmlReaderSettings
   {
       IgnoreWhitespace = true
   };

   using (MemoryStream ms = new MemoryStream())
   {
       XmlSerializer xs = new XmlSerializer(respObj.GetType());
       xs.Serialize(ms, respObj);
       ms.Position = 0; '<< Added
       var reader = XmlReader.Create(ms, settings);
       var newMessage = Message.CreateMessage(reader, int.MaxValue, msgCopy.Version);
       newMessage.Headers.Clear();
       newMessage.Headers.CopyHeadersFrom(msgCopy.Headers);
   }

But had to add ms.Position = 0; because I was getting the exception Root element is missing

However, the problem I have now is Fault exception Unrecognized message version. Where am I going wrong ?

Upvotes: 1

Views: 2448

Answers (1)

Popo
Popo

Reputation: 2460

Not sure if this will be helpful or not, but if not I will delete the answer, maybe someone else will have something more enlightening. This is modified version of some code I use in a message inspector to manipulate a message and pass it on to the operation. (below is not tested):

    var respObj = new object(); //resposneObjBody you have to define this object type added just for filler
    var settings = new XmlReaderSettings
    {
        IgnoreWhitespace = true
    };

    using (MemoryStream ms = new MemoryStream())
    {
            XmlSerializer xs = new XmlSerializer(respObj.GetType());
            xs.Serialize(ms, respObj);
            ms.Position = 0; 
            var reader = XmlReader.Create(ms, settings);
            var newMessage = Message.CreateMessage(msgCopy.Version, null, reader); // action is null, but you may want to put your reply action here
            newMessage.Headers.Clear(); //you may not need this either
            newMessage.Headers.CopyHeadersFrom(msgCopy.Headers); //you may not need this either
            newMessage.Properties.CopyProperties(msgCopy.Properties); //optional??
    }

Upvotes: 1

Related Questions