Yossi Dahan [BizTalk]


Monday, January 29, 2007

Related activities do not show up in the BAM portal

I'm playing with the concept of the tracking portal using BAM.

This is the sort of thing you usually only get to do towards the end of a phase in a project (or the end of the project, or not at all in many cases), which is usually just a little bit too late, but gladly in my current engagement we got to it early enough as tracking is a key requirement from our engine.

Anyway, while I've been busy creating activities and developing pipelines and pipeline components to write to them, I was less concerned about displaying the information

I know there's the BAM portal, but with very specific requirements for tracking and viewing tracked data, with the need to integrate this into our existing portal, and having a great web development team, we pretty much assume we will be developing cusotm UI to display the information, possibly utilizing the BAM web services, possibly not.

So you can understand why my only concern was to get the data into the BAMPrimaryImport database, so I put a lot of effort into defining the activities correctly, and writing to them appropriately and setting up relationships between them, but I've put very little effort into defining views as I do not plan to use them. to me - as long as the activies were populated and their relationships were created ok, my worries were over.

Regardless, I've decided to see what the BAM portal can do for me, mainly because I was tried of trying to make sense of rows in tables in the SQL management studio during development.

The BAM portal is actually quite nice as a basic tool to view activities., you can query your acitivites to find specific ones, and then see all the information about them, and you can see all the related activities for the once you've selected apparently.

Only that for some reason, while I knew that for a single activity I should have a lot of related acitvies defined, and I know they are linked correctly in the database, I could not see any appear on the screen.

I've decided to look into it so I've opened up sql profiler an quickly found out that the stored procedure called to get the related acitivtied for a particular activity is passed the name of the view to use for the lookup as a parameter. that seemed ok enough.

Looked into the stored procedure it self it became clear that the query does not look for any related activity that exist, but only realted instances of activities included in that view.
I guess that makes sense as activity id is not guarenteed to be unique across activity types, so you cannot look for "123" as your related acitivity, you need to look for "PO 123".

In my case - the view I created, mainly because I did not care much for the views as explained earlier, only included to top level activity, the related activities were not included in the view, and there fore did not appear on the portal.

After I've changed my view to include all the related activities I could infact see the related acitivites list in the portal populated.


Friday, January 12, 2007

Checking if a context property exists - the proper way

I wrote this two days ago, but as it appears, I was unaware of a crucially useful option.

Following through Richard Seroter's useful post I read through the list of the expression shape's allowed operations when I spotted exists

Using this operatoins one can use an expression such as "BTS.RetryCount exists Message_In" to check for the existence of a context property in the message.


This does allow us to have that if instead of a try catch.
I still find it strange that there's an inconsistency between the behaviour in the orchestration and the XLNGMessage's GetPropertyValue, but I can't really complain now that I know there is a good solution.


Wednesday, January 10, 2007

Checking if a context property exists

Note: I've added an important update here

I've mentioned this briefly in one of my previous posts, but really I think the subject deserves its own post -

There's a certain behaviour of BizTalk that does not fit, in my view, with a certain development guideline.

Generally, it is said, one should not use exceptions to control the flow of an application. exceptions should be there to handle, as their name suggest, exceptional situations.

What that comes down to (a very short description) is that, for example, if you're about to use a member that might contain null, it is better to encpasulate your work in an if(a!=null) block rather than using a try catch block around the access to the member to catch any NullReferenceException.

However, in BizTalk, if you try to access a context property that does not exist in the message context you will get a MissingPropertyException thrown. this means that if you need to check for the existence of a property from within an orchestration you will have to do that in a scope with an exception handler, so that if the exception was thrown you know the property does not exist, if it wasn't thrown the proeprty has a value.

While this gets the job done it is not in line with the guidance around exception handling and is not performing as well as an if (exceptions are more expensive than control flow statements)

Somewhat surprisingly in a way, there is a second option that works - you can pass your message to a helper class and use the XLANGMessage's GetPropertyValue method to access the value. this method is inconsistent with the use of context properties in an orchestration as it returns null if the property does not exist (which is good news for our purpose)

you can read more about it here



Reading a context property of a message in an orchestration is straight forward; however, when passing the message to an external assembly, although still very easy, the approach may be somewhat confusing at first.

The XlangMessage class has a GetProeprtyValue method to return the value of a context property.

The method takes in a type as a parameter and returns an object.
Returning an object makes perfect sense as the type of the context property you're reading can vary, but what is the type as the input parameter?

It is not obvious at first but when you create a property schema, as with pretty much everything in BizTalk that compiles into a class. The class would reside in a .net namespace defined in the namespace property of the property schema. The name of the class would be the name you set in the type name property. (both exist in the property page accesible by slecting the xsd file of the property schema and switching to the properties pane.

Further more, in the case of property schemas, each property is compiled into a class as well. These classes will reside in the same .net namespace as the property schema and have a class name as the name of the element.

This is, of course, true for your own custom context properties as well as the system context properties such as the various adapter's context properties.

Most of the system context properties are defined in the assembly Microsoft.BizTalk.GlobalPropertySchemas. You can easily see the various namespaces and classes if you look it up in Visual Studio's object browser.

So - back to GetProeprtyValue - it all comes together now - the parameter to the function is the .net type of the property it's value you want to get - if you want to use the File adpaters ReceivedFileName property add a reference to Microsoft.BizTalk.GlobalPropertySchemas and pass typeof(FILE.ReceivedFileName) as the paremeter.

If you have created a property called MyProperty in a property schema called MyContext than you will need to pass in typeof(MyContext.MyProperty) as the parameter


Friday, January 05, 2007

Import MSI Gotcha

When deploying BizTalk MSI's to servers I usually import them in the Admin Console before running the MSI.

The main reason is pure laziness - in the last screen of the import wizard there's a small checkbox you can tick to have the wizard start the MSI installation and that saves me from the hassle of browsing to it again. as simple as that.

Of course that fact that this tick box exists implies that doing things in that order is supported and, indeed, in most cases there's absolutley no problem with it.

Only that we've recently found a case where this approach does not work.

Apparently when you import a policy (or vocabulary, not sure which one actually causes the problem) that is using a .net object as a fact, BizTalk tries to load the assembly with the .net class from the GAC at the import stage.

I'm not sure why it does that, presumably for some sort of validation, but possibly just an oversight; anyway, what that means is that, if the assembly containing the .net class is in the same MSI as the policy/vocabulary, when BizTalk tries to import the policy it has not (yet) added the assembly to the GAC and so the import would fail.

Making sure the assembly is in the GAC before starting the import (i.e 'installing' the MSI before 'importing' it) avoids this issue.

And another important note - to make things worse the Admin console seems to "remember" the fact that the assembly was not found, so if you try to import the MSI, get the error, close the wizard, add the assembly to the GAC and then try to import again you will be very surprised to fail again.

All you need to do is close the Admin Console and open it again and, assuming the assembly is now in the GAC you should be able to import the MSI succesfully.