Quantcast
Channel: Gobbledygooks
Viewing all 102 articles
Browse latest View live

Speaking at Developer Summit 2008!

$
0
0

Developer Summit 2008Whoho! I'll be speaking at Developer Summit 2008. Developer Summit is a conference hosted by Cornerstone, it's being held in Stockholm between the 9th and 11th of April 2008.

I'll be doing a talk on Master Data Management (MDM) for the Enterprise using BizTalk 2006. Basically I'll present some basic theory behind the MDM concept and how it relates to SOA. Then I'll relate all that to a customer case I recently worked on solving a MDM requirement. Finally I'll be showing a short demo where I publish some Master Data and update all subscribers to it. In the same demo I'll also demonstrate on how to monitor the process using Business Activity Monitoring.

Sound interesting? Something specific you think should be in the presentation? Let me know!

Hope to see you there!


A loosely coupled Scatter-and-Gather implementation In BizTalk 2006

$
0
0

Why loose coupling?

There was a question in Microsoft BizTalk forums the other day about how one could implement a Scatter and Gather pattern in a more loosely coupled fashion.

Most examples on the implementation of this pattern in BizTalk use the Call Shape functionality available in BizTalk orchestrations. This however creates a hard coupling between the "Scatter orchestration" and it's "partner orchestrations". The downside of that is that when one adds or removes a partner the whole solution has to be recompiled and redeployed.

If one however could use the publish-subscribe architecture in the MessageBox to route messages between the "Gather orchestration" and it's partners, it'd be possible to add partners without having to worry about the rest of the solution. This post shows and example on how to implement a solution like that.

The BizTalk process in steps

