Skip to content

Instantly share code, notes, and snippets.

@mfenniak
Created February 4, 2013 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfenniak/4707000 to your computer and use it in GitHub Desktop.
Save mfenniak/4707000 to your computer and use it in GitHub Desktop.
Snippet to create and read a System.ServiceModel.Channels.Message object representing a WCF operation invocation containing multiple parameters. This is how you would use DataContractSerializer to make an entire operation call, including each individual parameter, rather than just serializing one object at a time.
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Xml;
public static class SoapUtilities
{
class RequestMessageBodyWriter : BodyWriter
{
private MessageBodyDescription bodyDescription;
private object[] parameters;
public RequestMessageBodyWriter(MessageBodyDescription bodyDescription, object[] parameters)
: base(false)
{
this.bodyDescription = bodyDescription;
this.parameters = parameters;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
// Can't Dispose this xmlWriter, 'cause it will close 'writer'.
var xmlWriter = XmlWriter.Create(writer);
xmlWriter.WriteStartElement(bodyDescription.WrapperName, bodyDescription.WrapperNamespace);
foreach (var part in bodyDescription.Parts)
{
var dcs = new DataContractSerializer(part.Type, part.Name, part.Namespace);
dcs.WriteObject(xmlWriter, parameters[part.Index]);
}
xmlWriter.WriteEndElement();
}
}
/// <summary>
/// Creates a SOAP message representing an operation call.
/// </summary>
/// <param name="parameters">An array of objects representing the parameters of the operation.</param>
/// <param name="serviceContractType">The Type object of the service contract definition.</param>
/// <param name="operationContractName">The name of the operation method.</param>
public static string WriteOperationRequest(object[] parameters, Type serviceContractType, string operationContractName)
{
var serviceDescription = ContractDescription.GetContract(serviceContractType);
var operationDescription = serviceDescription.Operations.Single(op => op.Name == operationContractName);
var inputMessage = operationDescription.Messages.Single(msgDescription => msgDescription.Direction == MessageDirection.Input);
var body = inputMessage.Body;
var soapMessage = Message.CreateMessage(
MessageVersion.Soap12,
serviceDescription.Namespace + serviceDescription.Name + "/" + operationDescription.Name,
new RequestMessageBodyWriter(body, parameters)
);
var sb = new StringBuilder();
using (var xmlWriter = XmlWriter.Create(sb))
soapMessage.WriteMessage(xmlWriter);
return sb.ToString();
}
/// <summary>
/// Reads a SOAP message for a specific operation and deserializes the operation parameters. This is the
/// inverse of WriteOperationRequest.
/// </summary>
/// <param name="message">The message content.</param>
/// <param name="serviceContractType">The Type object of the service contract definition.</param>
/// <param name="operationContractName">The name of the operation method.</param>
public static object[] ReadOperationParameters(string message, Type serviceContractType, string operationContractName)
{
var serviceDescription = ContractDescription.GetContract(serviceContractType);
var operationDescription = serviceDescription.Operations.Single(op => op.Name == operationContractName);
var inputMessage = operationDescription.Messages.Single(msgDescription => msgDescription.Direction == MessageDirection.Input);
var bodyDescription = inputMessage.Body;
object[] parameters = new object[inputMessage.Body.Parts.Count];
using (var stringReader = new StringReader(message))
using (var messageReader = XmlReader.Create(stringReader))
{
var soapMessage = System.ServiceModel.Channels.Message.CreateMessage(
messageReader,
1024 * 1024,
System.ServiceModel.Channels.MessageVersion.Soap12
);
var bodyReader = soapMessage.GetReaderAtBodyContents();
bodyReader.ReadStartElement(bodyDescription.WrapperName, bodyDescription.WrapperNamespace);
foreach (var part in bodyDescription.Parts)
{
var dcs = new DataContractSerializer(part.Type, part.Name, part.Namespace);
parameters[part.Index] = dcs.ReadObject(bodyReader);
}
bodyReader.ReadEndElement();
}
return parameters;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment