BizTalk - Why won't a message be manipulated in pipeline?

Asked By Ronny Drechsler on 05-Dec-13 04:56 AM
Hi

I have a custom pipeline project which removes/replaces special charaters in a message.
I have deployed it and I am able to debug the C# code and can see that the special characters will be removed/replaced.

But in the outgoing message after it has processed by trhe pipeline I can still see the special characters within.

public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage msg) {
 
  if (msg.BodyPart != null) {
 
    IBaseMessagePart pBody = msg.BodyPart;
    Stream sOriginalStream = pBody.GetOriginalDataStream();
 
    if (sOriginalStream != null) {
 
      MemoryStream memStream = new MemoryStream();
      string returnString = String.Empty;
 
      try {
 
        StreamReader sReader = new StreamReader(sOriginalStream);
        StringBuilder sBuilder = null;
        byte[] byteArray = new byte[sOriginalStream.Length];
        while (sReader.Peek() != -1) {
 
          sBuilder = new StringBuilder(sReader.ReadLine());
          returnString = ReplaceOrRemoveSpecialCharacters(sBuilder.ToString());
          byteArray = System.Text.Encoding.ASCII.GetBytes(returnString);
          memStream.Write(byteArray, 0, byteArray.Length);
 
        }
        pBody.Data = memStream;
        memStream.Position = 0;
        msg.BodyPart.Data = pBody.Data;
        msg.BodyPart.Data.Position = 0;
        pContext.ResourceTracker.AddResource(memStream);
 
      } catch (Exception ex) {
 
        EventLog.WriteEntry("Application", "CL.SendPipelines.TradesphereHandleSpecialCharacters :: " + ex.Message);
 
      } finally {
 
        /*
        sBuilder = null;
        sReader.Close();
        sReader.Dispose();
        memStream.Close();
        memStream.Dispose();
        */
 
      }
 
    }
 
  }
 
  return msg;
 
}
 
Any idea whats going wrong here?
Robbe Morris replied to Ronny Drechsler on 05-Dec-13 09:54 AM
Hmm, you didn't post the code to ReplaceOrRemoveSpecialCharacters.  Have you "confirmed" that it actually does remove the special characters?  If know you "think" it should but have you "confirmed" it with some test data that has the special characters.

Also, why are you creating a StringBuilder here?

builder = new StringBuilder(sReader.ReadLine());
returnString = ReplaceOrRemoveSpecialCharacters(sBuilder.ToString());

Why wouldn't you just use this:

returnString = ReplaceOrRemoveSpecialCharacters(sReader.ReadLine());
Ronny Drechsler replied to Robbe Morris on 05-Dec-13 09:59 AM
Hi Robbie. Here the code: I have placed the same issue to MSDN and got an hint and therefore the answer. Hope that helps you. Bye the way The replacement was fine as the returnString didn't contain special characters also in my project where I got the error. So I didn't post that easy search and replace stuff. But anyway. Here the solution:

namespace BTS.ClassLibrary.SendPipelines {
 
