using System.Collections.Generic;
using System.Xml.Serialization;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel ;
[ServiceContract, XmlSerializerFormat]
public interface ISampleService
[OperationContract, XmlSerializerFormat]
public void SampleMethod(SampleRequestWrapper wrapper);
public static class Namespaces
public const string SoapNamespace = "http://www.w3.org/2003/05/soap-envelope";
public const string ServiceNamespace = "http://example.com/namespace/";
[MessageContract(IsWrapped = false, WrapperNamespace = Namespaces.SoapNamespace)]
public class SampleRequestWrapper
[MessageBodyMember(Namespace = Namespaces.ServiceNamespace)]
public SampleRequest SampleRequest { get; set; }
[XmlType(Namespace = Namespaces.ServiceNamespace)]
[XmlRoot("SampleRequest", Namespace = Namespaces.ServiceNamespace)]
public class SampleRequest
public string Track { get; set; } = string.Empty;
[XmlElement("requestTimestamp", IsNullable = false)]
public string RequestTimestamp { get; set; } = string.Empty;
[XmlElement("subjectInfo", IsNullable = false)]
public SubjectInfo SubjectInfo { get; set; } = new();
[XmlElement("uniqueId", IsNullable = false)]
public string UniqueId { get; set; } = string.Empty;
public static void Test()
var body = new SampleRequest
RequestTimestamp = "20210305113442",
Console.WriteLine(new SampleRequestWrapper { SampleRequest = body } .ToMessageXml(null, new XmlSerializerFormatAttribute()));
var requestXml = GetRequestXml();
var requestMessage = MessageContractSerializerHelper.CreateMessageFromXml(requestXml, MessageVersion.Soap12WSAddressing10);
var requestBody = requestMessage.FromMessage<SampleRequestWrapper>(null, new XmlSerializerFormatAttribute());
static string GetRequestXml() =>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:add="http://www.w3.org/2005/08/addressing">
<SampleRequest xmlns="http://example.com/namespace/" track="V">
<requestTimestamp>20210305113442</requestTimestamp>
<uniqueId>ABCDE1234</uniqueId>
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
public static class MessageContractSerializerHelper
public static string ToMessageString(this Message message) =>
message.CreateBufferedCopy(int.MaxValue).CreateMessage().ToString();
public static Message CreateMessageFromXml(string xml, MessageVersion ver)
using var textReader = new StringReader(xml);
using var xmlReader = XmlReader.Create(textReader);
xmlReader.MoveToContent();
xmlReader.ReadToFollowing("Body", "http://www.w3.org/2003/05/soap-envelope");
xmlReader.MoveToContent();
using var subReader = xmlReader.ReadSubtree();
var streamingMessage = Message.CreateMessage(ver, null, subReader);
MessageBuffer messageBuffer = streamingMessage.CreateBufferedCopy(int.MaxValue);
Message bufferedMessage = messageBuffer.CreateMessage();
public static T FromMessage<T>(this Message message, string action, XmlSerializerFormatAttribute attr)
var converter = TypedMessageConverter.Create(typeof(T), action, attr);
return (T)converter.FromMessage(message);
public static Message ToMessage<T>(this T typedMessage, string action, XmlSerializerFormatAttribute attr)
var converter = TypedMessageConverter.Create(typedMessage.GetType(), action, attr);
return converter.ToMessage(typedMessage);
public static string ToMessageXml<T>(this T typedMessage, string action, XmlSerializerFormatAttribute attr)
return typedMessage.ToMessage(action, attr).ToString();
public static Message ToMessage<T>(this T typedMessage, string action)
var converter = TypedMessageConverter.Create(typedMessage.GetType(), action);
return converter.ToMessage(typedMessage);
public static string ToMessageXml<T>(this T typedMessage, string action)
return typedMessage.ToMessage(action).ToString();
public static Message ToMessage<T>(this T typedMessage, string action, string defaultNamespace)
var converter = TypedMessageConverter.Create(typedMessage.GetType(), action, defaultNamespace);
return converter.ToMessage(typedMessage);
public static string ToMessageXml<T>(this T typedMessage, string action, string defaultNamespace)
return typedMessage.ToMessage(action, defaultNamespace).ToString();
public static class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
using (var reader = new StringReader(xmlString))
return (T)(serial ?? new XmlSerializer(typeof(T))).Deserialize(reader);
public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
ns = new XmlSerializerNamespaces();
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings() { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
public static string GetOuterXml(this XmlNode node, bool indent = true)
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings
OmitXmlDeclaration = true,
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
return textWriter.ToString();
public static class XmlAssert
public static void AreEqual(
Assert.IsTrue(XNode.DeepEquals(Normalize(expected), Normalize(actual)));
private static XElement Normalize(XElement element)
.OrderBy(a => a.Name.ToString()),
.OrderBy(a => a.Name.ToString())
.Select(e => Normalize(e)));
.OrderBy(a => a.Name.ToString()));
return new XElement(element.Name, element.Attributes()
.OrderBy(a => a.Name.ToString()), element.Value);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}, {2}, NewLine: {3}).",
System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion,
System.Text.Json.JsonSerializer.Serialize(Environment.NewLine));
Console.WriteLine("{0} version: {1}", typeof(SoapCore.CustomMessage).Namespace, typeof(SoapCore.CustomMessage).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static class SoapCoreExtensions
public static Message CreateResponseMessage(
OperationDescription operation,
Dictionary<string, object> resultOutDictionary,
XmlNamespaceManager xmlNamespaceManager,
MessageVersion messageVersion,
SoapMessageEncoder soapMessageEncoder) where T_MESSAGE : CustomMessage, new()
T_MESSAGE responseMessage;
BodyWriter bodyWriter = new ServiceBodyWriter(_options.SoapSerializer, operation, responseObject, resultOutDictionary);
if (soapMessageEncoder.MessageVersion.Addressing == AddressingVersion.WSAddressing10)
var underlyingMessage = Message.CreateMessage(soapMessageEncoder.MessageVersion,
soapMessageEncoder.MessageVersion.Addressing == AddressingVersion.WSAddressing10 ? soapAction : null,
if (soapMessageEncoder.MessageVersion.Addressing == AddressingVersion.WSAddressing10)
responseMessage = new CustomMessage(underlyingMessage)
StandAloneAttribute = _options.StandAloneAttribute,
Message = Message.CreateMessage(soapMessageEncoder.MessageVersion, soapAction, bodyWriter),
AdditionalEnvelopeXmlnsAttributes = _options.AdditionalEnvelopeXmlnsAttributes,
NamespaceManager = xmlNamespaceManager
responseMessage.Headers.Action = operation.ReplyAction;
responseMessage.Headers.RelatesTo = requestMessage.Headers.MessageId;
responseMessage.Headers.To = requestMessage.Headers.ReplyTo?.Uri;
responseMessage = new CustomMessage(underlyingMessage)
StandAloneAttribute = _options.StandAloneAttribute,
Message = Message.CreateMessage(soapMessageEncoder.MessageVersion, null, bodyWriter),
AdditionalEnvelopeXmlnsAttributes = _options.AdditionalEnvelopeXmlnsAttributes,
NamespaceManager = xmlNamespaceManager
if (responseObject != null)
var messageHeaderMembers = responseObject.GetType().GetMembersWithAttribute<MessageHeaderAttribute>();
foreach (var messageHeaderMember in messageHeaderMembers)
var messageHeaderAttribute = messageHeaderMember.Attribute;
responseMessage.Headers.Add(MessageHeader.CreateHeader(messageHeaderAttribute.Name ?? messageHeaderMember.Member.Name, messageHeaderAttribute.Namespace ?? operation.Contract.Namespace, messageHeaderMember.Member.GetPropertyOrFieldValue(responseObject), messageHeaderAttribute.MustUnderstand));