Saturday, April 26, 2008

Subscriptions Viewer

Subscription Viewer was a very useful utility that was installed in the BizTalk installation folder to see the subscriptions. In Biztalk 2006 you can see the susbcriptions in the BizTalk using the Administration Console.


Double click on the subscription to subscription detials.

Some good interview questions: local-name function - Persistance Points in Orchestration

Why do we need to use the local-name function in our XPath expressions?

"local-name" function returns the node name in XML Document ignoring the namespace, for example the following XPath expression should fail if the xml document has namespace prefix:

/Order/OrderID

But this will never fail.
/*[local-name()=’Order’]/* [local-name()=’OrderID’]

What is the problem with the above approach?

We are ignoring the namespace completely which is not correct, we have sovled the problem by introducing a new one.
To overcome this we should include the namespace in the above expression as follows:
/*[local-name()='Order' and namespace-uri()='http://namespace']/*[local-name()='OrderID' and namespace-uri()='']



Sample Data:

Notice the use of the prefix in the above sample date, we have prefix "nso" this prevent using the simple XPath expression mentioned above without using the local-name

BizTalk Naming Conventions

I have been through the BizTalk Naming conversions, I think this is a good starting point. However, I don't agree with using Hungarian notation in orchestration shapes as well as using underscore.
For example: Scope_CreditServiceCall, Rcv_rawCreditReport

My reasons are:

1- It doesn't follow the same standard in the first section named "BizTalk Messaging Artifacts"
2- Microsoft doesn't recommend using Hungarian notation in .NET coding standard.
3- If you see list of orchestration objects in a tree it will be difficult to find the object if you have a big list.

Sunday, January 14, 2007

SQL Server Adaptor Ignores TimeOut Property

If you tried to increase the timeout in you SQL Server Port, it will not be saved in the connection string. A workaround is to edit the connection string manually in the property pane (don't open the connection property dialog).
You need to change it everytime you change the adaptor settings

;Connect Timeout=500;


Monday, December 25, 2006

UnZip Pipeline components A2Z

I have read this blog entry which is good start for anyone interested in writing UnZip pipeline component for BizTalk, but when you try the code you notice it doesn't work because the code doesn't promote the properties to the newly created messages. When you read the comments, you can find that you need to add some code. This is not only the issue, I'm going to discuss all issues and solutions here.

My Pipeline does the following (more on that later):

1. Promotes the Message Type context Property based on the Pipeline properties.

2. Handle directories in zip file (all files are extracted from zip file even if it is inside any folder)

3. Reader the stream in the proper way (the articles code doesn't work actually, and I got an exception).

4. Handle Password for zip files (A property in Pipeline)


public void Disassemble(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
Stream strmZipFile;
IBaseMessagePart msgPart;
msgPart = inmsg.BodyPart;
strmZipFile = msgPart.GetOriginalDataStream();
ZipInputStream oZipStream = new ZipInputStream(strmZipFile);
if (!string.IsNullOrEmpty(mPassword))
oZipStream.Password = mPassword;
try
{
ZipEntry sEntry = oZipStream.GetNextEntry();
while (sEntry != null )
{
if (sEntry.IsDirectory)
{
sEntry = oZipStream.GetNextEntry();
continue;
}
MemoryStream strmMem = new MemoryStream();
byte[] buffer = new byte[4096];
int count = 0;
while ((count = oZipStream.Read(buffer, 0, buffer.Length)) != 0)
strmMem.Write(buffer, 0, count);
strmMem.Seek(0, SeekOrigin.Begin);
msgPart.Data = strmMem;
IBaseMessage outMsg;
outMsg = pc.GetMessageFactory().CreateMessage();
outMsg.AddPart("Body", pc.GetMessageFactory().CreateMessagePart(), true);
outMsg.BodyPart.Data = strmMem;
for (int iProp = 0; iProp < inmsg.Context.CountProperties; iProp++)
{
string strName;
string strNSpace;
object val = inmsg.Context.ReadAt(iProp, out strName, out strNSpace);
// If the property has been promoted, respect the settings
if (inmsg.Context.IsPromoted(strName, strNSpace))
outMsg.Context.Promote(strName, strNSpace, val);
else
outMsg.Context.Write(strName, strNSpace, val);
}
if (this.Namespace != null && this.RootElementName != null)
{
string messageType = string.Format("{0}#{1}", this.Namespace, this.RootElementName);
outMsg.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", messageType);
}
_msgs.Enqueue(outMsg);
sEntry = oZipStream.GetNextEntry();
}
}
catch (Exception ex)
{
Debug.Write(ex.Message + Environment.NewLine + ex.StackTrace);
throw;
}

You notice that I have two property "Namespace" and RootElementName, I use it to promote "MessageType" property, the author suggests to load xml document to get the message type, which is not a good idea for large message, so I have created those two properties. This means that all messages come out of the pipeline will have same type and root element (your zip file will contains same message types, not bad limitation).

Note:

- I will write a version to use XmlReader to get the message Namespace and Root Element.

- We also copy the original message context to each newly created message (this code comes from the author feedback in the code project)

His code to read and write the stream doesn't work and I got the following exception from "Invalid offset/count combination", I changed the way we read/write the stream and it is working fine now.


Last issue to discuss is: what if you have a message that contains envelope and you want to execute the XmlDisassemble pipeline component after running the Unzip pipeline. You can't do that because the Disassemble stage only allows one components to be run (first match).

There is a workaround, you can move unzip code to the Decode stage, but you will have a limitation, your zip file should contain one message only, because the decode stage receives single message and outputs single message. You can find a complete sample in Pro BizTalk book, if you don't have the book, don't panic, download the book code samples from apress site.

Download Source Code

Sunday, December 17, 2006

Custom Pipeline Components in BizTalk 2006 Best Practise

1. You will find a lot of people talking about create custom pipelines.
2. Read Stephen comment on using Custom pipeline
3. To add you pipeline to the MSI package:
A. Deploy you BizTalk project
B. Open BizTalk Admin Console (BTSmmc.msc)
C. Open Resources node and Add you new "Add new resources" context menu.
D. Check 'Add to Global Assembly Cache on MSI Import'


BizTalk XmlNamespace Resolver Pipeline

Namespaces in BizTalk is an essential part of the input documents, although, BizTalk can deal with messages without namespaces, it is not the best practice.
Suppose you have an incoming xml message without a namespace and it may have some processing instructions or doctype .
The following disassemble pipeline does that clean up and add the namespace to the incoming document.
When you complete and deploy your custom pipeline component, you need to add new custom pipeline in your BizTalk Project, and then set the namespace preopery.
All messages pass thorough this pipeline will have the same namespace and it will be cleaned up from any processing instructions.


Note:
I recommend read this article (UnzipDisassembler - A custom pipeline component for BizTalk Server 2004).Then use BizTalk Server Pipeline Component Wizard in the disassemble method, just copy and past that code, you will need to define a preoperty of name 'Namesapce' during the new pipline component wizard.
I will not write a complete steps, the important thing here is dealing with streams in the disassemble method.


public void Disassemble(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
XmlAttribute namespaceAttribute;
string rootNodeName;
XmlDocument originalXmlDocument;
XmlDocument newXmlDocment;
MemoryStream memStream;
byte[] data;


originalXmlDocument = new XmlDocument();
originalXmlDocument.XmlResolver = null;

originalXmlDocument.Load(inmsg.BodyPart.GetOriginalDataStream());

// This not bad in case of small message size.
newXmlDocment = new XmlDocument();
newXmlDocment.LoadXml(originalXmlDocument.DocumentElement.OuterXml);
namespaceAttribute = newXmlDocment.CreateAttribute("xmlns");

// That is not accurate, User should specify the root node or we read that information from the schema.
rootNodeName = newXmlDocment.FirstChild.Name;
namespaceAttribute.Value = mNamespace ;
newXmlDocment.DocumentElement.Attributes.Append(namespaceAttribute);

inmsg.RemovePart("Body");
inmsg.AddPart("Body", pc.GetMessageFactory().CreateMessagePart(), true);


memStream = new MemoryStream();
// what about UTF16 messages?
data = UTF8Encoding.UTF8.GetBytes(newXmlDocment.OuterXml);
memStream.Write(data, 0, data.Length);
memStream.Seek(0, SeekOrigin.Begin);
inmsg.BodyPart.Data = memStream;
inmsg.BodyPart.ContentType = "xml";
inmsg.Context.Promote("MessageType", "http://schemas.microsoft.com/BizTalk/2003/system-properties", mNamespace + "#" + rootNodeName);

_msgs.Enqueue(inmsg);
}

Saturday, June 17, 2006

Visual Build Professional

Currently, I'm developing a SOA application where we have a lot of projects, the main challenge was to build good CM (Configuration management) strategy.
We wrote a lot of scripts to follow continues integration guideline from Martin Folwer (nightly build, create distributed application, notify our client about a new build, upload to FTP , etc.)
We put a lot of effort into that scripts and we are in very good shape now, but today, I find this tool, Visual Build Professional , which I think it would have saved a lot of time for me.
anyway, I got an evaluation version, I will play with it and I will publish my feedback soon.


VS 2005 Web Application Project - BizTalk Publishing Wizard

VS 2005 Web Application Project has been release, I like it so much. It replaces web application templates in VS.NET 2005 so that we can use the old build model (which I like).
BizTalk publishing Wizard uses the new project model for generated web services (i.e. No project file is there, just solution file). I don't like this approach.
Today, I have tried to create a new project (Web Service project) using vs.net 2005 Web Application Project and I sucessfully move the generated code to it.
I was able to test my receive location againts the newly created web services.
See the picture below so you can image what could be done (Just copying the files to the new project, but take care of the directory structure).

Friday, June 16, 2006

BizTalk 2004/2006 and Visual Source Safe

Now every one can use Source Safe 2005 to store (Map, Schemas, etc.). In VSS 6.0 we used to tell VSS to deal with biztalk files as binary, becuase VSS wouldn't have understood the unicode files, that is good news.
An idea comes to my mind, what about developing visualizer to compare biztalk maps and orchestration, so you can see the dif. instead of tracking the xml files.

Saturday, May 13, 2006

Custom Trace Listener (Debug) for EntLib

Why reinvent the wheel and create this custom trace listner?
The current custom trace listerner in the documentation uses debug .write, which doesn't work in the "release" mode.
I would like to show trace message to debugview even in release mode.
OutputDebugString do the magic, see the code below
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Practices.EnterpriseLibrary.Common
.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging
.Configuration;
using Microsoft.Practices.EnterpriseLibrary.
Logging;


namespace TareqCo.Framework.Logging
{
[ConfigurationElementType
(typeof(CustomTraceListenerData))]
public class DebugTraceListener:Microsoft.Practices.
EnterpriseLibrary.Logging.TraceListeners.CustomTraceListener
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void OutputDebugStringA
(string message);

public override void TraceData(TraceEventCache eventCache,
string source, TraceEventType eventType, int id,
object data)
{
if (data is LogEntry && this.Formatter != null)
{
this.WriteLine(this.Formatter.Format(data as
LogEntry));
}
else
{
this.WriteLine(data.ToString());
}
}

public override void Write(string message)
{
OutputDebugStringA(message);
}

public override void WriteLine(string message)
{
OutputDebugStringA(message);
}

}
}

All you need to know about Generics

I'm fan of Generics and I used it immediately when it is released, It reduced our amount of code so much
Join our Group Of Experts @ http://url123.com/27gd6
Find articles and tutorials @ http://url123.com/2shdd
Learn about Generic collections @ http://url123.com/27rdu
Read an extensive introduction @ http://url123.com/2swdy
Read about the pros and cons @ http://url123.com/2s5d3
Good book
Professional .NET 2.0 Generics

Good Luck all of you...