Criando Custom Pipeline Disassembler - Quebra de FF em N Registros. Parte 2

Olá Pessoal. Essa é o segundo post sobre como criar um Custom Pipeline Disassembler.
Na primeira parte do post, falamos sobre quando criar esse tipo de componente, como criar o projeto e adicionar as referencias necessárias.
Como prometido vamos implementar a Interface IDisassemblerComponent.
Nessa interface exige que implementemos basicamente dois métodos: o Disassemble e o GetNext.

 Adicionando as Bibliotecas

Antes de começar, vamos adicionar a dll Microsoft.Biztalk.XpathReader e Microsoft.BizTalk.Component.Utilities
Basta clicar em Add Reference e apontar para o caminho abaixo:
C:\Windows\assembly\GAC_MSIL\Microsoft.Biztalk.XpathReader\3.0.1.0__31bf3856ad364e35\Microsoft.Biztalk.XpathReader.dll
C:\Windows\assembly\GAC_MSIL\Microsoft.BizTalk.Component.Utilities\3.0.1.0__31bf3856ad364e35\Microsoft.BizTalk.Component.Utilities.dll
E precisamos adicionar as seguintes bibliotecas:
using System.Resources;
using System.Reflection;using System.Diagnostics;using System.Collections;
using System.ComponentModel;
using System.Xml.XPath;
using System.Xml;
using Microsoft.BizTalk.XPath;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Component;
using Microsoft.BizTalk.Messaging;
using Microsoft.BizTalk.Component.Utilities;
using Microsoft.Samples.BizTalk.Pipelines.CustomComponent;
Adicione as váriaveis globais:
private ArrayList outboundMessages = null; 
private int currentMessage = 0; 
private bool stopCollectingMessages = false;

Compilando a classe SeekableReadOnlyStream
No mundo do Biztalk devemos evitar usar a classe xmlDocument para tratar mensagens grandes (leia-se > 2mb). Junto com a instalação do Biztalk a Microsoft disponibiliza a classe SeekableReadOnlyStream, que pode tratar arquivos > 100 mb. Bastante hein?

Só que, essa classe não é nativa do .NET, ela esta disponivel em um Sample e deve ser compilado e publicado no GAC com strong key (chave de registro).

1 - Então vá até o diretório:
%Diretorio_de_Instalacao%\Microsoft BizTalk Server 2010\SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm
2 - Abra a solution SchemaResolverFlatFileDasm.sln
3 - Acrescente uma strong key e faça o deploy normalmente.

Implementando as Interfaces

Agora no nosso projeto adicione a dll que foi gerada e cole o código abaixo na classe TrataFlatFile.cs


   1:  void IDisassemblerComponent.Disassemble(IPipelineContext pContext, IBaseMessage pInMsg)
   2:          {
   3:              try
   4:              {
   5:                  base.DocumentSpecName = this.DocumentSpecName;
   6:                  base.Disassemble(pContext, pInMsg);
   7:              }
   8:              catch (Exception ex)
   9:              {
  10:                  System.Diagnostics.EventLog.WriteEntry("SampleDisassemble", ex.Message,
  11:                                                          EventLogEntryType.Error);
  12:              }
  13:   
  14:          }
  15:   
  16:          IBaseMessage IDisassemblerComponent.GetNext(IPipelineContext pContext)
  17:          {
  18:              //System.Diagnostics.EventLog.WriteEntry("GetNext:Called", currentMessage.ToString()); 
  19:              try
  20:              {
  21:                  if (stopCollectingMessages == false)
  22:                  {
  23:                      outboundMessages = new ArrayList();
  24:                      IBaseMessage ibmTemp = base.GetNext(pContext);
  25:                      GetSplittedMessages(ibmTemp, pContext);
  26:                      stopCollectingMessages = true;
  27:                      if (0 == outboundMessages.Count)
  28:                          return null;
  29:                  }
  30:              }
  31:              catch (Exception ex)
  32:              {
  33:                  System.Diagnostics.EventLog.WriteEntry("SampleDisassemble", ex.Message,
  34:                                                          EventLogEntryType.Error);
  35:              }
  36:   
  37:              if (currentMessage == outboundMessages.Count)
  38:                  return null;
  39:              // Return the current collected message 
  40:              return (IBaseMessage)outboundMessages[currentMessage++];
  41:   
  42:          }