  [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
  [ComponentCategory(CategoryTypes.CATID_Any)]
 
  [System.Runtime.InteropServices.Guid("DB8303F8-918E-4BBF-9048-E09589778D1A")]
 
  public class TradesphereHandleSpecialCharacters : IBaseComponent, IComponentUI, IComponent {
 
    public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage msg) {
 
      if (msg.BodyPart != null) {
 
        Stream st = msg.BodyPart.GetOriginalDataStream();
        StreamReader reader = new StreamReader(st);
        MemoryStream m = new MemoryStream();
        StreamWriter writer = new StreamWriter(m);
 
        //if (sOriginalStream != null) {
 
          try {
             
             
            string body = reader.ReadToEnd();
            //body = body.Replace(_FindString, _ReplaceWith);
            body = ReplaceOrRemoveSpecialCharacters(body);
 
            writer.AutoFlush = true;
            writer.Write(body);
            m.Position = 0;
            msg.BodyPart.Data = m;
 
            reader.Close();
            return msg;
           
          } catch (Exception ex) {
 
            EventLog.WriteEntry("Application", "BTS.SendPipelines.TradesphereHandleSpecialCharacters :: " + ex.Message);
 
          } // END try {
 
        // } // END if (sOriginalStream != null) {
 
      } // END public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage msg) {
 
      return msg;
 
    } // END public class TradesphereHandleSpecialCharacters : IBaseComponent, IComponentUI {
 
    public IntPtr Icon {
 
      get {
        return new System.IntPtr();
      }
 
    } // END public IntPtr Icon {
 
    public IEnumerator Validate(object projectSystem) {
 
      return null;
 
    } // END public IEnumerator Validate(object projectSystem) {
 
    public string Description {
 
      get {
        return "Replaces or removes special characters";
      }
 
    } // END public string Description {
 
    public string Name {
 
      get {
        return "BTS.SendPipelines.TradesphereHandleSpecialCharacters";
      }
 
    } // END public string Name {
 
    public string Version {
 
      get {
        return "1.0.0.0";
      }
 
    } // END public string Version {
 
    private static string ReplaceOrRemoveSpecialCharacters(string _input) {
 
 
      string output = String.Empty;
      string pattern = @"[äüößÄÜÖØøÆæÀÁÂÃÄÅàáâãäåÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖòóôõöÝýÿÙÚÛÜùúûüÇðÞþÐ|]";
      Regex regex = new Regex(pattern);
 
      MatchEvaluator myEvaluator = new MatchEvaluator(ReplaceMethod);
 
      output = regex.Replace(_input, myEvaluator);
      string output2 = output.Replace("\r\n","").Trim();
 
      return output2;
 
    } // END private string ReplaceOrRemoveSpecialCharacters(string _input){
 
    public static string ReplaceMethod(Match m) {
 
      switch (m.Value) {
        case "ß":
          return "ss";
        case "ä":
          return "ae";
        case "ö":
          return "oe";
        case "ü":
          return "ue";
        case "Ä":
          return "Ae";
        case "Ö":
          return "Oe";
        case "Ü":
          return "Ue";
        case "Ø":
          return "O";
        case "ø":
          return "O";
        case "Æ":
          return "A";
        case "æ":
          return "a";
        case "À":
          return "A";
        case "Á":
          return "A";
        case "Â":
          return "A";
        case "Ã":
          return "A";
        case "Å":
          return "A";
        case "à":
          return "a";
        case "á":
          return "a";
        case "â":
          return "a";
        case "ã":
          return "a";
        case "å":
          return "a";
        case "È":
          return "E";
        case "É":
          return "E";
        case "Ê":
          return "E";
        case "Ë":
          return "E";
        case "è":
          return "e";
        case "é":
          return "e";
        case "ê":
          return "e";
        case "ë":
          return "e";
        case "Ì":
          return "I";
        case "Í":
          return "I";
        case "Î":
          return "I";
        case "Ï":
          return "I";
        case "ì":
          return "i";
        case "í":
          return "i";
        case "î":
          return "i";
        case "ï":
          return "i";
        case "Ò":
          return "O";
        case "Ó":
          return "O";
        case "Ô":
          return "O";
        case "Õ":
          return "O";
        case "ò":
          return "o";
        case "ó":
          return "o";
        case "ô":
          return "o";
        case "õ":
          return "o";
        case "Ý":
          return "Y";
        case "ý":
          return "y";
        case "ÿ":
          return "y";
        case "Ù":
          return "U";
        case "Ú":
          return "U";
        case "Û":
          return "U";
        case "ù":
          return "u";
        case "ú":
          return "u";
        case "û":
          return "u";
        case "Ç":
          return "C";
        case "ð":
          return "o";
        case "Þ":
          return "T";
        case "þ":
          return "T";
        case "Ð":
          return "D";
        case "|":
          return "";
        default:
          return m.Value;
 
      } // END switch (m.Value) {
 
    } // END public string replaceMethod(Match m) {
 
  } // END class TradesphereHandleSpecialCharacters {
 
} // END namespace BTS.ClassLibrary.SendPipelines {
 
Robbe Morris replied to Ronny Drechsler on 05-Dec-13 10:10 AM
" MSDN and got an hint and therefore the answer"

I see where you've used AutoFlush and close the stream.  That said, there are a couple of different stream related classes that implement IDisposable but you don't wrap your code in a using to close the stream or clear its resources or call .Dispose().  This can lead to memory leaks in your app.

using(MemoryStream stream = new MemoryStream(blah blah blah))
{

}

This will automatically call .Dispose() on the stream (or any other class that implements IDisposable) whether there is an error or not.  The compiler turns this code block into try/catch/finally at runtime/msil time.
Ronny Drechsler replied to Robbe Morris on 05-Dec-13 10:15 AM
Thanks for that hint too.

I will change it as you are absolutely right.

BR