4,103 questions
I've figured out the solution:
[AttributeUsage(AttributeTargets.Method)]
internal class EnvelopeFormatMessageAttribute : Attribute, IOperationBehavior
{
internal class SoapEnvelopeMessageFormatter : IDispatchMessageFormatter
{
private readonly IDispatchMessageFormatter formatter;
public SoapEnvelopeMessageFormatter(IDispatchMessageFormatter formatter)
{
this.formatter = formatter;
}
public void DeserializeRequest(Message message, object[] parameters) =>
this.formatter.DeserializeRequest(message, parameters);
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
Message message = this.formatter.SerializeReply(messageVersion, parameters, result);
return new SoapEnvelopeMessage(message);
}
}
internal class SoapEnvelopeMessage : Message
{
private readonly Message message;
public SoapEnvelopeMessage(Message message)
{
this.message = message;
}
public override MessageHeaders Headers => this.message.Headers;
public override MessageProperties Properties => this.message.Properties;
public override MessageVersion Version => this.message.Version;
protected override void OnWriteStartBody(XmlDictionaryWriter writer) =>
writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); // Request response
protected override void OnWriteBodyContents(XmlDictionaryWriter writer) =>
this.message.WriteBodyContents(writer);
protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
{
writer.WriteStartDocument(); // <?xml version="1.0" encoding="utf-8"?>
writer.WriteStartElement("soap", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
}
}
const string serializerBehaviorType = "datacontractserializeroperationbehavior";
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
IOperationBehavior serializerBehavior = operationDescription.OperationBehaviors.FirstOrDefault(ob =>
serializerBehaviorType.Equals(ob.GetType().Name, StringComparison.InvariantCultureIgnoreCase));
if (dispatchOperation.Formatter == null)
{
serializerBehavior.ApplyDispatchBehavior(operationDescription, dispatchOperation);
}
dispatchOperation.Formatter = new SoapEnvelopeMessageFormatter(dispatchOperation.Formatter);
}
And then I can use it on any operation I want to be re-formatted.