EagleMl Web Service - Custom Classes and Overrides
This section describes some additional actions you should fulfill to make your work more effective.
Create a CustomTextMessageBindingElement class.
internal class CustomTextMessageBindingElement : MessageEncodingBindingElement, IWsdlExportExtension
  {
    #region Fields
    private MessageVersion _msgVersion;
    private string _mediaType;
    private string _encoding;
    private readonly XmlDictionaryReaderQuotas _readerQuotas;
    #endregion
    #region Properties
    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; }
    }
    #endregion
    #region Constructors
    private 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.Soap11WSAddressing10)
    {
          }
    public CustomTextMessageBindingElement(string encoding)
      : this(encoding, "text/xml")
    {
          }
    public CustomTextMessageBindingElement()
      : this("UTF-8")
    {
    }
    #endregion
    #region Overrides
    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;
      return base.GetProperty<T>(context);
    }
    #endregion
    #region IMessageEncodingBindingElement Members
    public override MessageEncoderFactory CreateMessageEncoderFactory()
    {
      return new CustomTextMessageEncoderFactory(MediaType, Encoding, MessageVersion);
    }
    #endregion
    #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.
      var mebe = new TextMessageEncodingBindingElement { MessageVersion = _msgVersion };
      ((IWsdlExportExtension)mebe).ExportEndpoint(exporter, context);
    }
    #endregion
  }
The most important methods are:
public CustomTextMessageBindingElement(string encoding)
and
public CustomTextMessageBindingElement()
In these methods, set the default contentType and encoding (text/xml and UTF-8).
Create CustomTextMessageEncoderFactory and CustomTextMessageEncoder classes.
public class CustomTextMessageEncoderFactory : MessageEncoderFactory
  {
    private MessageEncoder encoder;
    private MessageVersion version;
    private string mediaType;
    private string charSet;
    internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
      MessageVersion version)
    {
      this.version = version;
      this.mediaType = mediaType;
      this.charSet = charSet;
      this.encoder = new CustomTextMessageEncoder(this);
    }
    public override MessageEncoder Encoder
    {
      get
      {
        return this.encoder;
      }
    }
    public override MessageVersion MessageVersion
    {
      get
      {
        return this.version;
      }
    }
    internal string MediaType
    {
      get
      {
        return this.mediaType;
      }
    }
    internal string CharSet
    {
      get
      {
        return this.charSet;
      }
    }
  }
CustomTextMessageEncoderFactory is a support class. The CustomTextMessageEncoder class is as follows:
public class CustomTextMessageEncoder : MessageEncoder
  {   Â
    private CustomTextMessageEncoderFactory factory;
    private XmlWriterSettings writerSettings;
    private string contentType;
    public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
    {
      this.factory = factory;
      this.writerSettings = new XmlWriterSettings();
      this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
      this.contentType = string.Format("{0}; charset={1}",
        this.factory.MediaType, this.writerSettings.Encoding.HeaderName);
    }
    public override string ContentType
    {
      get
      {
        return this.contentType;
      }
    }
    public override string MediaType
    {
      get
      {
        return factory.MediaType;
      }
    }
    public override MessageVersion MessageVersion
    {
      get
      {
        return this.factory.MessageVersion;
      }
    }
    public override System.ServiceModel.Channels.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);
      return ReadMessage(stream, int.MaxValue);
    }
        public override System.ServiceModel.Channels.Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
       {
           try
           {
               XmlReader reader = XmlReader.Create(stream);
               return System.ServiceModel.Channels.Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
           }
           catch (Exception e)
           {
               stream.Position = 0;
               string value="";
               using (var strreader = new StreamReader(stream, Encoding.UTF8))
               {
                   value = strreader.ReadToEnd();
               }
               if (value.Contains("<ERROR>"))
               {
                   int k = value.IndexOf("<ERROR>");
                   value=value.Substring(k + 7);
                   k = value.LastIndexOf("</ERROR>");
                   if (k > 0)
                   {
                       value = value.Substring(0,k);
                   }
               }
              Â
               System.ServiceModel.FaultCode fc = new System.ServiceModel.FaultCode("Receiver");
               System.ServiceModel.Channels.Message m = Message.CreateMessage(this.MessageVersion, fc, value, "fault");
               return m;
           }
       }
    public override ArraySegment<byte> WriteMessage(System.ServiceModel.Channels.Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
    {
      MemoryStream stream = new MemoryStream();
     Â
      XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
      message.WriteMessage(writer);
      writer.Close();
      byte[] messageBytes = stream.GetBuffer();
      int messageLength = (int)stream.Position;
      stream.Close();
      int totalLength = messageLength + messageOffset;
      byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
      Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
      ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
      return byteArray;
    }
   Â
   Â
    public override void WriteMessage(System.ServiceModel.Channels.Message message, Stream stream)
    {
      XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
      message.WriteMessage(writer);
      writer.Close();
    }
    public override bool IsContentTypeSupported(string contentType)
    {
      if (contentType == "text/plain" || contentType== "text/xml")
        return true;
      return base.IsContentTypeSupported(contentType);
    }    Â
  }
The CustomTextMessageEncoder class requires the following fixes:
The content type fix should be made in the IsContentTypeSupported(string contentType) method. Fix possible incorrect contentTypes from EagleMlWebService.
Non-soap messages processing fix. The fix should be made in the ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) method.
Add the GenerateUID() method which generates a unique correlationID.
// unique id generation
    private static string GenerateUID()
    {
      long i = 1;
      foreach (byte b in Guid.NewGuid().ToByteArray())
      {
        i *= ((int)b + 1);
      }
      return string.Format("{0:x}", i - DateTime.Now.Ticks).ToUpper();
    }
Â