A mágica vai acontecer no método GetNext. E a quebra acontece no método GetSplittedMessages;

Segue o código:


   1:          private void GetSplittedMessages(IBaseMessage ibmParam, IPipelineContext pCxt)
   2:          {
   3:              XmlDocument xDoc = new XmlDocument();
   4:   
   5:              SeekableReadOnlyStream seek = new SeekableReadOnlyStream(ibmParam.BodyPart.Data);
   6:   
   7:              XPathCollection xCollection = new XPathCollection();
   8:              XPathReader xReader = new XPathReader(new XmlTextReader(seek), xCollection);
   9:   
  10:              int iHeader = xCollection.Add("/*[local-name()='Root' and namespace-uri()='Namespace']/*[local-name()='Intercambio' and namespace-uri()='']");
  11:   
  12:              bool blnMoveNext = true;
  13:              int iCont = 1;
  14:   
  15:              while (blnMoveNext)
  16:              {
  17:                  blnMoveNext = xReader.ReadUntilMatch();
  18:                  iCont++;
  19:                  XmlElement xeHeader = xDoc.CreateElement("Header");
  20:   
  21:                  StringBuilder xml = new StringBuilder();
  22:   
  23:                  do
  24:                  {
  25:                      if ("Header" != xReader.LocalName)
  26:                      {
  27:                          switch (xReader.NodeType)
  28:                          {
  29:                              case XmlNodeType.Element:
  30:                                  xml.Append("<" + xReader.LocalName + ">");
  31:                                  if (xReader.IsEmptyElement)
  32:                                      xml.Append("<" + xReader.LocalName + "/>");
  33:                                  break;
  34:                              case XmlNodeType.Text:
  35:                                  xml.Append(xReader.Value);
  36:                                  break;
  37:                              case XmlNodeType.EndElement:
  38:                                  xml.Append("</" + xReader.LocalName + ">");
  39:                                  break;
  40:                              case XmlNodeType.XmlDeclaration:
  41:                                  xml.Append("</" + xReader.Name + ">");
  42:                                  //writer.WriteProcessingInstruction(xReader.Name, xReader.Value);
  43:                                  break;
  44:                          }
  45:                      }
  46:                  } while (xReader.Read() && !xReader.Match(iHeader));
  47:   
  48:   
  49:                  if (iCont > 50) //Quantidade de Registros na quebra
  50:                  {
  51:                      iCont = 1;
  52:                      XmlElement xeRoot = xDoc.CreateElement("Root");
  53:                      xeRoot.InnerXml = xml.ToString();
  54:   
  55:                      xDoc.AppendChild(xeRoot);
  56:   
  57:                      IBaseMessage msg = null;
  58:                      msg = pCxt.GetMessageFactory().CreateMessage();
  59:                      msg.Context = ibmParam.Context;
  60:   
  61:                      IBaseMessagePart msgPart = pCxt.GetMessageFactory().CreateMessagePart();
  62:                      System.IO.MemoryStream memStrm = new MemoryStream();
  63:                      xDoc.Save(memStrm);
  64:   
  65:                      memStrm.Position = 0;
  66:                      memStrm.Seek(0, System.IO.SeekOrigin.Begin);
  67:                      msgPart.Data = memStrm;
  68:                      msg.AddPart(ibmParam.BodyPartName, msgPart, true);
  69:   
  70:                      outboundMessages.Add(msg);
  71:                      pCxt.ResourceTracker.AddResource(memStrm);
  72:                  }
  73:              }
  74:          }
Compile o projeto e copie a DLL gerada para a pasta \Microsoft BizTalk Server 2010\Pipeline Components

Lembrando que é necessário publicar a dll no GAC com o strong key, assim o custom Disassembler criado irá aparecer na tag Pipeline Components.


image


Conclusão:
Aprendemos neste post a usar a classe SeekableReadOnlyStream  que pode tratar arquivos > 100 mb e vimos como quebrar essas mensagens em 50 registros por vez.
Assim quando o Biztalk receber um arquivo com 200 registros irá ser criado 4 instancias contendo 50 registros cada uma.

Espero que tenham gostado! Até a próxima…

Seja o primeiro a comentar ;)

Postar um comentário

BizTalk 360

Visitas

Arquivo do blog