>> [![Aa559774_note(ja-jp,MSDN_10)](../assets/2008/01/aa559774-noteja-jpmsdn-10-thumb.gif)](../assets/2008/01/aa559774-noteja-jpmsdn-10.gif) NOTE: Notice the difference between the **Partners**Request, the **Partners**Response, the **Partner**Request and the **Partner**Response messages. The names are unfortunately very similar. >>>> The **Partners**Request and **Partners**Response messages are used for communication between the Scatter and the Gather orchestrations. It's also a **Partners**Request message that activates the process. >>>> **Partner**Response and **Partner**Request are used for communicating between the Scatter and the Gather orchestration and all the partner orchestrations. >>
  1. Request and scatter
    A PartnersRequest message is received. This message is an empty message and is only used for activating the process in this example scenario. The PartnersRequest message is consumed by the Scatter orchestration. The Scatter orchestration creates one PartnerRequest message. The orchestration also generates a unique key called a RequestID and start a correlation combining that that id and the PartnersRequest MessageType. Finally it post the PartnerRequest message to message box, writes the generated RequestID to the request messages context (RequestID is a MessageContextPropertyBase based context property) and dehydrates itself.
    LooselyCoupledScatterGather1

  2. Partners
    All the enlisted Partner orchestrations pick up the PartnerRequest message from the message box. These orchestration then communicates with their specific data source (could be a service, database, file or whatever), receives a response. Finally these orchestrations transform the response they received and creates a PartnerResponse message that's posted to the message box. Notice that the RequestID that was generated by the Scatter orchestration is also part of the context of the newly created PartnerResponse message.

  3. Gather
    The PartnerResponse messages are routed to the Gather orchestration. This orchestration uses a Singleton pattern based on the RequestID which all PartnerResponse messages carried with them in their context. This means that it'll receive all the PartnerResponse messages containing that same RequestID into the same orchestration instance (ergo all the Partners that were activated by the request message being sent from one Scatterer). For each message instance it receives it add it's price to a total price variable. When the Gather orchestration has received all the PartnerResponse messages (the orchestration knows how many Partners responses it should expect from one Scatterer orchestration and we can timeout if we don't get all expected with a timeframe) the total price we calculated is written to a PartnersResponse message.

  4. Response
    This message is routed back the Scatter orchestration by using the correlation it initialized in the start. It's finally this orchestration that send the final outgoing message (a PartnersResponse message).

Example solution

An example of the implementation can be downloaded from here.

The solution contains five different schemas.

  1. PartnersResponse
    Used for initializing the process.

  2. PartnersRequest
    Send from the Gather orchestration to the Scatter orchestration. It's also the final result and outgoing message from the process.

  3. PartnerRequest
    Picked up and activates all enlisted Partner orchestrations.

  4. PartnerRequest
    Send from the Partner orchestration containing the result from the Partner Service and send to the Gather orchestration.

  5. LooselyCoupledScatterGatherExampleProperties
    Property schema for storing the RequestID and to correlate all the PartnerResponses as well as the final PartnersResponse back to the Scatter orchestration.

Five orchestrations

  1. Scatterer orchestration
    The "main orchestration" that receives a request message from outside and "scatters" party requests to all the party orchestrations.

  2. Gatherer orchestration
    Gatherer orchestration that gathers all the responses from the partners and transforms these to a reply that is being routed back to the Scatterer and back out.

  3. Partner1, Partner2 and Partner3 orchestration
    Partner orchestrations that communicates to different services and receives price information.

Setting up and testing the example solution - it's easy!

When the solution is built and deployed one needs to setup and bind two ports; one outgoing port and one incoming port (this could also be a Request-Response port by changing the port type in the Scatterer orchestration). That's it!

Enlist and start everything by dropping a PartnersRequest test message (you'll find one among the zipped files) in the incoming folder. A PartnersResposne message should then be published in the outgoing folder containing a calculated price from all the Partner orchestrations.

Test message and a binding file are part of the zipped solution.

What would be different in "real life" solution?

I've made some major simplifications in this example to make it easy for setting it up and test the concept. These would very different in a "real" solution.

Partner Services

The Partner orchestrations are very simple. They actually don't communicate with outside world at all. All the do is setting a hard coded price and post a response. In a real solution these would not be part of the same solution as the Scatter and Gather orchestration (otherwise we would be force to redeploy when adding a Partner orchestration to the dll).

The Partner orchestrations would also communicate with some sort of outbound source like a web service or database for example. This would however complicate the setup therefore I've skipped that part in the example.

Managing partners

One of the benefits with a loosely coupled implementation is the possibility to add and remove Partner orchestrations without having redeploy the rest of the solution. Using this implementation the Gatherer orchestration needs to know how many Partner responses it should wait for before timing out. This requires that value being set in a config file or something similar. In this example the number of Partners are hard coded into the Gather orchestration (it's set to 3 Partners) to simplify the setup.

Final thoughts

Knowing how to create loosely coupled solutions like this is good knowledge to have. It's my own and others belief that this architecture makes it possible to create more robust and separated solutions that one can update without having to do a lot a work and disturb the current processes. It's however not the best solution performancewise as it adds a lot of extra hits on the MessageBox database and generates more work for the MessageAgent.

There are also a few things to watch out for:

Eternal loops

It easy to end up in a situation where you're subscribing to the same message as you posting to the MessageBox. That'll create and endless loop and cause a lot disturbance before you'll find it. Think through and document you subscriptions!

Correlations for promoting values

When doing a direct post in BizTalk most properties are not promoted. To force you properties to be promoted you'll have to initialize a correlation on the property as you send it. I can't say I like this. There should be a other way of saying that one wants it promoted.

A couple of other useful articles as we on the subject:

Download the example orchestration and let me know how you used it and what your solution looks like!

Random thoughts on SQL Server Adapter and T-SQL Stored Procedures for BizTalk 2006

$
0
0

Writing Stored Procedures is an art of its own. As all of you know it's very different from writing ordinary code and presents its own kind of problems and issues when it comes to performance, builds, version control, testing etc. This post will try and highlight a few points that I find important when it comes to Stored Procedures, and the especially in a BizTalk and integration related scenario.

Consider the simplified procedure below, I'll use is an example for much of the discussion in the rest of the post. Basically the procedure inserts or updates (based on if the optional EmployeeID exists from before or not) employee information to the Employee table of a database named "TestDB".

<span class="kwrd"></span>








<div><span style="color: #0000ff">Use</span><span style="color: #000000"> </span><span style="color: #ff0000">[</span><span style="color: #ff0000">TestDB</span><span style="color: #ff0000">]</span><span style="color: #000000">
</span><span style="color: #0000ff">Go</span><span style="color: #000000"> 
</span><span style="color: #0000ff">If</span><span style="color: #000000"> </span><span style="color: #808080">Exists</span><span style="color: #000000">(</span><span style="color: #0000ff">select</span><span style="color: #000000"> </span><span style="color: #808080">*</span><span style="color: #000000"> </span><span style="color: #0000ff">From</span><span style="color: #000000"> dbo.sysobjects </span><span style="color: #0000ff">Where</span><span style="color: #000000"> id </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #ff00ff">object_id</span><span style="color: #000000">(N</span><span style="color: #ff0000">'</span><span style="color: #ff0000">AddEmployee</span><span style="color: #ff0000">'</span><span style="color: #000000">) </span><span style="color: #808080">And</span><span style="color: #000000"> </span><span style="color: #ff00ff">OBJECTPROPERTY</span><span style="color: #000000">(id, N</span><span style="color: #ff0000">'</span><span style="color: #ff0000">IsProcedure</span><span style="color: #ff0000">'</span><span style="color: #000000">) </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">) </span><span style="color: #0000ff">Drop</span><span style="color: #000000"> </span><span style="color: #0000ff">Procedure</span><span style="color: #000000"> AddEmployeeGo 
</span><span style="color: #0000ff">Create</span><span style="color: #000000"> </span><span style="color: #0000ff">Procedure</span><span style="color: #000000"> AddEmployee    
    </span><span style="color: #008000">@EmployeeId</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">Int</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #808080">-</span><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">,    
    </span><span style="color: #008000">@LastName</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">Varchar</span><span style="color: #000000">(</span><span style="color: #800000; font-weight: bold">30</span><span style="color: #000000">),    
    </span><span style="color: #008000">@FirstName</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">Varchar</span><span style="color: #000000">(</span><span style="color: #800000; font-weight: bold">30</span><span style="color: #000000">),    
    </span><span style="color: #008000">@MiddleName</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">Varchar</span><span style="color: #000000">(</span><span style="color: #800000; font-weight: bold">30</span><span style="color: #000000">)
</span><span style="color: #0000ff">As</span><span style="color: #000000"> 
</span><span style="color: #0000ff">Begin</span><span style="color: #000000">    
    </span><span style="color: #0000ff">Declare</span><span style="color: #000000"> </span><span style="color: #008000">@currentEmployeeId</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">int</span><span style="color: #000000">    
    </span><span style="color: #0000ff">Declare</span><span style="color: #000000"> </span><span style="color: #008000">@currentAction</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">tinyint</span><span style="color: #000000">    
    </span><span style="color: #008080">--</span><span style="color: #008080"> Check based on the EmployeeId if the employee exists from before    </span><span style="color: #008080">
</span><span style="color: #000000">    </span><span style="color: #0000ff">If</span><span style="color: #000000"> </span><span style="color: #808080">Not</span><span style="color: #000000"> </span><span style="color: #808080">Exists</span><span style="color: #000000">(</span><span style="color: #0000ff">Select</span><span style="color: #000000"> EmployeeId </span><span style="color: #0000ff">From</span><span style="color: #000000"> Employee </span><span style="color: #0000ff">Where</span><span style="color: #000000"> EmployeeId </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #008000">@EmployeeId</span><span style="color: #000000">)    
        </span><span style="color: #0000ff">Begin</span><span style="color: #000000">        
            </span><span style="color: #008080">--</span><span style="color: #008080"> Inserts new employee        </span><span style="color: #008080">
</span><span style="color: #000000">            </span><span style="color: #0000ff">Insert</span><span style="color: #000000"> </span><span style="color: #0000ff">Into</span><span style="color: #000000"> Employee (LastName,FirstName,MiddleName)         
            </span><span style="color: #0000ff">Values</span><span style="color: #000000"> (</span><span style="color: #008000">@LastName</span><span style="color: #000000">, </span><span style="color: #008000">@FirstName</span><span style="color: #000000">, </span><span style="color: #008000">@MiddleName</span><span style="color: #000000">)        
            </span><span style="color: #0000ff">Set</span><span style="color: #000000"> </span><span style="color: #008000">@currentEmployeeId</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #ff00ff">Scope_Identity</span><span style="color: #000000">()        
            </span><span style="color: #0000ff">Set</span><span style="color: #000000"> </span><span style="color: #008000">@currentAction</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">    
        </span><span style="color: #0000ff">End</span><span style="color: #000000">    
    </span><span style="color: #0000ff">Else</span><span style="color: #000000">    
        </span><span style="color: #0000ff">Begin</span><span style="color: #000000">        
            </span><span style="color: #008080">--</span><span style="color: #008080"> Updates employee        </span><span style="color: #008080">
</span><span style="color: #000000">            </span><span style="color: #0000ff">Update</span><span style="color: #000000"> Employee </span><span style="color: #0000ff">Set</span><span style="color: #000000"> LastName </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #008000">@LastName</span><span style="color: #000000">,        
            FirstName </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #008000">@FirstName</span><span style="color: #000000"> </span><span style="color: #0000ff">WHERE</span><span style="color: #000000"> EmployeeId </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #008000">@EmployeeId</span><span style="color: #000000">        
            </span><span style="color: #0000ff">Set</span><span style="color: #000000"> </span><span style="color: #008000">@currentEmployeeId</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #008000">@EmployeeId</span><span style="color: #000000">        
            </span><span style="color: #0000ff">Set</span><span style="color: #000000"> </span><span style="color: #008000">@currentAction</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #800000; font-weight: bold">2</span><span style="color: #000000">    
        </span><span style="color: #0000ff">End</span><span style="color: #000000">      

    </span><span style="color: #0000ff">Select</span><span style="color: #000000"> </span><span style="color: #008000">@currentEmployeeId</span><span style="color: #000000"> </span><span style="color: #0000ff">As</span><span style="color: #000000"> </span><span style="color: #ff0000">[</span><span style="color: #ff0000">@EmployeeId</span><span style="color: #ff0000">]</span><span style="color: #000000">, </span><span style="color: #008000">@currentAction</span><span style="color: #000000">     
    </span><span style="color: #0000ff">As</span><span style="color: #000000"> </span><span style="color: #ff0000">[</span><span style="color: #ff0000">@ProcedureAction</span><span style="color: #ff0000">]</span><span style="color: #000000"> </span><span style="color: #0000ff">For</span><span style="color: #000000"> Xml Path (</span><span style="color: #ff0000">'</span><span style="color: #ff0000">Response</span><span style="color: #ff0000">'</span><span style="color: #000000">)
</span><span style="color: #0000ff">End</span><span style="color: #000000">
</span><span style="color: #0000ff">Go</span></div>

Builds and version control

I always try to have the complete database version controlled. One solution to this that some people advocate is to have a central development database. I have however always found it to be a lot of hassle with overwriting each others changes and so on and always try to make it possible for each developer to build a local version of the database for development. It should also be possible to always check out the latest version and run it to build all the database objects - no matter what you have from before. This is of course a bit tricky when it comes to the actual tables as you might have data and so on (in my opinion it shouldn't be the case during development but that's another post discussing test data for the database etc).

When it however comes to Stored Procedure as in this post it's easy - drop the old one if it exists and create the new one as in the example.

<div><span style="color: #0000ff">If</span><span style="color: #000000"> </span><span style="color: #808080">Exists</span><span style="color: #000000">(</span><span style="color: #0000ff">select</span><span style="color: #000000"> </span><span style="color: #808080">*</span><span style="color: #000000"> </span><span style="color: #0000ff">From</span><span style="color: #000000"> dbo.sysobjectsWhere id </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #ff00ff">object_id</span><span style="color: #000000">(N</span><span style="color: #ff0000">'</span><span style="color: #ff0000">AddEmployee</span><span style="color: #ff0000">'</span><span style="color: #000000">) </span><span style="color: #808080">And</span><span style="color: #000000"> </span><span style="color: #ff00ff">OBJECTPROPERTY</span><span style="color: #000000">(id, N</span><span style="color: #ff0000">'</span><span style="color: #ff0000">IsProcedure</span><span style="color: #ff0000">'</span><span style="color: #000000">) </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">) </span><span style="color: #0000ff">Drop</span><span style="color: #000000"> </span><span style="color: #0000ff">Procedure</span><span style="color: #000000"> AddEmployee
</span><span style="color: #0000ff">Go</span><span style="color: #000000">
</span><span style="color: #0000ff">Create</span><span style="color: #000000"> </span><span style="color: #0000ff">Procedure</span><span style="color: #000000"> AddEmployee </span><span style="color: #008000">@EmployeeId</span><span style="color: #000000"> </span><span style="color: #000000; font-weight: bold">Int</span><span style="color: #000000"> </span><span style="color: #808080">=</span><span style="color: #000000"> </span><span style="color: #808080">-</span><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">, ...</span></div>

If found this article by Jeff Atwood over at Coding Horror (and the articles by K. Scott Allen it links to) very good on how to think about version control database objects.

Idempotent procedures

In complex integration solution it's a common problem with multiple messages - sending systems might send the same message twice for a number of reasons and one will end up with a shaky system if that causes an error in the integration. I've also seen solutions to this problem where a check is done against the database (say from a BizTalk orchestration) and based on that result a decision is made to call an update or an insert procedure. In my opinion that just unnecessary complexity and database communication. I believe one should try and handle whether to update or insert inside the procedure as long as that's possible and effective.

I in the AddEmployee Stored Procedure example might receive a EmployeeID as an input parameter and based on a check inside the procedure if the employee exists from before with that id a post is either updated or inserted.

Response message

I generally always want two things in return from a Store Procedure like the one in the AddEmployee example (In a select based procedure that would of course be very different as we like all the data in return).

  1. The id that been added or changed

  2. What action that's been performed (insert or update)

What action that was performed is a good idea to return as it's quite usual to use this in for example BAM tracking or other logging and so on (we might want know how many employees that was added versus updated for example).

Using the Xml Path syntax for generating the Xml response (thanks again Nick for a great post) from the procedure has made it even simpler to actually skip using the Add Generated Item option in BizTalk. All you have think about is to set name of the child node the request root node to the same name as the procedure (in this case AddEmployee). Also remember that the type should be set up as a Multi-Part Message Type in the orchestrations you use it from and that the Receive Pipeline you choose in the Send Port must use a Xml Disassembler component (XmlReceive pipeline will do fine unless you have your custom pipeline for some reason).

SchemaDBTest

Error handling

Some people might find it strange that I don't have any error handling in my Stored Procedures but in most cases an error in the procedure will cause an exception in the port communication with the database and that's fine. If I'd like to handle that error I'll handle that either in the orchestration or using other mechanisms in BizTalk like Failed Message Routing etc. If I can't handle the error in the procedure I don't see a reason to catch it.

Security

I've seen to many cases where developers actually used the user and password login option available on the database adapter and port. Even if the credentials are safe in the SSO database there is a risk you'll end up in a mess with login data spread all over the BizTalk administration. One should always use try to use Windows NT Integrated Security!

Even more common than the above is to have a user that part of the administrators group or similar to hit the database - don't! I usually try an set up one Host to run as in all the communication with a specific database (Could also be a Host for that database and that BizTalk Application so that different applications have their own Host). I'll then give that specific user the least privileges needed in the specific database.

In the AddEmployee and TestDB example I'd create a new Group in the AD called for example "BizTalk TestDB Users". I'd then create a User in the AD called "BizTalk TestDB User". It's based on this I'd then create a Host in BizTalk referencing the above created Group.

TestDBHost

Finally we'll create a Host Instance and make a Send Handler of it on the SQL Server Adapter.

DBTestHostInstance

DBTestSqlAdapter

Now we can set the least required privileges on the "BizTalk TestDB Users" in Sql Server as that the Group the User belongs that'll hit the database. In this case this means granting the Group to the standard BizTalk required privileges for a Host besides granting it Execute right on the AddEmployee Stored Procedure.

Something I missed? How do you handle your database communication and security in your BizTalk implementations?

Writing BizTalk context properties to a message from a WCF service using behaviors

$
0
0

The new WCF adapter in BizTalk 2006 R2 offers a lot of new possibilities. One of those is to write data to the BizTalk Message context properties directly from an exposed WCF Service. A practical use of this technic could be to write the username from the Windows credentials of the calling client into the context of the BizTalk message. This could be useful as this information is encrypted in messages that are received via the WCF adapter and isn't possible to read when inside BizTalk. I'll try and demonstrate the technique in this post.

If you have used the SOAP adapter before you might know that all you had to do was to turn on Windows based security for the exposed SOAP service and the username was automatically promoted to the context of the incoming BizTalk message. That username could then be used for routing, tracking which user called the service or using the value in plain text when communicating further to other connected systems. However using the WCF adapter this is not true anymore - when using the new WCF Message Security model the username and password is encrypted in the message and once the message is received by BizTalk it's to late to read it. Basically we have to read the username in the actual service and write it into our own context property (that doesn't get encrypted).

One way of achieving this is to read the username in the service and then to add it to the WCF Message Headers. All WCF message headers will by default be written to a the BizTalk Message context property called InboundHeaders (in the http://schemas.microsoft.com/BizTalk/2006/1/Adapters/WCF-properties namespace). First we'll create an EndpointBehavior that will use a MessageInspector to add the username to the message header. Finally we create BehaviorExtensionElement so we can use a WCF Custom Binding in BizTalk and configure it to add our new behavior.

Creating the new EndpointBehavior

To create the configurable behavior we'll need the three classes we mentioned above.

  1. A class that implements the IDispatchMessageInspector interface to handle to reading and writing to the actual message.

  2. A class that implements the IEndpointBehavior interface to define what kind of endpoint we're creating and what it should do.

  3. A class that implements the BehaviorExtensionElement abstract class to create the behavior and make it configurable.

    using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using System.ServiceModel.Configuration;

    namespace CustomWCFProperties.Behavior { ////// PromoteUserNameMessageInspector implements IDispatchMessageInspector and adds the name from the WindowsIdentity to a WCF header called WindowsUserName in the http://CustomWCFProperties.Schema namespace. BeforeSendReply only returns as we're not interested in handling the response. ///publicclass PromoteUserNameMessageInspector : IDispatchMessageInspector { #region IDispatchMessageInspector Members
    </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">object</span><span style="color: #000000"> AfterReceiveRequest(</span><span style="color: #0000ff">ref</span><span style="color: #000000"> System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            </span><span style="color: #0000ff">string</span><span style="color: #000000"> windowsUserName </span><span style="color: #000000">=</span><span style="color: #000000"> ServiceSecurityContext.Current.WindowsIdentity.Name;
            request.Headers.Add(MessageHeader.CreateHeader(</span><span style="color: #000000">"</span><span style="color: #000000">WindowsUserName</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">"</span><span style="color: #000000">http://CustomWCFProperties.Schema</span><span style="color: #000000">"</span><span style="color: #000000">, windowsUserName));
            </span><span style="color: #0000ff">return</span><span style="color: #000000"> </span><span style="color: #0000ff">null</span><span style="color: #000000">;
        }
    
        </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> BeforeSendReply(</span><span style="color: #0000ff">ref</span><span style="color: #000000"> Message reply, </span><span style="color: #0000ff">object</span><span style="color: #000000"> correlationState)
        {
            </span><span style="color: #0000ff">return</span><span style="color: #000000">;
        }
    
        </span><span style="color: #0000ff">#endregion</span><span style="color: #000000">
    }
    
    </span><span style="color: #808080">///</span><span style="color: #008000"> </span><span style="color: #808080"><summary></span><span style="color: #008000">
    </span><span style="color: #808080">///</span><span style="color: #008000"> PromoteUserNameBehavior implements IEndpointBehavior and adds a message inspector to the dispatch behavior. Doesn't use any binding parameters, doesn't validate any configuration etc and can't be used in a client (only in a service).
    </span><span style="color: #808080">///</span><span style="color: #008000"> </span><span style="color: #808080"></summary></span><span style="color: #808080">
    

    publicclass PromoteUserNameBehavior : IEndpointBehavior { #region IEndpointBehavior Members
    </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            </span><span style="color: #0000ff">return</span><span style="color: #000000">;
        }
    
        </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            </span><span style="color: #0000ff">throw</span><span style="color: #000000"> </span><span style="color: #0000ff">new</span><span style="color: #000000"> Exception(</span><span style="color: #000000">"</span><span style="color: #000000">The method or operation is not implemented.</span><span style="color: #000000">"</span><span style="color: #000000">);
        }
    
        </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(</span><span style="color: #0000ff">new</span><span style="color: #000000"> PromoteUserNameMessageInspector());
        }
    
        </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">void</span><span style="color: #000000"> Validate(ServiceEndpoint endpoint)
        {
            </span><span style="color: #0000ff">return</span><span style="color: #000000">;
        }
    
        </span><span style="color: #0000ff">#endregion</span><span style="color: #000000">
    }
    
    </span><span style="color: #808080">///</span><span style="color: #008000"> </span><span style="color: #808080"><summary></span><span style="color: #008000">
    </span><span style="color: #808080">///</span><span style="color: #008000"> Defines the behavior.
    </span><span style="color: #808080">///</span><span style="color: #008000"> </span><span style="color: #808080"></summary></span><span style="color: #808080">
    

    publicclass PromoteUserNameBehaviorElement : BehaviorExtensionElement { protectedoverrideobject CreateBehavior() { returnnew PromoteUserNameBehavior(); }
    </span><span style="color: #0000ff">public</span><span style="color: #000000"> </span><span style="color: #0000ff">override</span><span style="color: #000000"> Type BehaviorType
        {
            </span><span style="color: #0000ff">get</span><span style="color: #000000"> { </span><span style="color: #0000ff">return</span><span style="color: #000000"> </span><span style="color: #0000ff">typeof</span><span style="color: #000000">(PromoteUserNameBehavior); }
        }
    }
    

    }

Finally we have to sign the assembly using a strong key and add it to the GAC.

Configure the machine.config

As we need BizTalk and the WCF adapter to pick up the need behavior and make it possible to configure our receive port we need to to add the behavior element to the machine.config.aspx). The easiest way of doing this is to use the new WCF Service Configuration Editor tool and point to the machine.config file.

PromoteUserNameBehavior GAC

After the dll been added and the machine.config file has been saved the the line below should have been added to the element (that is if you use the same strong name key as in the sample project I've linked here).

<div><span style="color: #0000ff"><</span><span style="color: #800000">add </span><span style="color: #ff0000">name</span><span style="color: #0000ff">="addCustomWCFProperties"</span><span style="color: #ff0000"> type</span><span style="color: #0000ff">="CustomWCFProperties.Behavior.PromoteUserNameBehaviorElement, AddCustomWCFPropertiesBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=705e34637fdffc54"</span><span style="color: #ff0000"> </span><span style="color: #0000ff">/></span></div>

Create the BizTalk Receive Port and Receive Location

Next thing to do is to start the BizTalk WCF Service Publishing Wizard. Choose to publish a service endpoint and make sure you enable metadata and create a receive location. In this example we'll next choose to "Publish schemas as WCF service" and then define our service by naming service operations and so on.

When you then browse to the URL you choose to publish your service to you'll see the nice example of how to instance the service you just defined.

WSDL code example

If we then send a request message to service (you'll find a client as part of the attached solution here) and inspect the message and its context properties in BizTalk we'll see that the username of the calling client is nowhere to be found.

Message No Username

Configure a WCF-Custom binding and adding a Endpoint Behavior

To add the username to the message context we'll need to add our newly created behavior to our service. We'll do this by switch the service over to use a WCF-Custom binding to enable configuration. We then need to add the URL in the address field, define the binding type to a wsHttpBinding and to add our addCustomeWCFProperties behavior to the list of endpoint behaviors.

Add Endpoint behavior

>> [![note](../assets/2008/04/windowslivewriterwritingbiztalkcontextpropertiestoamessag-72f4note-thumb.gif)](../assets/2008/04/windowslivewriterwritingbiztalkcontextpropertiestoamessag-72f4note-2.gif) NOTE: there is a limitation in the BizTalk WCF implementation in that you can't create the WCF-Custom receive location that uses a HTTP in-process based binding (like the wsHttpBinding used in a WCF-Custom endpoint is) first and then use the WCF Publishing Wizard to only publish a metadata endpoint. >>>> [Richard Seroter writes about it here](http://www.topxml.com/code/cod-72_10213_biztalk-and-wcf-part-v-publishing-operations-patterns.aspx) and I found the same thing to be true. >>>> _"This error doesn’t have to do with mixing MEX endpoints and “regular” endpoints in the same IIS web site, but rather, creating MEX endpoints for in-process HTTP bindings seems to trigger this. **Note that an IIS-hosted MEX endpoint CAN be created for IIS-hosted HTTP endpoints, but not for in-process hosted HTTP endpoints."**_ >>>> If you however choose a different binding that Http or (as in this case) publishes the metadata first and then switches over to a custom binding you're ok. >>

If we then post another message to the service and inspect the message we'll see that the behavior actually added a header and that it's part of our BizTalk context properties. The adapter is also smart enough to know that this header isn't part of the original headers and therefore stores in it's own field within the context properties (you'll find as part of the InboundHeaders block as well).

Message Username

One problem remains - the actual value of the user is nested inside a XML node and the property isn't promoted.

Extract and promote the value

To extract and promote the value we use an old fashion pipeline component using the following code in the execute method (the complete project is part of the downloadable sample project).

<div><span style="color: #000000">        </span><span style="color: #0000ff">public</span><span style="color: #000000"> IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
        {
            StringReader reader </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">new</span><span style="color: #000000"> StringReader(inmsg.Context.Read(</span><span style="color: #000000">"</span><span style="color: #000000">WindowsUserName</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">"</span><span style="color: #000000">http://CustomWCFProperties.Schema</span><span style="color: #000000">"</span><span style="color: #000000">).ToString());

            </span><span style="color: #0000ff">if</span><span style="color: #000000"> (reader </span><span style="color: #000000">!=</span><span style="color: #000000"> </span><span style="color: #0000ff">null</span><span style="color: #000000">)
            {
                XPathDocument document </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #0000ff">new</span><span style="color: #000000"> XPathDocument(reader);
                XPathNavigator navigator </span><span style="color: #000000">=</span><span style="color: #000000"> document.CreateNavigator();
                </span><span style="color: #0000ff">string</span><span style="color: #000000"> value </span><span style="color: #000000">=</span><span style="color: #000000"> navigator.SelectSingleNode(</span><span style="color: #000000">"</span><span style="color: #000000">/</span><span style="color: #000000">"</span><span style="color: #000000">).Value;
                inmsg.Context.Promote(</span><span style="color: #000000">"</span><span style="color: #000000">WindowsUserName</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">"</span><span style="color: #000000">http://CustomWCFProperties.Schema</span><span style="color: #000000">"</span><span style="color: #000000">, value);
            }

            </span><span style="color: #0000ff">return</span><span style="color: #000000"> inmsg;
        }</span></div>

All the component does is reading the XML node the value exists inside and then it reads the actual value. Finally it writes the value back and promotes it. To be able to promote the value we also have to have a Property Schema deployed with a corresponding property name and namespace (WindowsUser and http://CustomeWCFProperties.Schema in this case).

The end results looks something like this.

Message Promoted Username

The username is extracted and promoted and available for example for tracking or to for example use in a routing scenario.

This technique could of course be used for all kinds of scenarios where you like to add information to the context properties and could potentially replace a lot of the classic scenarios for custom pipelines.

All kind of comments are of course more than welcome!

Download the sample solution here.

Speaking at Developer Summit on Masterdata Management using BizTalk 2006

$
0
0

I recently spoke at the leading developer conference here in Sweden called Developer Summit. The talk was called Masterdata Management using BizTalk 2006. The slides can be found here.

I can really recommend Developer Summit as a conference. Everything is super well organized and having the opportunity to listen to celebrities like David Chappell, Jim Webber, Dan North and Christian Weyerin Sweden is really great!

This year I also liked the mix of presentation as some where more general presentation as for example Benjamin Ling who's the director of platform at Facebook and who gave an insight to how the platform is managed and developed. I also really enjoyed (besides the obvious ones as for example Christian Weyer's WCF talk) Frans Hanel's talk on the history and architecture behind a major price comparison site called prisjakt.nu - very interesting and a great technical mix in otherwise Microsoft focused conference.

Using BAM for latency tracking in a BizTalk request response scenario

$
0
0

This post will try and explain how BAM tracking can be used in SOAP based request response scenario in BizTalk 2006. It important to notice that some of the issues discussed in the post are specific to the SOAP adapter and are non-issues if the scenario would for example use the the WCF adapter or similar.

Describing the scenario

In this case we have a SOAP receive port that receives a request and returns a response. The request is routed to a orchestration that calls three different send ports. These ports then sends new requests to back-end systems and returns responses (communication with back-ends systems are also SOAP based). The three responses are used to build up the final response that is then returned to original receive port as a final response.

Our goal is to track the duration between the request and response on each of the ports. The idea is also to find a solution and tracking model that doesn’t have to change if we add or remove ports or add similar processes to track.

scenario

Defining and deploying the tracking model

We’ll start by defining our tracking model in Excel. Our activity contains of the following items:

  • InterchangeId (data item)
    As we won’t correlate all the tracking point into one single row (that would break the goal of having one model for all processes, the model would then have to be specific for one process and it’s specific ports) the interchange id will then tell us what different rows belong together and that describes one process.

  • ReceivePortName (data item)
    The name of the receive port.

  • Request (milestone item)
    The time the request was either sent or received (depending on if we track a port that received/sent the request using a receive port or send port).

  • Response (milestone item)
    The time the response was either sent or received (depending on if we track a port that received/sent it's response on a receive port or send port).

  • SendPortName (data item)
    The name of the send port.

After we described the model it’s time to export it to an XML representation and then to use the BM tool to deploy it and generate the BAM database infrastructure. You'll find some nice info on this here.

Using the Tracking Profile Editor to bind the model

Next step is to bind the model to the implementation using the Tracking Profile Editor. The figure below shows the different properties that were used. Notice that none of the items was bound to the actual orchestration context. All properties are general properties that we track on the ports.This is important as that gives us the possibility to just add and remove ports to change the tracking.

tracking profile using continuation


The next figure shows how the tracking of the request milestone event actually happens on either the RP1 port or on any of the three different send ports! If we developed a new process using other ports we could just add it here, no new model required.

tracking profile configure ports 2

What about the continuation then?

Our final problem is that unless we somehow correlate our request tracking point with our receive tracking point the receive we’ll end up with each tracking point spread over several different rows. In the example below I've marked the request for the RP01 port and the response event on the same port.

bam portal split results

The reason for this is of course that BAM doesn’t have a context for the two tracking points and doesn't know that actually belongs together. This differs from tracking in a orchestration were we always are in a context (the context of the orchestration), it’s then easy for BAM to understand that we like to view all the tracking point as one row – when tracking on ports it’s different. Continuation helps us tell BAM that we like have a context and correlate these two points.

tracking profile using continuation 2

In our case ServiceID is the prefect candidate for correlating the two points. A request and a response will have the same service id. In an other situation we could just as well have used a value from inside the message (say for example an invoice id).

The result is one single row for the request response for each port. So in our case a complete process (a complete interchange) is shown on four rows (one row for each of the ports). In the example below the first rows shows us the complete duration (and the other tracking data) between the request response to the client. The other rows show the duration for the send ports communication with the back-ends systems.

bam portal complete results

This model might not be optimal in an other scenario where your process are more fixed and you can then create a tracking model that is more specific to you actual process. But this solution meets our design goal as we’re now able to just add and remove port using the tracking profiler to track new port in completely new processes without having to go back and change the tracking model.

>> [![note](../assets/2008/04/windowslivewriterusingbamforlatencytrackinginabiztalkrequ-9c0bnote-thumb.gif)](../assets/2008/04/windowslivewriterusingbamforlatencytrackinginabiztalkrequ-9c0bnote-2.gif) NOTE: When configuring BAM to track a port the _[MessageType](http://msdn2.microsoft.com/en-us/library/aa561650.aspx)_ is actually promoted. This causes some problems in combination with the SOAP based ports that have been published using the Web Services Publishing Wizard. Saravana writes about this [here](http://www.digitaldeposit.net/blog/2007/08/soap-adapter-and-biztalk-web-publishing.html) and all his articles on this subject is a must read when working with SOAP ports. The problem however comes down to that the Web Services Publishing Wizard generates code that puts the wrong _DocumentSpecName _in the message context and that causes the _XmlDisassembler_ to fail (it tricks the _XmlDisassembler_ to look for a _MessageType_ that doesn't exists). >>>> This usually isn’t a problem (unless you like to use a map on a port) but as BAM will force the port to promote the _MessageType_ based on the _DocumentSpecName _we’ll have to fix this. Saravana has two solutions to the problem and I find the one that replaces the _DocumentSpecName_ with a null value and lets the _XmlDisassembler_ find the _MessageType_ to work well. >>

Speaking at KNUG - Karlstad .NET User Group

$
0
0

Yesterday I presented the MasterData Management using BizTalk 2006 R2 talk (I'll soon have a post out with the presentation in English) I recently held at Developer Summit at the local .NET user group in Karlstad (KNUG).

Janolof on how to be coolKNUG is a new .NET user group that I actually helped start a couple of months ago. This meeting was the second meeting for the group. The meeting was attended by about 20 persons and we had two presentations on the agenda. Besides my own Thomas Heder showed the group some LINQ and how he and his colleagues uses LINQPad to develop and test there queries.

We also discussed future subjects, possible speakers and moving information on the group over to a Community Server driven site.

Does anyone have any experience on Community Server and how the feature set matches those need for running a user group (managing users, blogs, email lists, calendar etc)?

Does BizTalk have man-boobs?

$
0
0

I've just finished watching this webcast from QCon 2008 with Martin Fowler and Jim Webber. It's basically their view on how integration middleware is used today and how we plan and implement our SOA and ESB project.

Their main point is that we use much to bloated middleware (BizTalk is mentioned as an example here) and that we should have a more agile approach to implement SOA and ESBs. They've used all the agile ideas (testing, isolated testable functionality, deliver small and often, continuous builds etc, etc) and applied them to integration - fair enough. I totally agree that trying to convert your complete enterprise architecture into a SOA architecture is a guaranteed failure. This is also something we heard for a while now from others as well.

I do also agree that BizTalk is a huge platform and that it isn't perfect in all aspects. IMHO it does however give us some important advantages compared to a custom coded message bus and services. I'll try and list a few of them below.

  1. Fixed architecture
    We don't have invent the wheel every time. BizTalk is a product with an architecture that one have to learn and use. There are times when this is a pain (did I hear low latency and BizTalk persistence points?) but it's also a huge kick start to all projects once you learnt it. Once you figured out how you use the products you'll actually have something up and running in no time.

Isn't an early delivery that we can test something good? I'm sure I can deliver a BizTalk based integration faster that some can using custom code when starting from scratch.

  1. Drag-and-drop
    There is a learning curve to BizTalk and all it's tools but once one gotten over this one can move really fast, even without a deep understanding of .NET and software development (there are of course both pros and cons to this). I've seen projects with 50+ integration processes (to me that's a big, complex project) where we actually used people fresh out of school, spent two weeks to teach them basic BizTalk and had them deliver critical parts of the projects. I'd like to see that happen custom coded ESB project with thousands lines of code ...

You probably get a nice design and implementation if you can hire 10 top developers and a couple of architects, but that isn't always possible.

  1. Tools
    Does a custom code, lean approach, really scale in this scenario? Do you take the time to pause and build that management and configuration tool that you don't get with a custom code project? I don't say that we got the perfect view and control of our processes and messages in BizTalk but at least we got some control. At least I got the BizTalk Administration Console to let me see how my different application are doing, what messages and process etc that got suspended. At least I got the BAM framework where I can configure a tracking and monitoring in no time (usually ...) etc, etc.

  2. It works
    Say your implementing a process that receives purchase orders and that these orders might contain orders for a couple of millions dollars. Do you want to be developer that tells you boss that you think you might have lost a message due to a exception in your custom code? Of course you have 90% test coverage and continuous integration but you never tested for this exception case ... I don't want to be that developer/architect.

I don't say don't test. I'm very pro testing and I really feel that agile is the right approach. I'm just saying I need something tested and safe to build this super critical solutions on. Something that I know works and that I can be really productive on and start solving business cases from minute one.

What do you think? Does BizTalk have man-bobs and is that only a bad thing? And does Martin Fowler really have leather pants on?


Removing XML namespaces - revisit

$
0
0

I have a old post on removing XML namespace from outgoing messages using XSLT in a map on the send port. Removing XML namespace is usually a late requirement that shows up during integration tests with for example legacy systems that has problems reading XML and only finds XML namespaces messy and confusing and wants it removed.

The post recently got commented by Jeff Lynch (one of the codebetter.com bloggers) asking me why I just didn't create a schema without any XML namespace in it to represent the outgoing schema (see figure below) and then map to that in the send port.

Removing XML namespaces - revisit

Say for example that we have incoming messages like the one below with namespaces.

<div><span style="color: #0000FF; "><</span><span style="color: #800000; ">ns0:BlahRoot </span><span style="color: #FF0000; ">xmlns:ns0</span><span style="color: #0000FF; ">="http://Sample.BlahIncomingSchema"</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">
  </span><span style="color: #0000FF; "><</span><span style="color: #800000; ">BlahNode</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">Test Value</span><span style="color: #0000FF; "></</span><span style="color: #800000; ">BlahNode</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">
</span><span style="color: #0000FF; "></</span><span style="color: #800000; ">ns0:BlahRoot</span><span style="color: #0000FF; ">></span></div>

We've then defined a schema without namespace and map to that and get the following result.

<div><span style="color: #0000FF; "><</span><span style="color: #800000; ">BlahRoot</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">
  </span><span style="color: #0000FF; "><</span><span style="color: #800000; ">BlahNode</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">Test Value</span><span style="color: #0000FF; "></</span><span style="color: #800000; ">BlahNode</span><span style="color: #0000FF; ">></span><span style="color: #000000; ">
</span><span style="color: #0000FF; "></</span><span style="color: #800000; ">BlahRoot</span><span style="color: #0000FF; ">></span></div>

This method is of course much cleaner then any previous and it's also more conceptually correct as the schema actually represents the contact between BizTalk and the receiving system (the contract is a message without namespace in it, not one with that we then remove).

The only problem with this kind of approach is that as BizTalk recognized the message type using a combination between root node and XML namespace we can't have another schema with the BlahRoot root node without a defined XML namespace. Even if those two schemas would look totally different in structure and be two different message types BizTalk would be able to see the difference (to BizTalk they both be #BlahRoot message types).

Thanks Jeff for pointing this out to me.

Looking forward to stackoverflow.com

$
0
0

stackoverflow-logo-250I'm really looking forward to the release of stackoverflow.com - have you heard about it? If not it's a collaboration between Joel Spolsky and Jeff Atwood. Joel and Jeff are of course the two blogger behind the popular Joel on Software and Coding Horror blogs.

Joel is also one of the founders of the FogCreek Software company. FogCreek has a couple of different products but the most known is probably FogBugz which is a really cool project management/bug tracking/wiki/support tool for software development and management. At first it might not look like a very impressing tool but have a look at this presentation by Joel and I think you'll start thinking different (I know we did and we're now using it for both planing and managing big integrations projects).

Anyway, if you missed the story behind stackoverflow have a look here and don't miss the podcasts that Joel and Jeff record, some of them are really cool. I know I've learnt a lot by just listening in to their conversations.

We not have quite a few online BizTalk communities such as the Microsoft forums, Google Groups, BizTalk Gurus, facebook (search for BizTalk related groups) and at LinkedIn (a couple of open BizTalk related groups) - is there room for another one at stackoverflow? Do we need one?

Running MSBuild scripts from Visual Studio

$
0
0

MSBuild2It seems like there more build script one writes, the more often one wants to run them and it's always a bit annoying (and time consuming) having to leave Visual Studio and start MSBuild from the command line. Brennan Stehling has a cool solution to that problem here were he sets up MSBuild as an external tool and runs it.

One problem for us was the we had our solution files in one place on the file system and our build files in a totally different place. The solution was to add the build file for the current solution as a Solution Folder.aspx) (as shown in the figure below) and then set MSBuild to use $(ItemDir) as its Initial Directory. That will kick of MSBuild from the directory that the current selected Solution Folder points to and in our case that's were the XXX.Build.Article.proj file exists.

MSBuild

Efficient grouping and debatching of big files using BizTalk 2006

$
0
0

I've seen people struggle both on the forums and while doing consulting when in it comes to finding an good way of grouping and transforming content in file before debatching it. Say for example we have a text file like the example below.

0001;Test row, id 0001, category 10;10 
0002;Test row, id 0002, category 10;10
0003;Test row, id 0003, category 10;10
0004;Test row, id 0004, category 20;20
0005;Test row, id 0005, category 20;20
0006;Test row, id 0006, category 20;20
0007;Test row, id 0007, category 20;20
0008;Test row, id 0008, category 10;10
0009;Test row, id 0009, category 10;10
0010;Test row, id 0010, category 30;30

Notice how the the ten rows belong to three different categories (10,20 and 30). These kind of export are in my experience quite common batch export from legacy systems and they usually aren't ten rows (in my last project the sizes ranged from 5 MB to 25 MB) ...

The problem

The problem is that the receiving system expects the data to be in separate groups,grouped by the categories the rows belong to. The expected message might look something like the below for category 10 (notice how all rows within the group are from category 10)

<ns1:Group numberOfRows="5" xmlns:ns1="http://Blah/Group">
  <Row>
    <Id>0001</Id>
    <Text>Test row, id 0001, category 10</Text>
    <Category>10</Category>
  </Row>
  <Row>
    <Id>0002</Id>
    <Text>Test row, id 0002, category 10</Text>
    <Category>10</Category>
  </Row>
  <Row>
    <Id>0003</Id>
    <Text>Test row, id 0003, category 10</Text>
    <Category>10</Category>
  </Row>
  <Row>
    <Id>0008</Id>
    <Text>Test row, id 0008, category 10</Text>
    <Category>10</Category>
  </Row>
  <Row>
    <Id>0009</Id>
    <Text>Test row, id 0009, category 10</Text>
    <Category>10</Category>
  </Row>
</ns1:Group>

The problem is now that we need to find a efficient way of first grouping the incoming flat file based message and then to debatch it using those groups. Our ultimate goal is to have separate messages that groups all rows that belongs to the same category and then send these messages to the receiving system. How would you solve this?

I've seen loads of different solution involving orchestrations, databases etc, but the main problem they all had in common is that they've loaded up to much of the message in memory and finally hit an OutOfMemoryException.

The solution

The way to solve this is to use pure messaging as one of the new features in BizTalk 2006 is the new large messages transformation engine.

>> **Large message transformation.** In previous versions of BizTalk Server, mapping of documents always occurred in-memory. While in-memory mapping provides the best performance, it can quickly consume resources when large documents are mapped. In BizTalk Server 2006, large messages will be mapped by the new large message transformation engine, which buffers message data to the file system, keeping the memory consumption flat. >>

So the idea is the to read the incoming flat file, use the Flat File Disassembler to transform the message to it's XML representation (step 1,2 and in the figure below) and the to use XSLT to transform in to groups (step 4 and 5). We will then use the XML Disassembler to split those groups into separate messages containing all the rows within a category (step 6 and 7).

GroupingFlow2

Step 1, 2 and 3 are straight forward and pure configuration. Step 4 and 5 will require some custom XSLT and I'll describe that in more detail in the section below. Step 6 and 7 will be discussed in the last section of the post.

Grouping

Let's start by looking at a way to group the message. I will use some custom XSLT and a technique called the Muenchian method. A segment from the XML representation of the flat file message could look something like this.

<Rows xmlns="http://Blah/Incoming_FF">
    <Row xmlns="">
        <ID>0001</ID>
        <Text>Test row, id 0001, category 10</Text>
        <Category>10</Category>
    </Row>
    <Row xmlns="">
        <ID>0002</ID>
        <Text>Test row, id 0002, category 10</Text>
        <Category>10</Category>
    </Row>
...
[message cut for readability]

The XSLT will use could look something like the below. It's kind of straight forward and I've tried commenting the important parts of in the actual script. Basically it will use keys to fins the unique categories and then (again using keys) selecting those rows within the category to loop and write to a group.

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns1="http://GroupAndDebatch.Schemas.Incoming_FF"
                xmlns:ns2="http://GroupAndDebatch.Schemas.Grouped">
    <!--Defining the key we're gonna use-->
    <xsl:key name="rows-by-category" match="Row" use="Category" />

    <xsl:template match="/ns1:Rows">
        <ns2:Groups>

        <!--Looping the unique categories to get a group for-->
        <xsl:for-each select="Row[count(. | key('rows-by-category', Category)[1]) = 1]">

            <!--Creating a new group and set the numberOfRows-->
            <Group numberOfRows="{count(key('rows-by-category', Category))}">

            <!--Loop all the rows within the specific category we're on-->
            <xsl:for-each select="key('rows-by-category', Category)">
                <Row>
                    <ID>
                        <xsl:value-of select="ID"/>
                    </ID>
                    <Text>
                        <xsl:value-of select="Text"/>
                    </Text>
                    <Category>
                        <xsl:value-of select="Category"/>
                    </Category>
                </Row>
            </xsl:for-each>
            </Group>
        </xsl:for-each>
        </ns2:Groups>
    </xsl:template>

</xsl:stylesheet>
>> [![note](../assets/2008/07/windowslivewriterefficientgroupingandsplittingofbigfiles-8295note-thumb.gif)](../assets/2008/07/windowslivewriterefficientgroupingandsplittingofbigfiles-8295note-2.gif)You have found all the [XSLT and XML related features](http://msdn.microsoft.com/en-us/library/aa302298.aspx) in Visual Studio - right? >>

Ok, so the above XSLT will give us a XML structure that looks some like this.

<?xml version="1.0" encoding="utf-8"?>
<ns2:Groups xmlns:ns2="http://Blah/Groups" xmlns:ns1="http://Blah/Group">
    <ns1:Group numberOfRows="5">
        <Row>
            <ID>0001</ID>
            <Text>Test row, id 0001, category 10</Text>
            <Category>10</Category>
        </Row>
        <Row>
            <ID>0002</ID>
            <Text>Test row, id 0002, category 10</Text>
            <Category>10</Category>
        </Row>
        <Row>
            <ID>0003</ID>
            <Text>Test row, id 0003, category 10</Text>
            <Category>10</Category>
        </Row>
        <Row>
            <ID>0008</ID>
            <Text>Test row, id 0008, category 10</Text>
            <Category>10</Category>
        </Row>
        <Row>
            <ID>0009</ID>
            <Text>Test row, id 0009, category 10</Text>
            <Category>10</Category>
        </Row>
    </ns1:Group>
    <ns1:Group numberOfRows="4">
        <Row>
            <ID>0004</ID>
            <Text>Test row, id 0004, category 20</Text>
            <Category>20</Category>
        </Row>
...
[message cut for readability]

Finally! This we can debatch!

Debatching

Debatch the Groups message above is also rather straight forward and I won't spend much time on in this post. The best way to learn more about it is to have a look ate the EnvelopeProcessing sample in the BizTalk SDK.

And the end result of the debatching are single messages within a unique category, just as the receiving system expects! Problem solved.

Issue #1 - slow transformations

The first time I've put a solution like this in test and started testing with some real sized messages (> 1 MB) I really panicked, the mapping took forever. And I really mean forever, I sat there waiting for 2-3 hours (!) for a single file getting transformed. When I had tested the same XML based file in Visual Studio the transformation took about 10 seconds so I knew that wasn't it. With some digging here I found the TransformThreshold parameter.

TransformThreshold decides how big a message can be in memory before BizTalk start buffering it to disk. The default value is 1 MB and one really has to be careful when changing this. Make sure you thought hard about your solution and situation before changing the value - how much traffic do you receive and how much of that can you afford reading in to memory?

In my case I received a couple of big files spread out over a night so setting parameter with a large amount wasn't really a problem and that really solved the problem. The mapping finished in below 10 minutes as I now allow a much bigger message to be read into memory and executed in memory before switching over to the large message transformation engine and start buffering to disk (which is always much slower).

Problem #2 - forced to temp storage

Looking at the model of the data flow again you probably see that I'm using the XML Disassembler to split the grouped files (step 5 to step 6).

GroupingFlow3

The only way I've found this to work is actually to write the Grouped XML message to file and the to read that file in to BizTalk again and in that receive pipeline debatch the message. Not the most elegant solution, but there really isn't a another out-of-the-box way of debatching messages (the XML Assembler can't do it) and I don't want to use an orchestration to execute the a pipeline as I want to keep the solution pure messaging for simplicity and performance reasons.

Finishing up

Have you solved similar cases differently? I'd be very interested in your experience! I also have a sample solution of this - just send me an email and make sure you'll get it.

Update

Also don’t miss this issue (pdf) of BizTalk Hotrod magazine. There is an article on “Muenchian Grouping and Sorting using Xslt” describing exactly the problem discussed above.

How the extend a custom Xslt in BizTalk using EXSLT and the Mvp.Xml project

$
0
0

Lately I've been using custom Xslt more and more instead of the BizTalk mapping tool. I still use the mapping tool in easy scenarios when I just need to do some straight mapping or maybe even when I need to concatenate some fields, but as soon as I need to to some looping, grouping, calculations etc I've made a promise to myself to use custom Xslt!

I find custom Xslt so much easier in more complex scenarios and once one get past the template matching and understands how and when to use recursion (No you can't reassign a variable in Xslt and you're not supposed to!) I find it to be a dream compared to the mapping tool. I also find the code so much easier to maintain compared to the result from the mapping tool. I mean someone would have to pay me good money to even start figuring out what this map is doing. And the scary thing is that if you worked with BizTalk for a while you probably know that maps like this isn't that rare! I've even seen worse!

Don't get me wrong, Xslt definitely has some majorlimitations.

Some of the acute limitations of XSLT 1.0 I can think of off the top of my head are: >> * The lack of real string comparison > * No support for dates > * No simple mechanism for grouping > * No querying into RTF's >

And it doesn't take long before one runs up against one of these and suddenly you wish you were back in mapping tool were we just could add scripting functoid and some code or a external assembly. But then you remember ... (Sorry, I know it's painful just to watch it).

BadMap_thumb

There has to be a better way of doing this and combining the best out of the two worlds!

I started looking into to how BizTalk actually solves combining Xslt and the possibility to use external assemblies. After a couple of searches I found Yossi's nice article that explained it to me (from 2005! I'm behind on this one!) and it even turns out that there an example in the BizTalk SDK.

Ok, so now I had what I need. I started a new class library project and began writing some date parsing methods, some padding methods and so on.

It somehow however felt wrong from the start and I got this grinding feeling that I must be reinventing the wheel (I mean these are well know limitations of Xslt and must have been solved before). Even worse I also felt that I was creating a stupid single point of failure as I started using the component from all different maps in my projects and I have actually seen how much pain a bug in similar shared dll:s could cause. Basically a small bug in the component could halt all the process using the library! Finally I realized that this kind of library would be under constant development as we ran into more and more areas of limitations in the our Xslt:s and that would just increase the risk of errors and mistakes.

After some further investigation I found EXSLT which looked like a solution to my problems! A stable, tested library of Xslt extensions that we could take dependency on as it's unlikely to have any bugs and that should include the functionality we're missing in standard Xslt!

How I used EXSLT in BizTalk

These days it's the Xml Mvp crowd over at the Mvp.Xml project who develops and maintains the .NET implementation of EXSLT. So I downloaded the latest binaries (version 2.3). Put the the Mvp.Xml.dll in the GAC. Wrote a short custom extension Xml snippet that looked like this (using what I've learnt from Yossi's article).

<?xml version="1.0" encoding="utf-8"?>
<ExtensionObjects>
    <ExtensionObject
     Namespace="http://exslt.org/dates-and-times"
     AssemblyName="Mvp.Xml, 
     Version=2.3.0.0, Culture=neutral, 
     PublicKeyToken=6ead800d778c9b9f"
     ClassName="Mvp.Xml.Exslt.ExsltDatesAndTimes"/>
</ExtensionObjects>

All you define is the Xml namespace you like to use in your Xslt to reference the dll, the full assembly name and finally the name of the class in Mvp.Xml.Exslt you want to use (make sure you also download the source to Xml.Mvp, it helps when looking up in what classes and namespaces different methods are placed).

That means you need one ExtensionObjects block for each class you want you use which really isn't a problem as the methods are nicely structured based on there functionality.

Then we can use this in a Xslt like this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:S1="http://ExtendedMapping.Schema1"
                xmlns:S2="http://ExtendedMapping.Schema2"
                xmlns:exslt="http://exslt.org/dates-and-times"
                version="1.0"> 

    <xsl:template match="/">
        <S2:Root>
            <Field>
                <xsl:value-of select="exslt:dateTime()"/>
            </Field>
        </S2:Root>
    </xsl:template>
</xsl:stylesheet>

Which gives us the below output. Notice the current time and date! Cool!

<S2:Root xmlns:S1="http://ExtendedMapping.Schema1" xmlns:S2="http://ExtendedMapping.Schema2" xmlns:exslt="http://exslt.org/dates-and-times">
  <Field>2008-09-05T20:45:13+02:00</Field> 
</S2:Root>

All you then have to do in you map is to reference the Xslt and the extension Xml.

Custom Extension In Map

Just as final teaser I'll paste a few methods from the EXSLT documentation

Some string methods:

  • str:align()

  • str:concat()

  • str:decode-uri()

  • str:encode-uri()

  • str:padding()

  • str:replace()

  • str:split()

  • str:tokenize()

Some date and time methods:

  • date:add()

  • date:add-duration()

  • date:date()

  • date:date-time()

  • date:day-abbreviation()

  • date:day-in-month()

  • date:day-in-week()

  • date:day-in-year()

  • date:day-name()

  • date:day-of-week-in-month()

  • date:difference()

  • date:duration()

  • date:format-date()

  • date:hour-in-day()

  • date:leap-year()

  • date:minute-in-hour()

  • date:month-abbreviation()

  • date:month-in-year()

  • date:month-name()

  • date:parse-date()

  • date:second-in-minute()

  • date:seconds()

  • date:sum()

  • date:time()

  • date:week-in-month()

  • date:week-in-year()

  • date:year()

As if this was enough (!) the Mvp Xml project added a couple of there own methods! What about string lowercase and string uppercase - all in Xslt! And about 30 new date-time related methods extra to the standard ones already in EXSLT!

Check out the full documentation here!

Let me know how it works out for you.

Using BizUnitExtensions to poke around in some XML

$
0
0

I'll start by saying that I really (like in "really, really!") like BizUnit! BizUnit in combination with MSBuild, NUnit and CruiseControl.NET has really changed the way work and how I feel about work in general and BizTalk development in particular.

If you haven't started looking into what for example MSBuild can do you for you and your BizTalk build process you're missing out on something great. The time spent on setting up a automatic build process is time well spent - take my word for it!

But build processes isn't was this post is supposed to be about. This post is about one of the few limitations of BizUnit and the possibilities to work around one of those in particular.

BizUnit is a test framework that is intended to test Biztalk solutions. BizUnit was created by Kevin.B.Smith and can be found on [this CodePlex space](http://www.codeplex.com/bizunit) . BizUnit has quite a significant number of steps that have nothing to do with Biztalk per se and can be used for any integration project testing. >>
[![note](../assets/2008/10/windowslivewriterusingbizunitextensionstopokesomexml-d286note-thumb.gif)](../assets/2008/10/windowslivewriterusingbizunitextensionstopokesomexml-d286note-2.gif)If you have used BizUnit before and need an introduction before reading further, start [here](http://www.codeproject.com/KB/biztalk/BizUnit2006.aspx), [here](http://www.codeplex.com/bizunit) or [here](http://biztalkia.blogspot.com/2007/03/getting-started-with-nunit-and-bizunit.html) - they're all excellent articles. >>

As stated BizTalk has quite a significant number of steps but to my knowledge it's missing a step to change and update file from within the test script. This step and a couple of other are added in separate fork-project to BizUnit called BizUnitExtensions.

This project [_BizUnitExtension_] aims to provide some more test step libraries, tools and utilities to enhance the reach of BizUnit. Here you can find some enhancements/extensions to the steps in the base libraries , new steps, support applications, tutorials and other documentation to help you understand and use it....This project is currently owned and contributed to by Santosh Benjamin and Gar Mac Críostaand. Our colleagues have also contributed steps and suggestions. We welcome more participation and contributions. >>

Amongst other steps (some for Oracle DBs etc) BizUnitExtensions adds a XmlPokeStep!

**XmlPokeStep:** This step is modelled on the lines of the NAnt XmlPoke task The XmlPokeStep is used to update data in an XML file with values from the context This will enable the user to write tests which can use the output of one step to modify the input of another step. >>

A cool thing about BizUnitExtensions is that it really just extends BizUnit. You'll continue to run on the BizUnit dll:s when you use steps form BizUnit and just use the BizUnitExtensions code when you actually use some of steps from that library.

The example below shows how we first use an ordinary BizUnit task to validate and read a value from a file. We then use BizUnitExtension to gain some new powers and update the file with that value we just read.

<!–Ordinary BizUnit step to validate a file –>
<TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileValidateStep">
    <Timeout>5000</Timeout>
    <Directory>..\..\ReceiveRequest</Directory>
    <SearchPattern>*Request.xml</SearchPattern>
    <DeleteFile>false</DeleteFile>

    <ContextLoaderStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.XmlContextLoader">
        <XPath contextKey="messageID">/*[local-name()=’SystemRequest’]/ID</XPath>
    </ContextLoaderStep>

</TestStep>

<!–Use BizUnitExtensions to poke the value and change it –>
<TestStep assemblyPath="BizUnitExtensions.dll" typeName="BizUnit.Extensions.XmlPokeStep">
    <InputFileName>..\..\SystemResponse.xml</InputFileName>
    <XPathExpressions>
        <Expression>
            <XPath>/*[local-name()=’SystemResponse’]/ID</XPath>
            <NewValue takeFromCtx="messageID"></NewValue>
        </Expression>
    </XPathExpressions>
</TestStep>

This of course means that all you need to extend you current test steps and gain some cool new abilities is to add another assembly to you test project![image](../assets/2008/10/windowslivewriterusingbizunitextensionstopokesomexml-d286image-thumb-3.png)

Using BizUnitExtensions in a "real" scenario

An scenario when this can be useful is the following example were we need to test some message correlation.image

  1. A message request is received via a web service.

  2. The message is sent to a queue via an orchestration in BizTalk. To be able to correlate the response a message id is added to the message request sent to the back-end system.

  3. A message response is sent from the back-end system using a second queue. The response message contains the same message id as the incoming request contained.

  4. BizTalk correlates the message back to the web service using the message id.

So how can we now test this? The steps should be something like the below.

>> [![note](../assets/2008/10/windowslivewriterusingbizunitextensionstopokesomexml-d286note-thumb-1.gif)](../assets/2008/10/windowslivewriterusingbizunitextensionstopokesomexml-d286note-4.gif) Notice that we read and write to the file system in the example. Once deployed to test these send ports and receive location will be reconfigured to use the queuing adapter. But for testing the scenario the file system works just fine a simplifies things IMHO. >>
  1. Send a request message using BizUnit and the HttpRequestResponseStep. Make sure it runs concurrently with the other steps and then wait for a response (using the runConcurrently-attribute on the step).
  2. Configure the send port so the orchestration that added the generated message id writes the message to a folder. Use the FileValidateStep and a nested XmlContextLoader to read the message from the folder and write the message id the context.
  3. Use the context and the XmlPokeStep from BizUnitExtensions to update a response message template with the message id from the request message (this is of course needed so we can correlate the response message back to the right orchestration).
  4. Copy the update response message template using the FileCreateStep to the folder that is monitored by the the receive location used for reading responses.

    <!–Clean up!–>....\ReceiveRequest.....\SendResponse.

    <TestExecution>
        <!–Post a request message on the SOAP port. Run it Concurrently–>
        <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.HttpRequestResponseStep" runConcurrently="true">
            <SourcePath>..\..\WebRequest.xml</SourcePath>
            <DestinationUrl>http://localhost:8090/BizTalkWebService/WebService1.asmx?op=WebMethod1</DestinationUrl>
            <RequestTimeout>15000</RequestTimeout>
        </TestStep>
    
        <!–Read the system request message and read the generaed id to the context–>
        <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileValidateStep">
            <Timeout>5000</Timeout>
            <Directory>..\..\ReceiveRequest</Directory>
            <SearchPattern>*Request.xml</SearchPattern>
            <DeleteFile>false</DeleteFile>
            <ContextLoaderStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.XmlContextLoader">
                <XPath contextKey="messageID">/*[local-name()=’SystemRequest’]/ID</XPath>
            </ContextLoaderStep>
        </TestStep>
    
        <!–If we have the file in source control it might be read-only -> remove that attribute–>
        <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.ExecuteCommandStep">
            <ProcessName>attrib</ProcessName>
            <ProcessParams>SystemResponse.xml -r</ProcessParams>
            <WorkingDirectory>..\..\</WorkingDirectory>
        </TestStep>
    
        <!–Update our response template (using BizUnitExtensions) and add the message id that we read into the the context–>
        <TestStep assemblyPath="BizUnitExtensions.dll" typeName="BizUnit.Extensions.XmlPokeStep">
            <InputFileName>..\..\SystemResponse.xml</InputFileName>
            <XPathExpressions>
                <Expression>
                    <XPath>/*[local-name()=’SystemResponse’]/ID</XPath>
                    <NewValue takeFromCtx="messageID"></NewValue>
                </Expression>
            </XPathExpressions>
        </TestStep>
    
        <!–Wait a moment so we don’t copy the file until we’re done updating it–>
        <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.DelayStep">
            <Delay>1000</Delay>
        </TestStep>
    
        <!–Copy the file to the folder that monitored by the receive location for opicking up system responses–>
        <TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileCreateStep">
            <SourcePath>..\..\SystemResponse.xml</SourcePath>
            <CreationPath>..\..\SendResponse\SystemResponse.xml</CreationPath>
        </TestStep>
    </TestExecution>
    

This might look messy at first but I think it's really cool I also think it worth thinking about on how you should run this at during development otherwise? You would then have to build some small stub to return a response message with the right id ... I prefer this method!

BizUnitExtension makes me like BizUnit even more! Thanks to Kevin. B. Smith, Santosh Benjamin and Gar Mac Críostaand for spending so much time on this and sharing it with us mere mortals!

Update: Gar's blog can be found here.

Handle the 'bodyTypeAssemblyQualifiedName' SOAP Adapter bug in MSBuild as a RegEx ninja

$
0
0

This is a very specific problem but I'm sure some of you stumbled over it. When disassembling a XML message in a SOAP port BizTalk can't read the message type. This causes problems when for example trying to handle an envelope message and split it to smaller independent messages in the port. It's a known problem discussed here and here (you also find information about it in the BizTalk Developer's Troubleshooting Guide) and the solution is to make a small change in the generated web service class. Below is a small part of he generated class.

//[cut for clarity] ...
            Microsoft.BizTalk.WebServices.ServerProxy.ParamInfo[] outParamInfos = null;
            string bodyTypeAssemblyQualifiedName = "XXX.NO.XI.CustomerPayment.Schemas.r1.CustomerPayments_v01, XXX.NO.XI.CustomerPaym" +
                "ent.Schemas.r1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ac564f277cd4488" +
                "e";
            // BizTalk invocation
            this.Invoke("SaveCustomerPayment", invokeParams, inParamInfos, outParamInfos, 0, bodyTypeAssemblyQualifiedName, inHeaders, inoutHeaders, out inoutHeaderResponses, out outHeaderResponses, null, null, null, out unknownHeaderResponses, true, false);
        }
    }
}

Basically the problem is that the generated code puts the wrong DocumentSpecName property in the message context. I'll not dicusses the problem in detail here but Saravana Kumar does thorough dissection of the problem in his post on it.

The solution is to update the bodyTypeAssemblyQualifiedName to set a null value. That will cause the XmlDiassasemler to work as we're used to and expect.

>> If the value _null_ is passed instead of _bodyTypeAssemblyQualifiedName_, SOAP adapter won't add the _DocumentSpecName_ property to the context. Now, when we configure our auto-generated SOAP_ReceiveLocation_ to use _XmlReceive_ pipeline, the _XmlDisassembler_ component inside _XmlReceive_ will go through the process of automatic dynamic schema resolution mechanism, pick up the correct schema and promotes all the required properties (distinguished and promoted) defined in the schema and it also promotes the _MessageType_ property. >>>> **From:** [http://www.digitaldeposit.net/saravana/post/2007/08/17/SOAP-Adapter-and-BizTalk-Web-Publishing-Wizard-things-you-need-to-know.aspx](http://www.digitaldeposit.net/saravana/post/2007/08/17/SOAP-Adapter-and-BizTalk-Web-Publishing-Wizard-things-you-need-to-know.aspx) >>
//[cut for clarity] ...
            Microsoft.BizTalk.WebServices.ServerProxy.ParamInfo[] outParamInfos = null;
            string bodyTypeAssemblyQualifiedName = null;
            // BizTalk invocation
            this.Invoke("SaveCustomerPayment", invokeParams, inParamInfos, outParamInfos, 0, bodyTypeAssemblyQualifiedName, inHeaders, inoutHeaders, out inoutHeaderResponses, out outHeaderResponses, null, null, null, out unknownHeaderResponses, true, false);
        }
    }
}

But if you have an automated deployment process you probably use MSBuild to generate your Web Services. Then is soon becomes very annoying to remember to update the .cs-file again and again for every deployment. So how can we script that update?

First we need to find a regular expression to find the right values. With some help from StackOverflow (let's face it, there are some crazy regular expressions skills out there ...) I ended up on the following.

(?<=string\sbodyTypeAssemblyQualifiedName\s=\s)(?s:[^;]*)(?=;)

ninja5 If you're not a RegEx ninja the line above does something like this:

  1. After the string "string bodyTypeAssemblyQualifiedName = "

  2. turn on single line (treat "\r\n" as any other character) ( this is what "(?s: )" does)

  3. match every character that is not a semicolon

  4. until a single semicolon is reached.

Then I used a task from the SDC Task library (you probably already use this if you're using MSBuild and BizTalk). More specially we use the File.Replace

<Target Name="FixSOAPServiceCode">
    <File.Replace
            Path="$(WebSiteServicePath)CustomerPaymentService\App_Code\CustomerPaymentService.asmx.cs"
            Force="true"
            NewValue="null"
            RegularExpression="(?&lt;=string\sbodyTypeAssemblyQualifiedName\s=\s)(?s:[^;]*)(?=;)">
    </File.Replace>
</Target>

Now this task is part of the build script and called right after the tasks that generates the web service. This saves me a lot of manual work and potential errors!


Aggregated monitoring of BizTalk solutions using 'BizMon'

$
0
0
>> **Update 2010-09-30:** BizMon is now owned and developed by [Communicate Norway](http://www.communicate.no). They have renamed, and further developed the product, to IPM (Integration Monitoring Platform) – check it out [here](http://ipm.communicate.no/exciting-news). >>
>> _**Update 2009-08-11: **This project turned out to be far more complicated and bigger than I first expected (ever heard that before?). Due to that and the fact that we wanted to have a company behind that could offer full-time support and stability “BizMon” has been released as a commercial product that you can find [here](http://bizmontool.com/). _ >>>> _I love to get some [help from you](http://bizmontool.com/we-have-a-rtm-version)**** to test it and make it as good as possible. Even if it is commercial and cost money we have a free alternative for small environments and we work hard to keep the license price as low as possible._ >>

****

>> _**Update 2009-02-25:** In the original post I said I'd post more on the architecture and the code during February 09. I'm however current struggling getting the needed legal rights etc, etc to be able to talk further about the "BizMon"-solution. It was harder than I thought ... I'll get back to posing on the subject as soon as I have that sorted._ >>

Integration of enterprise processes often ends up being very business critical. If a integration fails delivering the messages it was supposed to it usually means the business will be affected in a very negative way (for example losing money or delivering bad service). That of course means that monitoring the status of the integrations soon becomes very important (if you're not into getting yelled at or potentially loosing your job).

Strangely enough **BizTalk Server 2006 R2 in my humble opinion doesn't come with the right tool to efficiently monitoring big enterprise integration solutions!**

What do I mean by monitoring?

image Before I get myself deeper into trouble I'd like to define what I mean by monitoring. I think monitoring a BizTalk integration solution could be divided into four categories.

  1. Infrastructure (traditional)
    This is the easy one and one that IT-pros and alike are used to monitor. Hardware status, network traffic, disk space, event logs etc all fall under this category. If the storing area for the databases start running low on memory we can be pretty sure it'll eventually effect the integration somehow.

  2. BizTalk infrastructure
    This is where it starts getting a bit trickier. This category includes the status of receive locations, orchestrations, host instances and send ports. If a receive location is down no messages will be picked up (but we can also be sure of not getting any suspended messages).

  3. Suspended messages
    As most reader of this blog probably know suspended message is due to some sort of failure in BizTalk. It can be an actually exception in code or something that went wrong while trying to send messages. It's however and important category to monitor.

  4. Heartbeat (monitoring actual successful traffic)
    While the points 1-3 above focuses on errors and that things being inactive this category actually monitors that the integration runs as expected.

To me this final point is almost the most important one. What I mean is that if everything runs as expected and we're sending the expected amount of messages in the right pace everything else must be ok - right? It's however the one that in my experience almost always overlooked!

"What do you mean 'Not the right tools to monitor'? We have loads of tools in BizTalk 2006 R2!"

OK. So let's see what tools we have available actually monitor the categories above.

  1. Infrastructure (traditional)****
    I won't discuss this kind of monitoring in this post. There are loads of tools (all from the huge expensive enterprise ones to plenty of good open-source alternatives) for this and you're probably already using one or several of them already.

  2. BizTalk infrastructure
    There are a couple of way of achieving this. One of the is to use the Microsoft BizTalk Server Management Pack for Operation Manager. It does however of course require that you have invested in System Center Operation Manager already ...

Another way is to either use the ExplorerOM classes or connecting directly to the BizTalk configuration database and code your own report of some sort.

The final (and most common way in my experience) is to try and document the correct configuration and settings and then have someone check these manually (if you're that person I feel for you ...).

  1. Suspended messages
    Suspended messages are of course very important to monitor and it's for some reason also the first thing developers think of monitoring when developing BizTalk integration (maybe because of the fact that they're similar to traditional exceptions in software). There are also here a couple of different ways to solve the problem.

Microsoft BizTalk Server Management Pack for Operation Manager mentioned above has the functionality to monitor and altering on suspended messages.

BizTalk Server fires the MSBTS_ServiceInstanceSuspendedEvent WMI event every time a service instance gets suspended. It's fully possible to write a service that watches for this event and then for example sends some sort of alert. Darren Jefford has an example on how do something like that in this post.

In BizTalk 2006 Failed Message Routing was introduced. This gives the developer the possibility to subscribe to suspended messages. These can then for example be sent out to file system or written to a database. Microsoft ESB Guidance for BizTalk Server 2006 R2 Exception management component uses this approach. The problem with this approach is however that the message is moved out of BizTalk and one loses all the built in possibilities of resending them etc.

  1. **Heartbeat (monitoring actual successful traffic)

imageAs I said before I think this is a very important metric. If you can see that messages travel through BizTalk in a normal rate things much be pretty ok – right? Without doing to much coding and developing you own pipeline components for tracking etc there are two options.

        **      

The first one is of course using the Health and Activity Tracking tool (HAT). This shows a simple view of receives, processed and sent messages. I hate to say it but the HAT tool is bad. It's slow, it's hard to use, it's hard to filter information, it times out, it doesn't aggregate information, it's basically almost useless ... (Just to make one thing clear: I make my living working with BizTalk and I really enjoy the product but tracking and monitoring is really one of it's ugly sides. I hate to say it.)

The other option is to develop a simple BAM tracking profile to monitoring the send and receive port ports of the different processes.

So to repeat what I said earlier: no I don't think BizTalk comes with the right tool to monitor integration solutions. I do however think that the platform has the capabilities to create something that could close that gap in the product.

What I need!

Much of what’s discussed in this post can be solved using the BizTalk Administrations Console (to manually monitor BizTalk infrastructure status) or in the Health and Activity Tracking tool (to manually monitor traffic). The aim of this post is however to discuss the possibilities to use this information, aggregate it and give the persons responsible for monitoring integration a dashboard that shows the current status of all integrations within the enterprise.

Monitor DashBoard

The dashboard monitor application need the following main features.

  • In one single screen give an overview of the overall status of all the integrations. By status I mean if there are ports, orchestration or host instances that aren't running that should be running or if there is any suspended traffic on that particular integration.

  • The possibility to show detailed information for a specific integration on what artifacts (ports, host instances etc) that are/aren't running. How much traffic that's been sent/received via the integration. When traffic was sent/received and if there's any suspended messages on the integration.

  • The option to filter exclude specific artifacts from monitoring (for example receive locations that's usually turned off etc).

  • Setting up monitoring by for example email and also define what integrations to be included in one specific monitoring (different persons are usually responsible for monitoring different integrations).

Introducing "BizMon"

Based on the needs and "requirements" above I've started developing a application. The idea is to release it as open-source as soon as I get to a first stable version (I'd be very interested in help on practical details on how to do so). For now I'll demonstrate it by showing some screenshots. The application is a web application based on ASP.NET MVC.

Screenshot: "Applications" page

image

The above image shows a screenshot from the start page of the BizMon-application that shows the aggregated status of the entire BizTalk group it's connected to. The applications is build to monitor one BizTalk group and the shown page displays all applications within that BizTalk group.

In the example image the two first rows have an OK status. That means that all of the monitored artifacts (receive locations, send ports, orchestrations and host instances) within that application are in a running and OK status.
The yellow line on the YIT.NO.Project-application indicates a warning. That means that all the artifacts are in a OK status but there're suspended messages within that application. The red line indicates that one or more of the monitored artifacts are in a inactive status.

Each row and application show when the last message on that application was received and/or sent. It also show how many suspended messages exists and when the last message got suspended.

Screenshot: "Application-detail" page

image

When clicking on a application on the main page previously shown the application-detail page is displayed for that application. This page shows detailed information on each of the artifacts within that application. I also shows suspended messages and the date and time of the last suspended.

It also displays a graph showing how many messages that has been processed by each of the ports. Currently the graph can view data from the last 7 days. In the screenshot above data from the 6th of January is shown and as it's set to display data for a specific day the data is grouped in hours of that day. It's also possible to view the aggregated data from all the traced days as show below. When viewing data from all days the graphs is grouped by days.

(The graph only shows data from the 6th of January as this is from test and there was no traffic of the previous days but I'm sure you get the idea ...)

image

Screenshot: "Application-detail" page with inactive artifacts

image

This final page show details of an application with some inactive artifacts. The small cross highlighted by the arrow in the image show the possibility to filter out a single artifact from monitoring. If an excluded artifacts is failing the overall status of the application will still be OK and no alerts will be sent.

Help!

I'd love to get some input and feedback on all this. What do you think could be useful, what do you think won't? Do you know of something similar, how do you solve this kind of monitoring?

I'd also like to know any suitable placed to publish the code as an open-source project or is the best thing to just release it here on the blog? What do you think? Use the comments or send me a mail.

What's next?

I have a few thing on the alerts part of the application left and then I'll release a first version. I'm hoping that could happened at the end of February 09 (look at the update at the top of the post) . Make sure to let me know what you think!

I'll publish a follow-up post discussing the technical details and the architecture more in detail shortly.

Better performance in batch imports to SQL Server using BizTalk

$
0
0

During my years of BizTalk development I've been warned of a couple of scenarios that the product wouldn't handle very well. Yesterday another of those scenarios turned out to kind of false and, if done right, not really a problem at all.

The scenario I'm talking about is a batch import of data to SQL Server using the SQL adapter. In my case the data is received as a flat text file containing a large number of rows. These rows should the be places inside a database table as one table-row per row in the flat file.

The common way of dealing with batch incoming data like this is to split (aka disassemble) it in the receive port using the Flat File Disassembler pipeline component (for a good example - look here). Disassembling the data when receiving it is usually good practice to avoid running into OutOfMemoryException when dealing with big messages.

Sometimes the requirements also forces one into reading each row to a separate message to be able to route and handle each messages in a unique way depending of it's content. If that so - this is a not a good post for you. In this post I'll discuss the scenario were all the data just needs to go as fast as possible from the text file into a single database table. No orchestration or anything, just a simple batch import.

So, what's The problem with the batch import scenario?

When I implemented similar batch import scenarios in the past I tried to practice good practice and split the data into separate files that I then filtered to the SQL adapter send port, one by one.

image

  1. The received flat file files has been split into thousands of small little message that one by one are sent to the SQL adapter send port.
  2. The SQL adapter then parses each message into a SQL script that executes a store procedure and the message is finally inserted to the target database.

"So what's the problem?" you then ask? It's slow! It's very slow! Each message gets stored a couple of times in the BizTalk database and each message is sent inside it's own DTC transaction against the target database. And all this adds up ...

And after reading this this interview by Richard Seroter with Alan Smith I also felt I was the only one having the problem either ...

There are quite a few people asking about using BizTalk for heavy database integration, taking flat files, inserting the data in databases and processing it. SQL Server Integration Services (SSIS) does a much better job than BizTalk at this, and is worth looking at in those scenarios. BizTalk still has its uses for that type of work, but is limited be performance. The worst case I saw was a client who had a daily batch that took 36 hours to process using BizTalk, and about 15 minutes using SSIS. On another project I worked on they had used BizTalk for all the message based integration, and SSIS for the data batching, and it worked really well. >>

Note: As I'll described later in this post my import scenario went from something like 3-4 hours to 2 minutes (importing 10 MB). Alan talks about a 36 hours (!) import. I don't know anything more about the scenario he mentions and it might not even be solved using the technique discussed below. Hopefully Alan might comment on the post and give us more details. ;)

How can we get better performing imports using BizTalk?

As the import scenario we described doesn't involve any orchestration but is a pure messaging scenario and we do all the transformation on the ports we don't really have to worry about OutOfMemoeyExceptions even though the message is quite big.

**Large message transformation.** In previous versions of BizTalk Server, mapping of documents always occurred in-memory. While in-memory mapping provides the best performance, it can quickly consume resources when large documents are mapped. In BizTalk Server 2006, large messages will be mapped by the new large message transformation engine, which buffers message data to the file system, keeping the memory consumption flat. ([Source](http://www.microsoft.com/technet/prodtechnol/biztalk/2006/evaluate/overview/default.mspx)) >>

Another reason for splitting the message was for it to work with the SQL adapter. When setting up the SQL adapter to work with a store procedure the adapter expects a message that looks something like the below.

<ns0:ImportDataSP_Request xmlns:ns0="http://FastSqlServerBatchImport.Schemas.SQL_ImportDataSP">
    <ImportData Name="Name 1" Value="1"></ImportData>
</ns0:ImportDataSP_Request>

This tells us that the store procedure called is "ImportData" with "Name 1" as the value for the "Name" parameter and "1" as the value for the parameter called "Value" in the stored procedure. So each little separate message would get mapped on the send port into something like this.

What I however didn't know until I read this post was that the message I send to the SQL adapter port just as well could look like this!

<ns0:ImportDataSP_Request xmlns:ns0="http://FastSqlServerBatchImport.Schemas.SQL_ImportDataSP">
    <!-- TWO rows!!! -->
    <ImportData Name="Name 1" Value="1"></ImportData>
    <ImportData Name="Name 2" Value="2"></ImportData>
</ns0:ImportDataSP_Request>

So basically we can have as many store procedure calls as we want in one single file that then can send to the SQL adapter send port!

Eureka!) __This means that we don't have to split the incoming file! We can keep it as one big single file and just transform it to a huge file containing separate nodes that we send to the SQL Adapter send port! The SQL adapter will then parse this into separate store procedure calls for us.

image__

Is it really any faster?

As the technique above drastically reduced the amount of database communication needed I knew it'd be much faster. Some initial testing shows that an import of a file containing somewhere around 55 000 rows (about 10 MB) into our article database went from 3-4 hours to under two minutes!

See for yourself!

In this sample solution I have a text file containing 2 600 rows. I've then created two separate projects in a solutions. One that splits the messages into separate messages (called "SlowImport") and one that just transforms it and send it as one message to the send port (called "FastImport"). One takes 1:50 minutes and 2 seconds on my development machine ... I won't tell you which one is the faster one ...

Test it for yourself and let me know what you think.

Receiving scheduled MsgBoxViewer-reports via e-mail

$
0
0

I attended a session the other day at TechDays here in Sweden with Microsoft Escalation Engineer Niklas Engfelt. The session was about troubleshooting BizTalk and Niklas of course showed the wonderful MsgBoxViewer (MBV) tool by Jean-Pierre Auconie. If you haven't tested and looked deeper into this tool you need to do so. It's great!

I worked with the tool before but now I wanted to schedule the tool and to have MBV-reports e-mailed to relevant persons within the company on a weekly basis. This is quite easy to accomplish as MBV comes in two version. One GUI-based (shown below) version and one command-line based.

image

The command-line version is of course perfect for scheduling using the Windows Task Scheduler.

image

If you feel uncomfortable running all the queries (there is a lot of them) on a schedule you can pick some you find important and configure the tool to only run those. Jean-Pierre has a post on how to do just that here.

After MBV has completed all its queries and done its magic it will produce a html-report in the working folder (that's the folder in the "Start in" field in the scheduled task example above).

We then use a tool called AutoMailer NT (cost €20 - there is a 30 days trial) to:

  1. Poll the working folder for a *.html report file.

  2. Compress the file (using zip).

  3. Send the report to a configured list of recipients.

  4. Delete the report file.

The AutoMailer NT installation is a bit rough (don't miss to the ****separate download (!) of the trial certificate). But once you have everything working it's great to have a fresh MBV report in you inbox every Monday telling you how your BizTalk environment is doing and possible issues to attend to.

BAM ate my XML declaration!

$
0
0

There are integrations which only purpose is to move a file just as it is. No advanced routing. No orchestration processing. No transformation. Just a simple port-to-port messaging scenario.

It is however still a good idea to monitor these just as one would monitor a more complicated integration. We use BAM to monitor all our integrations and to measure how many messages that has been processed in a integration. Using BAM monitoring in a simple solution as the above however has its issues …

Setting up a simple test solution

image

  1. The solution will move a XML file between two port called “SimpleTrackingReceivePort” and “SimpleTrackingSendPort”.

  2. Both port have PassThru pipelines configured.

  3. The XML file does not have a installed schema. Remember we are just moving the file not actually doing anything with it.

  4. A BAM tracking definition with one milestone called “StartPort” will be used. This will be mapped to the “PortStartTime” property on both the receiving and sending port .

Our tracking profile configuration will like below. Dead simple.

image

So – what’s the problem?

Let us drop a XML message looking some like this.

<?xml version="1.0" encoding="UTF-16"?>
<SimpleTest>
    <SimpleContent Text="This is a test" />
</SimpleTest>

Remember that there is not a schema installed so we do not really have to worry about the structure of the file. It should just be “a file” to BizTalk and everything should be transferred between the ports. Even if we drop a executable or whatever - it should just be transferred. Nothing should read or examine the file as it’s just a pass thru!

As soon as BAM tracking is configured on a port that is however not the case. Lets take a look at the file we receive on the other end of our integration.

<SimpleTest>
    <SimpleContent Text="This is a test" />
</SimpleTest>

BizTalk now removed our XML declaration! Basically it treated the message as a XML message and parsed the message as such while tracking it. It' will also add the dreaded Byte-Order-Mark and fail any non-valid XML messages. The problem is that this is not the behavior what one expects and causes receiving systems that rely on the XML declaration to fail!

As we also don’t have a installed schema it is not possible to use a XMLTransmit pipeline to add the XML declaration and remove the BOM.

What to do?

If you’d like to track a XML based message using BAM make sure you have the schema installed … Even if you are just using PassThru.

Is it a bug or just something one should expect? In my opinion it is at least very annoying!

Tips and tricks on BizTalk generated SOAP Web Services

$
0
0

Traditional SOAP Web Services might feel kind of old as more and more people move over to WCF. But a lot of integration projects still relay heavily on old fashion SOAP Web Services.

Using BizTalk generated Web Services however has a few issues and one needs to add a few extra steps and procedures to make them effective and easy to work with. This post aims to collect, link and discuss all those issues and solutions.

1. Building and deploying

BizTalk Server includes the “BizTalk Web Services Publishing Wizard” tool that integrates with Visual Studio. This is basically a tool to generate a DSL based script for generating web services.

image

The wizard collects information about what schema or a orchestration to expose, namespaces, names of service and method, where on IIS to publish the service etc, etc.

The output of the tool is then a xml file (a “WebServiceDescription” file) that has all the collected values in it.

image

As a final step Visual Studio uses the newly created description file as input to a class called WebServiceBuilder in the .NET Framework. It is this class that is responsible for interpreting the description, configure and generate the service.

A common procedure is to use the wizard and click thru it and input values for every single deployment. This is of course slow, error prone and stupid.

What is much better is to take a copy of the generated “WebServiceDescription” file, save it to your source control system and then programmatically pass the file to the WebServiceBuilder class as part of your deployment process. Possible changes to the details of the service can then be done directly in the description file.

I have seen this approach save lots of time and problems related to deployment.

2. Fixing namespace

Another annoying problem (I’d would actually go so far as calling it a bug) is the problem with the bodyTypeAssemblyQualifiedName value in the generated Web Service class.

This causes BizTalk to skip looking up the actual message type for the incoming message. As no message type exists for the message is in BizTalk mapping and routing on message types etc will fail. It is a know problem and there are solutions to it. I would also recommend take the extra time need to make this small “post process step” be part of your deployment process (see how here).

3. Pre-compiling

By default the “WebServiceBuilder” class generates a web service without pre-compiling it. Usually this is not a problem. But in some cases were one really on the web service being online and give a quick response-message the performance problems in this approach can be a huge problem.

When generating the web service without pre-compiling it IIS has to compile the service and then keep the compiled service in memory. That means that when IIS releases the service from memory there is a latency before IIS re-compiled the service, loaded it into memory and executed it. This is a known problem and I have seen this “slow first hit” issue been a frequent question the different forums.

The solution is to use the aspnet_compiler.exe tool and pre-compile the service and the use those pre-compiled dlls as the service. IIS then never has to recompile it and will serve initial hits much faster.

Here is an example of how we defined a target to do this as part of our deployment process using MSBuild.

  1. Pre-compile the service into a new folder

  2. Clean out the “old” not compile service folder.

  3. Copy the pre-complied service into the service folder

    <Folder.CleanFolder Path="$(WebSiteServicePath)$(WebServiceName)\"/>
    
    <Folder.CopyFolder
                Source="$(WebSiteServicePath)$(WebServiceName)Compiled\"
                Destination="$(WebSiteServicePath)$(WebServiceName)\" />
    

  4. Paul Petrov has two different articles here describing the process and also a different way that above on how to include the pre-compilation in you build process.

http://geekswithblogs.net/paulp/archive/2006/03/30/73900.aspx, http://geekswithblogs.net/paulp/archive/2006/04/19/75633.aspx

Viewing all 102 articles
Browse latest View live