In the BizTalk SDK, there is a sample pipeline component that allows this feature (see the project inside \Microsoft BizTalk Server 2006\SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm), but this component only recognizes different documents if them have a Tag Identifier in the first two characters.
My problem was a bit different. The difference between documents is in a concrete position:
DOCUMENT DATA MESSAGE TYPE 65 DOCUMENT DETAIL
The info about wich is the flat file schema is inside the message (in previous sample, was 65 the identifier).
I have modified the SDK sample Pipeline Component to select the correct schema with the info inside the different messages.
First of all, I added two new properties: StartPosition and ReadLength. StartPosition indicates where the identifier characters starts. ReadLength is the identifier's length.
private int startPosition = 0;Second step is to implement the IPersistPropertyBag, to save and load this properties:
private int readLength = 0;
public int StartPosition
{
get
{
return startPosition;
}
set
{
startPosition = value;
}
}
public int ReadLength
{
get
{
return readLength;
}
set
{
readLength = value;
}
}
public void Load(IPropertyBag propertyBag, int errorLog)Third and last step is modify the Probe method, that reads the message stream, at the StartPosition position ReadLength characters:
{
object property = null;
propertyBag.Read("StartPosition", out property, errorLog);
if (property != null)
StartPosition = (int)property;
propertyBag.Read("ReadLength", out property, errorLog);
if (property != null)
ReadLength = (int)property;
}
public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
{
object ptrVar = StartPosition;
propertyBag.Write("StartPosition", ref ptrVar);
ptrVar = ReadLength;
propertyBag.Write("ReadLength", ref ptrVar);
}
public bool Probe(IPipelineContext pContext, IBaseMessage pInMsg)At last, GetMessageType method in SDK sample, hard-coded the schemas DocumentSpec. We can modify this method to retrieve this information from a config file or SSO as config store.
{
if (null == pContext)
throw new ArgumentNullException("pContext");
if (null == pInMsg)
throw new ArgumentNullException("pInMsg");
if (null == pInMsg.BodyPart || null == pInMsg.BodyPart.GetOriginalDataStream())
return false;
ReadOnlySeekableStream stream = new ReadOnlySeekableStream(pInMsg.BodyPart.GetOriginalDataStream());
Stream sourceStream = pInMsg.BodyPart.GetOriginalDataStream();
if (!sourceStream.CanSeek)
{
ReadOnlySeekableStream seekableStream = new ReadOnlySeekableStream(sourceStream);
pInMsg.BodyPart.Data = seekableStream;
sourceStream = pInMsg.BodyPart.Data;
}
long position = sourceStream.Position;
char[] identifier = new char[ReadLength];
try
{
StreamReader reader = new StreamReader(sourceStream);
reader.BaseStream.Position = StartPosition;
if (reader.Read(identifier, 0, identifier.Length) < identifier.Length)
return false;
}
finally
{
sourceStream.Position = position;
}
string messageType = GetMessageType(new string(identifier));
if (null == messageType)
return false;
IDocumentSpec documentSpec = pContext.GetDocumentSpecByType(messageType);
pInMsg.Context.Write(DOCUMENT_SPEC_NAME_PROPERTY_NAME, XML_NORM_NAMESPACE_URI, documentSpec.DocSpecStrongName);
return disassembler.Probe(pContext, pInMsg);
}
1 comment:
Thank you, that was extremely valuable and interesting...I will be back again to read more on this topic.
Post a Comment