Reputation: 5352
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
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