Skip to content

Instantly share code, notes, and snippets.

@Misiu
Created March 24, 2017 13:37
Show Gist options
  • Save Misiu/e84a6adfd2891265f7ecb88bc6201130 to your computer and use it in GitHub Desktop.
Save Misiu/e84a6adfd2891265f7ecb88bc6201130 to your computer and use it in GitHub Desktop.
CustomTextMessageEncoder V4
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Xml;
namespace DokZastrzezoneV4
{
public class CustomTextMessageBindingElement : MessageEncodingBindingElement, IWsdlExportExtension
{
private MessageVersion _msgVersion;
private string _mediaType;
private string _encoding;
private readonly XmlDictionaryReaderQuotas _readerQuotas;
CustomTextMessageBindingElement(CustomTextMessageBindingElement binding)
: this(binding.Encoding, binding.MediaType, binding.MessageVersion)
{
_readerQuotas = new XmlDictionaryReaderQuotas();
binding.ReaderQuotas.CopyTo(_readerQuotas);
}
public CustomTextMessageBindingElement(string encoding, string mediaType,
MessageVersion msgVersion)
{
if (encoding == null)
throw new ArgumentNullException("encoding");
if (mediaType == null)
throw new ArgumentNullException("mediaType");
if (msgVersion == null)
throw new ArgumentNullException("msgVersion");
_msgVersion = msgVersion;
_mediaType = mediaType;
_encoding = encoding;
_readerQuotas = new XmlDictionaryReaderQuotas();
}
public CustomTextMessageBindingElement(string encoding, string mediaType)
: this(encoding, mediaType, MessageVersion.Soap12WSAddressing10)
{
}
public CustomTextMessageBindingElement(string encoding)
: this(encoding, "text/xml")
{
}
public CustomTextMessageBindingElement()
: this("UTF-8")
{
}
public override MessageVersion MessageVersion
{
get
{
return _msgVersion;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
_msgVersion = value;
}
}
public string MediaType
{
get
{
return _mediaType;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
_mediaType = value;
}
}
public string Encoding
{
get
{
return _encoding;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
_encoding = value;
}
}
// This encoder does not enforces any quotas for the unsecure messages. The
// quotas are enforced for the secure portions of messages when this encoder
// is used in a binding that is configured with security.
public XmlDictionaryReaderQuotas ReaderQuotas
{
get
{
return _readerQuotas;
}
}
#region IMessageEncodingBindingElement Members
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new CustomTextMessageEncoderFactory(MediaType, Encoding, MessageVersion);
}
#endregion
public override BindingElement Clone()
{
return new CustomTextMessageBindingElement(this);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.BuildInnerChannelFactory<TChannel>();
}
public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
return context.CanBuildInnerChannelFactory<TChannel>();
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.BuildInnerChannelListener<TChannel>();
}
public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
if (context == null)
throw new ArgumentNullException("context");
context.BindingParameters.Add(this);
return context.CanBuildInnerChannelListener<TChannel>();
}
public override T GetProperty<T>(BindingContext context)
{
if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
{
return (T)(object)_readerQuotas;
}
else
{
return base.GetProperty<T>(context);
}
}
#region IWsdlExportExtension Members
void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
}
void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
// The MessageEncodingBindingElement is responsible for ensuring that the WSDL has the correct
// SOAP version. We can delegate to the WCF implementation of TextMessageEncodingBindingElement for this.
TextMessageEncodingBindingElement mebe = new TextMessageEncodingBindingElement
{
MessageVersion = _msgVersion
};
((IWsdlExportExtension)mebe).ExportEndpoint(exporter, context);
}
#endregion
}
}
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceModel.Channels;
using System.Text;
using System.Xml;
namespace DokZastrzezoneV4
{
public class CustomTextMessageEncoder : MessageEncoder
{
private CustomTextMessageEncoderFactory factory;
private XmlWriterSettings writerSettings;
private string contentType;
public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
{
this.factory = factory;
writerSettings = new XmlWriterSettings();
writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
//writerSettings.ConformanceLevel = ConformanceLevel.Fragment;
//writerSettings.OmitXmlDeclaration = false;
contentType = string.Format("{0}; charset={1}", this.factory.MediaType, writerSettings.Encoding.HeaderName);
}
public override string ContentType
{
get
{
return contentType;
}
}
public override string MediaType
{
get
{
return factory.MediaType;
}
}
public override MessageVersion MessageVersion
{
get
{
return factory.MessageVersion;
}
}
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
byte[] msgContents = new byte[buffer.Count];
Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
bufferManager.ReturnBuffer(buffer.Array);
MemoryStream stream = new MemoryStream(msgContents);
string incoming = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
Console.WriteLine("Incoming message:");
Console.WriteLine(incoming);
Console.WriteLine();
return ReadMessage(stream, int.MaxValue);
}
public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
{
XmlReader reader = XmlReader.Create(stream);
var message = Message.CreateMessage(reader, maxSizeOfHeaders, MessageVersion);
return message;
}
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
Debug.WriteLine("MESSAGE:");
Debug.WriteLine(message.ToString());
MemoryStream ms = new MemoryStream();
XmlDictionaryWriter w = XmlDictionaryWriter.CreateBinaryWriter(ms);
message.WriteMessage(w);
w.Flush();
ms.Position = 0;
XmlDictionaryReader r = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(r);
XmlNode binarySecurityToken = doc.GetElementsByTagName("o:BinarySecurityToken")[0];
if (binarySecurityToken != null)
{
XmlAttribute attr = doc.CreateAttribute("EncodingType");
attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
if (binarySecurityToken.Attributes != null) binarySecurityToken.Attributes.Append(attr);
}
XmlNode SecurityTokenReference = doc.GetElementsByTagName("o:SecurityTokenReference")[0];
if (SecurityTokenReference != null)
{
XmlAttribute attr = doc.CreateAttribute("wsse11", "TokenType", "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd");
attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
if (SecurityTokenReference.Attributes != null) SecurityTokenReference.Attributes.Append(attr);
}
XmlNode wsseReference = doc.GetElementsByTagName("o:Reference")[0];
if (wsseReference != null)
{
XmlAttribute attr = doc.CreateAttribute("ValueType");
attr.Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
if (wsseReference.Attributes != null) wsseReference.Attributes.Append(attr);
}
ms = new MemoryStream();
w = XmlDictionaryWriter.CreateBinaryWriter(ms);
doc.WriteTo(w);
w.Flush();
ms.Position = 0;
r = XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max);
Message newMessage = Message.CreateMessage(r, maxMessageSize, message.Version);
newMessage.Properties.CopyProperties(message.Properties);
Debug.WriteLine("NEW MESSAGE:");
Debug.WriteLine(newMessage.ToString());
ArraySegment<byte> messageBuffer;
int messageLength;
using (MemoryStream stream = new MemoryStream())
{
using (XmlWriter writer = XmlWriter.Create(stream, writerSettings))
{
newMessage.WriteMessage(writer);
}
var writeBuffer = stream.ToArray();
messageBuffer = new ArraySegment<byte>(writeBuffer);
messageLength = (int)stream.Position;
}
int totalLength = messageLength + messageOffset;
byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(messageBuffer.Array, 0, totalBytes, messageOffset, messageLength);
ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
return byteArray;
}
public override void WriteMessage(Message message, Stream stream)
{
XmlWriter writer = XmlWriter.Create(stream, writerSettings);
message.WriteMessage(writer);
writer.Close();
}
public override bool IsContentTypeSupported(string contentType)
{
if (base.IsContentTypeSupported(contentType))
{
return true;
}
if (contentType.Length == MediaType.Length)
{
return contentType.Equals(MediaType, StringComparison.OrdinalIgnoreCase);
}
else
{
if (contentType.StartsWith(MediaType, StringComparison.OrdinalIgnoreCase)
&& (contentType[MediaType.Length] == ';'))
{
return true;
}
}
return false;
}
}
}
using System.ServiceModel.Channels;
namespace DokZastrzezoneV4
{
public class CustomTextMessageEncoderFactory : MessageEncoderFactory
{
private readonly MessageEncoder _encoder;
private readonly MessageVersion _version;
private readonly string _mediaType;
private readonly string _charSet;
internal CustomTextMessageEncoderFactory(string mediaType, string charSet, MessageVersion version)
{
_version = version;
_mediaType = mediaType;
_charSet = charSet;
_encoder = new CustomTextMessageEncoder(this);
}
public override MessageEncoder Encoder
{
get { return _encoder; }
}
public override MessageVersion MessageVersion
{
get { return _version; }
}
internal string MediaType
{
get { return _mediaType; }
}
internal string CharSet
{
get { return _charSet; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment