Juanjo's Blog

Dot Net Development | Technology | Xbox freak :-)

  Home :: Contact :: Syndication  :: Login
  11 Posts :: 0 Stories :: 4 Comments :: 0 Trackbacks

Archives

Post Categories

My Blog Read List

My links

Saturday, May 28, 2005 #

In the project currently I am working, I am migrating a legacy BizTalk 2002 application to BizTalk 2004. As you probably already know, the migration path between the two products is far from easy... So I am rewriting all from scratch so I can take all advantadges that .Net provides, and avoiding the legacy limitations from COM world...

In the current post, I will talk about Custom Pipeline Components. If you know already BTS 2002, the Pipeline Components in BTS 2004 are similar from the Application Integration Components (AIC) from BTS 2000 / 2002. And I am working in a Custom Pipeline Component for transforming an XML with a propietary (and very huge) XSL to convert this XML to a MIME document. Also, this Pipeline Component is reading the MIME response from the remote service and extracting the embedded XML document.

The Custom Pipeline inherits from some interfaces, and one of this, IComponent, exposes a public method named Execute. This method is executed every time the Custom Pipeline Component is called from a Pipeline.

And in this step was where my troubles arised... I had this code, in the Execute method, that was transforming the MIME into an XML string:



  public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
  {
   IBaseMessagePart bodyPart = inmsg.BodyPart;
   Stream originalStrm = null;
   MemoryStream strm = new MemoryStream();

   try
   {   
    if (bodyPart!=null)
    {
     // Get a *copy* of the original input stream
     originalStrm = bodyPart.Data;
     if (originalStrm != null)
     {
      //Read Incoming data
      string data = "";

      StreamReader sreader = new StreamReader(originalStrm, System.Text.Encoding.UTF8);

      //Receive pipeline, parse MIME document and extract XML
      data = this.fromMIME( sreader.ReadToEnd() );     

      //Send the data back to the Message
      StreamWriter swriter = new StreamWriter(strm, System.Text.Encoding.UTF8);
      swriter.Write(data);
      swriter.Flush();
      strm.Seek(0, System.IO.SeekOrigin.Begin);

     }
    }
   }
   catch (Exception ex)
   {
    System.Diagnostics.EventLog.WriteEntry(ex.Source, ex.Message + "\n" + ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
    strm = (MemoryStream) originalStrm;
   }
   finally
   {
    bodyPart.Data = strm;
    pc.ResourceTracker.AddResource( strm );
   }
            
   return inmsg;
  }

This code was working perfect for me... Until I connect it to my Receive Pipeline and to my Orchestration. When unit testing the orchestration, all messages were suspended, with an exception saying that the message, with an empty namespace, was not corresponding with the expected one, "www.clearscreen.com#Response". It was very disssapointing, because the XML was in a proper format and with it expected namespace in place, the root tag was "Response" and its namespace was "www.clearscreen.com" :

But this was not enough for BizTalk to route the message. I discovered that we need to promote a property of the message in the Custom Pipeline:



  public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
  {
   IBaseMessagePart bodyPart = inmsg.BodyPart;
   Stream originalStrm = null;
   MemoryStream strm = new MemoryStream();

   try
   {   
    if (bodyPart!=null)
    {
     // Get a *copy* of the original input stream
     originalStrm = bodyPart.Data;
     if (originalStrm != null)
     {
      //Read Incoming data
      string data = "";

      StreamReader sreader = new StreamReader(originalStrm, System.Text.Encoding.UTF8);

      //Receive pipeline, parse MIME document and extract XML
      data = this.fromMIME( sreader.ReadToEnd() );     


      //Send the data back to the Message
      StreamWriter swriter = new StreamWriter(strm, System.Text.Encoding.UTF8);
      swriter.Write(data);
      swriter.Flush();
      strm.Seek(0, System.IO.SeekOrigin.Begin);

      // IMPORTANT CODE HERE: Promote the message type context property
      string systemPropertiesNamespace = "http://schemas.microsoft.com/BizTalk/2003/system-properties";
      string messageType = "www.clearscreen.com#Response"; 
      inmsg.Context.Promote("MessageType", systemPropertiesNamespace, messageType);

     }
    }
   }
   catch (Exception ex)
   {
    System.Diagnostics.EventLog.WriteEntry(ex.Source, ex.Message + "\n" + ex.StackTrace, System.Diagnostics.EventLogEntryType.Error);
    strm = (MemoryStream) originalStrm;
   }
   finally
   {
    bodyPart.Data = strm;
    pc.ResourceTracker.AddResource( strm );
   }
            
   return inmsg;
  }

Hope this helps!

posted @ 5:12 PM