<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-2349891517694519380</id><updated>2009-05-04T16:15:26.403+07:00</updated><title type='text'>ASP.Net, .Net, BizTalk, Tech and Life - Francois Malgreve - Bangkok</title><subtitle type='html'>I am a Software Development Specialist who held many different roles such as Developer, Team Leader, Project Manager and Software Architect.
I mostly work with Microsoft technologies such as .Net, C#, ASP.Net, SQL Server 2005 and BizTalk Server 2006. I currently reside in Thailand (Bangkok) working on integration projects (B2B, B2C, EAI) using BizTalk Server 2006.</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.malgreve.net/atom.xml'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-985844418477640751</id><published>2008-11-26T11:50:00.001+07:00</published><updated>2008-11-26T11:51:48.346+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T-SQL'/><title type='text'>How to script data – generate insert T-SQL statements from existing data</title><content type='html'>I found &lt;a href="http://vyaskn.tripod.com/code.htm#inserts"&gt;this script&lt;/a&gt; that is able to generate insert T-SQL statements for data already existing in a database table. The script is packaged into a stored procedure and is thus very convenient to use.&lt;br /&gt;It can reveal very useful when creating scripts for database initialization when packaging the release of a database driven application or moving some data to a new environment.&lt;br /&gt;&lt;br /&gt;Developers do not always have access to all the different environments but sometimes still need to package data deployment scripts for those environments. Most often this will apply to lookup tables such as a lookup tables containing configuration values of an application which can potentially change with every release of an application. It could also apply to simpler cases such as a country code lookup table. Anyways, with this script, it will just take you seconds to generate all the insert statements into an SQL script that you can release with other deliverables (libraries, stored procedures…) to the release manager in charge of updating the application on the live environments.&lt;br /&gt;&lt;br /&gt;The strong points of this script are that it handles identity column as well as computed columns and can script data for both views and tables. As this script is so useful for me, I backed-up the stored procedure scripts would the original link be one day broken:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.malgreve.net/generate_insert_sql2000.txt" rel="nofollow"&gt;Procedure to script data for SQL 2000&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.malgreve.net/generate_insert_sql2005.txt" rel="nofollow"&gt;Procedure to script data for SQL 2005&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;I do not have SQL 2008 yet so I could check if the script works for SQL 2008. I guess that it might as SQL Server didn’t change as dramatically between the 2005 and 2008 version as it did between the 2000 and 2005 version. Anyway if someone tries it, please feel welcome to let me know about it in a comment :)&lt;br /&gt;&lt;br /&gt;Note that commercial products are available would you need fancier data scripting features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-985844418477640751?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/985844418477640751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=985844418477640751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/985844418477640751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/985844418477640751'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/11/how-to-script-data-generate-insert-t.html' title='How to script data – generate insert T-SQL statements from existing data'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4995603275997398817</id><published>2008-09-22T18:36:00.002+07:00</published><updated>2008-09-22T18:45:14.944+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><title type='text'>Regular expressions tool designer</title><content type='html'>Regular expressions are very useful but as I do not have to use them a lot, I often forget the exact syntax required for my particular need.&lt;br /&gt;So today I would like to share a tool to build regular expressions which I have been using many times over, the &lt;a href="http://www.radsoftware.com.au/regexdesigner/"&gt;Regular Expression Designer of Rad Software&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The tool is free, easy to use but yet powerful and intuitive. The contextual help is very short but just perfect and straight to the point for someone who already has previous regex experience. If you are a total newbie in regular expressions, you should read some short introductory material beforehand.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4995603275997398817?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4995603275997398817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4995603275997398817' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4995603275997398817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4995603275997398817'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/09/regular-expressions-tool-designer.html' title='Regular expressions tool designer'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6007582921999088049</id><published>2008-09-15T09:40:00.001+07:00</published><updated>2008-09-15T10:43:58.500+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Server Installation'/><title type='text'>Error configuring BizTalk Server 2006</title><content type='html'>Today I had quite some troubles installing BizTalk Server 2006. As I have previously installed BizTalk many times without being stuck on a problem for so long, I thought I would blog about it. Who knows, it might help some other soul encountering the same issue.&lt;br /&gt;&lt;br /&gt;My configuration was the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1 Windows Server 2003 64-bit running SQL Server 2005.&lt;/li&gt;&lt;li&gt;1 Windows Server 2003 64-bit with BizTalk Server 2006 installed but not yet configured.&lt;/li&gt;&lt;/ul&gt;Both machines had MSDTC and COM+ installed and running, a pre-requisite to install BizTalk on a multiple-server environment.&lt;br /&gt;All the BizTalk Users as well as the Windows Account used to install BizTalk had the necessary rights and belonged to the necessary Groups. See a previous post of mine for more information; &lt;a href="http://www.malgreve.net/2007/08/biztalk-2006-multiserver-installation.html"&gt;Biztalk 2006 multi-server installation guide&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, after having installed BizTalk Server 2006, the BizTalk Server needs to be configured by using the &lt;span style="font-style:italic;"&gt;BizTalk Server Configuration&lt;/span&gt; tool and there the weirdest thing happened: it failed, but not completely! &lt;span style="font-weight:bold;"&gt;Enterprise SSO&lt;/span&gt; (Enterprise Single Sign-On) and &lt;span style="font-weight:bold;"&gt;Business Rules Engine&lt;/span&gt; (BRE) components were configured successfully while &lt;span style="font-weight:bold;"&gt;Group&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;BizTalk Runtime&lt;/span&gt; failed.&lt;br /&gt;Thinking I made some human mistake in the configuration, I retried 2 times but the same problem happened. On a side note, before retrying to configure BizTalk, I had to manually delete the BizTalkMgmtDb as it was created even as the configuration step creating that DB failed.&lt;br /&gt;&lt;br /&gt;I then read line by line the log file produced by the configuration tool and searched for the source of the problem. I will paste here the relevant parts:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;[1:57:09 PM Error ConfigHelper] [DBNETLIB][ConnectionOpen (Connect()).]SQL Server does not exist or access denied.&lt;br /&gt;[1:57:09 PM Error ConfigHelper] SQL error: 08001 Native error code: 17&lt;br /&gt;[1:57:09 PM Error ConfigHelper] c:\depotsetupv2\private\common\configwizard\confighelper\sqlhelper.cpp(1176): FAILED hr = 80004005&lt;br /&gt;[1:57:09 PM Error ConfigHelper] c:\depotsetupv2\private\common\configwizard\confighelper\sqlhelper.cpp(918): FAILED hr = 80004005&lt;br /&gt;[1:57:09 PM Info ConfigHelper]  Did not find existing database: BizTalkMgmtDb on computer: &lt;br /&gt;[1:57:09 PM Info RuleEngineConfig] Management database (server = , database = BizTalkMgmtDb) doesn't exist&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With this information in hand, I suspected something was wrong with the credentials and I checked all the Users and Groups in Active Directory and also checked that I was admin of the SQL Server machine but everything looked ok. I nevertheless re-tried the configuration a few times, being extra careful with every setting but unsuccessfully. I then moved on to next problem in the log file.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;[2:08:41 PM Error ConfigHelper] c:\depotsetupv2\private\common\configwizard\confighelper\service.cpp(729): FAILED hr = 80070421&lt;br /&gt;[2:08:41 PM Warning ConfigHelper] The account name is invalid or does not exist, or the password is invalid for the account name specified.&lt;br /&gt;[2:08:41 PM Warning ConfigHelper]  Failed to validate service credentials for account: %1&lt;br /&gt;[2:08:41 PM Info BtsCfg] Check Your NT Account Specification&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here the configuration log complains about Windows Credential issues again. Everything was pointing out to Active Directory, this would reveal to actually point me in the wrong direction. So, as I could still not find any problem in AD, I moved on to the next problem I could find in the log:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;2008-09-12 14:13:16:0075 [INFO] WMI Deploying 'C:\Program Files (x86)\Microsoft BizTalk Server 2006\Microsoft.BizTalk.GlobalPropertySchemas.dll'&lt;br /&gt;2008-09-12 14:13:22:0184 [WARN] AdminLib GetBTSMessage: hrErr=80070002; Msg=The system cannot find the file specified.; &lt;br /&gt;2008-09-12 14:13:22:0184 [WARN] AdminLib GetBTSMessage: hrErr=c0c02560; Msg=Failed to read "KeepDbDebugKey" from the registry.&lt;br /&gt;The system cannot find the file specified.; &lt;br /&gt;2008-09-12 14:13:22:0184 [INFO] WMI Error occurred during database creation; attempt to rollback and delete the partially created database'ny-agbdb-301\BizTalkMsgBoxDb'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Two points here:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The file “T:\Program Files (x86)\Microsoft BizTalk Server 2006\Microsoft.BizTalk.GlobalPropertySchemas.dll” was present on the file system so it didn’t seem there was anything I could do about it.&lt;/li&gt;&lt;li&gt;The key “KeepDbDebugKey” did not exist in the registry of running healthy BizTalk systems so I supposed this registry key exists only temporarily during the BizTalk configuration procedure.&lt;/li&gt;&lt;/ul&gt;I then moved on the next potential problem in the log file:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;2008-09-12 14:14:02:0465 [ERR] WMI Failed in pAdmInst-&gt;Create() in CWMIInstProv::PutInstance(). HR=c0c025b3&lt;br /&gt;2008-09-12 14:14:02:0465 [ERR] WMI WMI error description is generated: Exception of type 'System.EnterpriseServices.TransactionProxyException' was thrown.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here the configuration tool log entry complains about a Transaction from the System.EnterpriseServices library. As this package refers to Distributed Transactions (MS DTC), I doubled checked that MS DTC was running well on both machines, checked firewall configurations but all the necessary ports were open.&lt;br /&gt;I then started to try to troubleshoot DTC following the &lt;a href="http://msdn.microsoft.com/en-us/library/aa561924.aspx"&gt;MSDTC troubleshooting guide from Microsoft&lt;/a&gt; and found a utility called &lt;span style="font-weight:bold;"&gt;dtctester&lt;/span&gt; that can be downloaded from the &lt;a href="http://support.microsoft.com/kb/293799"&gt;KB 293799&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-weight:bold;"&gt;dtctester&lt;/span&gt; test failed and so I was now sure that the problem was related with DTC. I re-checked the firewall settings, checked the dual network adapter and the DNS as advised by Microsoft and found out that the problem lied with the DNS having some wrong reverse mappings (IP address -&gt; hostname mappings).&lt;br /&gt;&lt;br /&gt;As a corollary, notice that the only log information that proved to point me to the actual source of  the problem were log entries with the string &lt;span style="font-weight:bold;"&gt;[ERR]&lt;/span&gt; in their header. All others had either &lt;span style="font-weight:bold;"&gt;[INFO]&lt;/span&gt; or &lt;span style="font-weight:bold;"&gt;[WARN]&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;To conclude, I would advise to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use &lt;span style="font-weight:bold;"&gt;dtctester&lt;/span&gt; before operating a BizTalk multi-server installation.&lt;/li&gt;&lt;li&gt;When running into problems, look first at the log entries having either the &lt;span style="font-weight:bold;"&gt;[ERR]&lt;/span&gt; or &lt;span style="font-weight:bold;"&gt;Error&lt;/span&gt; string in their header - It indeed seems there are two different formats of log entry header in the log file produced by the Configuration tool. While looking first for the Error type of log entries sounds obvious, it seems that not many people are aware of the log entry header formats and the log entry types generated in the log file.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6007582921999088049?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6007582921999088049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6007582921999088049' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6007582921999088049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6007582921999088049'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/09/error-configuring-biztalk-server-2006.html' title='Error configuring BizTalk Server 2006'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6669073534649790839</id><published>2008-08-08T18:16:00.004+07:00</published><updated>2008-08-08T18:39:23.984+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Operation and Maintenance'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>How to purge BizTalkMsgDb?</title><content type='html'>If the BizTalk Message Box database (BizTalkMsgDb) grows too large, performance of the database subsystem will reduce. As a rule of thumb, the BizTalkMsgDb should never grow larger than 5 Gb for large systems with long running transactions. For high-volume environment with no long running transactions, the BizTalkMsgDb size should be much smaller than 5Gb.&lt;br /&gt;&lt;br /&gt;Would your message box have already grown too large and the system become unresponsive, you might want to clean up the BizTalkMsgDb database manually but keep in mind that:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The BizTalk Server must be taken down during the procedure.&lt;/li&gt;&lt;li&gt;All existing messages will be purged and lost.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There is an article in the MSDN documentation that explains in details &lt;a href="http://msdn.microsoft.com/en-us/library/bb727781.aspx"&gt;how to manually purge data from the Message Box Database&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To make a long story short, here is step by step summary:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Stop ALL BizTalk service host instances from the Services console.&lt;/li&gt;&lt;li&gt;Restart IIS by running IISRESET from the command prompt if you are running any adapters in isolated hosts (for example HTTP, SOAP, or WCF).&lt;/li&gt;&lt;li&gt;Execute the stored procedure &lt;span style="font-weight:bold;"&gt;bts_CleanupMsgbox&lt;/span&gt; on your message box database. If the stored procedure does not exist, create it by running the sql script “msgbox_cleanup_logic.sql” found in the directory “&amp;lt;BizTalk installation directory&amp;gt;\Schema\”.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Important note&lt;/span&gt;: If you are running BizTalk Server 2006, you first have to get an updated version of the Msgbox_cleanup_logic.sql file to (re)create the &lt;span style="font-weight:bold;"&gt;bts_CleanupMsgbox&lt;/span&gt; stored procedure at &lt;a href="http://support.microsoft.com/kb/924715"&gt;http://support.microsoft.com/kb/924715&lt;/a&gt;. The hotfix is available for download directly without having to contact MS. If you are running BizTalk Server 2006 R2 then the updated version of the Msgbox_cleanup_logic.sql file is already installed and you do not need to download the hotfix.&lt;/li&gt;&lt;li&gt;Execute the stored procedure &lt;span style="font-weight:bold;"&gt;bts_PurgeSubscriptions&lt;/span&gt; on your message box database. If the stored procedure does not exist, you can create it by inspecting the sql script “msgboxlogic.sql” found in the directory “&amp;lt;BizTalk installation directory&amp;gt;\Schema\”. Copy paste only the part of the script that creates this specific stored procedure and run it.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;As deleting data in a database does not reduce the size the database files on the disk; you need to shrink the database files if you want to reduce its physical size. There are 2 simple ways to do it:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Through SQL Server Management Studio, right click on the BizTalkMsgDb database, click on Tasks &gt; Shrink &gt; Database&lt;/li&gt;&lt;li&gt;Through T-SQL, using the DBCC SHRINKDATABASE command: DBCC SHRINKDATABASE (BizTalkDTADb);&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;There is also another useful command to truncate the database logfile, would it be necessary:&lt;br /&gt;BACKUP LOG BizTalkDTADb WITH TRUNCATE_ONLY&lt;br /&gt;&lt;br /&gt;Microsoft does not support this procedure on production systems simply because this will purge production data. So, as long as you keep in mind that all existing messages will be purged, it is safe to run it on a production environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6669073534649790839?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6669073534649790839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6669073534649790839' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6669073534649790839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6669073534649790839'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/08/how-to-purge-biztalkmsgdb.html' title='How to purge BizTalkMsgDb?'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6735542138012598055</id><published>2008-07-31T22:55:00.007+07:00</published><updated>2008-08-01T16:51:47.197+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Exception Handling'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>How to Handle Unhandled Exception</title><content type='html'>When an unhandled exception occurs in the .Net Framework run-time 1.0 &amp;amp; 1.1, the Windows Process will terminate &lt;span style="font-weight: bold;"&gt;only&lt;/span&gt; if the exception occurred on the main application thread. Would an unhandled exception occur in a thread other than the main application thread, it will be caught by the runtime and therefore &lt;span style="font-weight: bold;"&gt;NOT cause the application to terminate&lt;/span&gt;. This means that unhandled exceptions in child threads disappear silently without anyone being able to know about it, implying that bugs are silently swallowed by the runtime without anyone being notified about it. The dangerous scenario is that a user might believe that a unit of work has executed successfully while it is actually not the case. This is in my opinion something not desirable and has been addressed in later version of the .Net Framework.&lt;br /&gt;&lt;br /&gt;Indeed, from the .Net Framework 2.0 onwards, unhandled exceptions occurring on &lt;span style="font-weight: bold;"&gt;ANY&lt;/span&gt; thread (thus including any child threads being background threads or not) shuts down the application running the particular thread.&lt;br /&gt;&lt;br /&gt;When the runtime terminates an application because of an unhandled exception, it writes an entry in the Windows Event Log which looks like the following:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;EventType clr20r3, P1 processname, P2 1.0.0.0, P3 485f85f0, P4 system, P5 2.0.0.0, P6 471ebf0d, P7 3832, P8 bf, P9 system.componentmodel.win32, P10 NIL.&lt;/blockquote&gt;&lt;br /&gt;“processname” being the name of the .Net executable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. How to resolve unhandled exceptions? The System.AppDomain.UnhandledException event.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If an unhandled exception occurs in a windows application (multi-threaded or not), a windows service named winservice.exe for example, the runtime will terminate the service and write an Event Log entry such as:&lt;br /&gt;“EventType clr20r3, P1 winservice.exe, P2 1.0.0.0, P3 485f85f0, P4 system, P5 2.0.0.0, P6 471ebf0d, P7 3832, P8 bf, P9 system.componentmodel.win32, P10 NIL.”&lt;br /&gt;&lt;br /&gt;While it is good to be notified that a service crashed, the information supplied is rather cryptic and has very little added value. It would be nicer to have a way to log unhandled exceptions with a more meaningful message so that it is possible to get enough information to be able to fix the source code and re-deploy the application.&lt;br /&gt;&lt;br /&gt;Conveniently, the .Net Framework provides the &lt;span style="font-weight: bold;"&gt;System.AppDomain.UnhandledException&lt;/span&gt; event. This event fires whenever an application domain unloads because of an unhandled exception. Note that registering for the event does not cause unhandled exceptions to be "handled". It simply notifies you that an exception has gone unhandled, so that it is possible to take some action such as logging the exception message and stack trace and eventually do some clean up before the application dies. The Exception is still unhandled and so still causes the application to shut down.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The discussion in this article is not a solution on how to handle exceptions. Exception handling is a strategy on how to handle exceptions and is a different discussion. This article explains how to act with unhandled exceptions so that details about the exception can be logged so that a proper solution can be found to resolve the issue/bug.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ideally, all exceptions should be handled in the source code with try-catch-finally blocks so that unhandled exceptions do not occur.  Nevertheless, there are always unforeseen cases and developer mistakes which, in my opinion, justify caring for unhandled exceptions across the board.&lt;br /&gt;&lt;br /&gt;Here is an example on how to register for the event with an event handler that log exception details in the Windows Event Log:&lt;br /&gt;&lt;br /&gt;// This event provides notification of uncaught exceptions. Write this in the entry point of your program, like in the OnStart() method of a Windows Service.&lt;br /&gt;AppDomain currentDomain = AppDomain.CurrentDomain;&lt;br /&gt;currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler);&lt;br /&gt;static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)&lt;br /&gt;{&lt;br /&gt;    Exception ex = (Exception)args.ExceptionObject;&lt;br /&gt;    EventLog.WriteEntry("WinService.exe", "Unhandled Exception caught: " + ex.Message + ex.StackTrace, EventLogEntryType.Error);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. Note for Windows Form Applications - Application.ThreadException event.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2.1 Application.ThreadException event&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For Windows Form Applications, there is another event that is raised when an unhandled exception occurs, the &lt;span style="font-weight: bold;"&gt;System.Windows.Forms.Application.ThreadException&lt;/span&gt;. Nevertheless, &lt;span style="font-weight: bold;"&gt;this event fires only when unhandled exceptions happen in Window Forms threads (UI threads)&lt;/span&gt;. This means when an exception is thrown from code that was ultimately called as a result of a &lt;span style="font-weight: bold;"&gt;Windows Message&lt;/span&gt;. Windows Messages are emitted by keyboard hits, mouse clicks or "paint" messages,... in short, nearly all code in a typical Windows Forms application.&lt;br /&gt;&lt;br /&gt;While this works perfectly, it lulls one into a false sense of security that all exceptions will be caught by the central exception handler:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Exceptions thrown on worker threads are a good example of exceptions not caught by &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;Exceptions thrown by the code inside the Main method of the Windows Forms application, including the main form's constructor, executes before the Windows message loop begins and so is another example of exceptions that do not raise the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In this case, we said the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event handler to be a “central exception handler” because it is still possible for the application to keep running when this event is raised, depending on what kind of logic is implemented in the handler.&lt;br /&gt;&lt;br /&gt;As a reminder, Worker Threads are threads:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Created manually: Thread.Start()&lt;/li&gt;&lt;li&gt;Created by the ThreadPool: ThreadPool.QueueUserWorkItem()&lt;/li&gt;&lt;li&gt;Created by any kind of asynchronous call which internally uses a thread pool thread to execute: Delegate.BeginInvoke(), BeginXXX()&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;One must attach a handler to the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event &lt;span style="font-weight: bold;"&gt;before&lt;/span&gt; instantiating the main form of the application by calling Application.Run(). Also, because this is a static event, you must detach the event handler(s) when the application is disposed or memory leaks will result.&lt;br /&gt;&lt;br /&gt;The Application.ThreadException as a default event handler which behaves in the following way:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If an unhandled exception occurs in the main application thread, the default exception handler catches it and terminates the application.&lt;/li&gt;&lt;li&gt;If an exception occurs in a thread other than the main application thread, the thread exits, but the application continues to run.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2.2 Application.SetUnhandledExceptionMode&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is possible to instruct the application whether it should catch all unhandled exceptions thrown by Windows Forms components and terminate the application, or whether it should raise an event so that an event handler can be implemented; the event handler could halt execution and expose the unhandled exception to the user.  This is setting is done by using the application configuration file or the &lt;span style="font-weight: bold;"&gt;Application.SetUnhandledExceptionMode()&lt;/span&gt; method.&lt;br /&gt;It is possible to instruct the application whether it should catch all unhandled exceptions thrown by Windows Forms components and terminate the application, or whether it should raise an event so that an event handler can be implemented; the event handler could halt execution and expose the unhandled exception to the user.  This is setting is done by using the application configuration file or the &lt;span style="font-weight: bold;"&gt;Application.SetUnhandledExceptionMode()&lt;/span&gt; method.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;UnhandledExceptionMode.ThrowException&lt;/span&gt; never route exceptions to the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event handler and so the default event handler will terminate the application when an unhandled exception occurs as explained earlier.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;UnhandledExceptionMode.CatchException&lt;/span&gt; always route exceptions to the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event handler.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Again, as a reminder, the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event handler is only for unhandled exception occurring on UI threads and so the &lt;span style="font-weight: bold;"&gt;SetUnhandledExceptionMode()&lt;/span&gt; method affects only the way unhandled exceptions coming from UI threads are treated, it does not affect how non UI threads unhandled exceptions are treated. &lt;span style="font-weight: bold;"&gt;System.AppDomain.UnhandledException&lt;/span&gt; event handlers will always be called when non UI threads unhandled exceptions occur.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2.3 Sample&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hereunder is a code sample on how to register to the &lt;span style="font-weight: bold;"&gt;Application.ThreadException&lt;/span&gt; event in a Windows Form Application. As said earlier the event handler will only be called for unhandled exceptions occurring on the UI thread.  Thus, the code sample also has an event handler for unhandled exception on non-UI threads by registering to the &lt;span style="font-weight: bold;"&gt;System.AppDomain.UnhandledException&lt;/span&gt; event:&lt;br /&gt;&lt;br /&gt;static class Program&lt;br /&gt;{&lt;br /&gt;    /// &lt;summary&gt;&lt;br /&gt;    /// The main entry point for the application.&lt;br /&gt;    /// &lt;/summary&gt;&lt;br /&gt;    [STAThread]&lt;br /&gt;    static void Main()&lt;br /&gt;    {&lt;br /&gt;        // Add the event handler for handling UI thread exceptions to the event.&lt;br /&gt;        Application.ThreadException += new ThreadExceptionEventHandler(Form1_UIThreadException);&lt;br /&gt;&lt;br /&gt;        // Set the unhandled exception mode to force all Windows Forms errors on UI threads&lt;br /&gt;        // to go through our handler regardless of application settings.&lt;br /&gt;        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);&lt;br /&gt;&lt;br /&gt;        // Add the event handler for handling non-UI thread exceptions to the event. &lt;br /&gt;        AppDomain.CurrentDomain.UnhandledException +=&lt;br /&gt;            new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);&lt;br /&gt;&lt;br /&gt;       // Default generated code by Visual Studio for WinForms&lt;br /&gt;       Application.EnableVisualStyles();&lt;br /&gt;       Application.SetCompatibleTextRenderingDefault(false);&lt;br /&gt;       Application.Run(new Form1());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;You can find a zip file &lt;a href="http://www.malgreve.net/FormUnhandledException.zip"&gt;here&lt;/a&gt; containing a complete Visual Studio 2008 solution demonstrating both type of unhandled exception event handler and their effect.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Note for ASP.NET applications - Application_Error in Global.asax.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Would an unhandled exception occurs in an ASP.NET application on a worker thread, the runtime will terminate the worker process (w3wpp.exe) and write an Event Log entry such as:&lt;br /&gt;“EventType clr20r3, P1 w3wp.exe, P2 6.0.3790.1830, P3 42435be1, P4 app_web_7437ep-9, P5 0.0.0.0, P6 433b1670, P7 9, P8 a, P9 system.exception, P10 NIL.”&lt;br /&gt;&lt;br /&gt;In ASP.Net, there is an &lt;span style="font-weight: bold;"&gt;Application_Error&lt;/span&gt; method in the Global.asax file that can be implemented so that an action can be taken when an unhandled exception occurs (logging the exception details, for example). Again, treating an unhandled exception in such a way is not handling an exception (that should be done in the try-catch-finally block in the code), the web application will still crash and display an error message on the browser but it lets the programmer have a way to log information about the exception and eventually do some other clean-up tasks.&lt;br /&gt;&lt;br /&gt;Nevertheless, similarly to Windows Forms Application, &lt;span style="font-weight: bold;"&gt;the Application_Error will be called only for unhandled exception that occurred on the main thread&lt;/span&gt;. Unhandled exceptions occurring on worker threads will not be caught by the Application_Error event handler in the global.asax file. If we want to be notified of unhandled exception occurring on worker threads, we need to register an event handler to the &lt;span style="font-weight: bold;"&gt;System.AppDomain.UnhandledException&lt;/span&gt; event, as we did for Windows Services and Forms Applications. The event handler should at least log the exception and eventually do some clean tasks.&lt;br /&gt;&lt;br /&gt;Microsoft has a &lt;a href="http://support.microsoft.com/?id=911816"&gt;KB on how to implement an event handler for the System.AppDomain.UnhandledException event within an HTTPModule&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You can find &lt;a href="http://www.malgreve.net/WebUnhandledException.zip"&gt;here&lt;/a&gt; a zip file with a Visual Studio 2008 solution using the HTTPModule defined in the KB. I registered the HTTP module in the web.config the following way:&lt;br /&gt;&lt;br /&gt;&amp;lt;system.web&amp;gt;&lt;br /&gt;   &amp;lt;httpModules&amp;gt;&lt;br /&gt;      &amp;lt;add name="UnhandledExceptionModule" type="WebMonitor.UnhandledExceptionModule, UnhandledExceptionModule, Version=1.0.0.0,&lt;br /&gt;Culture=neutral, PublicKeyToken=51d169497dc4a81e, processorArchitecture=MSIL"/&amp;gt;&lt;br /&gt;   &amp;lt;/httpModules&amp;gt;&lt;br /&gt;&amp;lt;/system.web&amp;gt;&lt;br /&gt;&lt;br /&gt;The only non trivial attribute is the “PublicKeyToken”. The Public Key Token is a 64-bit hash of the public key corresponding to the private key used to sign the assembly. A &lt;a href="http://en.wikipedia.org/wiki/.NET_assembly"&gt;.Net assembly&lt;/a&gt; is said to have a strong name when it is signed.&lt;br /&gt;&lt;br /&gt;There are 2 ways to retrieve the Public Key Token from a strongly named assembly:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The lazy way is to add the assembly in the GAC and go to C:\WINDOWS\assembly, one of the column showed in Windows Explorer is the Public Key Token. Only strongly named assemblies can be stored in the GAC.&lt;/li&gt;&lt;li&gt;Run the command line “sn -T UnhandledExceptionModule.dll” which prints the Public Key token of a strongly named assembly.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Contrary to the instructions given in the KB, I did not GAC either NGEN the HTTP module; I just referenced the HTTPModule project from the web project so that the HTTP module library is automatically copied to the web application bin folder. All assemblies in the bin folder are automatically found by the run-time so that is not necessary to GAC all third party libraries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6735542138012598055?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6735542138012598055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6735542138012598055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6735542138012598055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6735542138012598055'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/07/how-to-handle-unhandled-exception.html' title='How to Handle Unhandled Exception'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-7969551950670334885</id><published>2008-06-26T11:17:00.003+07:00</published><updated>2008-07-21T13:51:27.378+07:00</updated><title type='text'>SQL Server and .Net Data Type mapping</title><content type='html'>Today I would like to post a table listing the corresponding .Net Type to use with each SQL Data Type. This comes in handy when writing ADO.NET code.&lt;br /&gt;&lt;br /&gt;The following link lists Microsoft SQL Server data types and their equivalent data type in .Net.&lt;br /&gt;To be more exact it lists:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Every SQL Server data types&lt;/li&gt;&lt;li&gt;Their equivalent in the Common Language Runtime (CLR) for SQL Server in the System.Data.SqlTypes namespace&lt;/li&gt;&lt;li&gt;Their native CLR equivalents in the Microsoft .NET Framework&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms131092.aspx"&gt;SQL Server Data Types and Their .NET Framework Equivalents&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I have also copy-pasted the SQL Server and .Net Data Type mapping table hereunder for my own convenience:&lt;br /&gt;&lt;br /&gt;&lt;table style="background-color: rgb(255, 255, 255);" border="1" width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;SQL Server data type&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;CLR data type (SQL Server)&lt;/span&gt;&lt;/td&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;CLR data type (.NET Framework)&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  varbinary   &lt;/td&gt; &lt;td&gt;  SqlBytes, SqlBinary  &lt;/td&gt; &lt;td&gt;  Byte[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  binary  &lt;/td&gt; &lt;td&gt;  SqlBytes, SqlBinary  &lt;/td&gt; &lt;td&gt;  Byte[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  varbinary(1), binary(1)  &lt;/td&gt; &lt;td&gt;  SqlBytes, SqlBinary  &lt;/td&gt; &lt;td&gt;  byte, Byte[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  image  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  varchar  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  char  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  nvarchar(1), nchar(1)  &lt;/td&gt; &lt;td&gt;  SqlChars, SqlString  &lt;/td&gt; &lt;td&gt;  Char, String, Char[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  nvarchar  &lt;/td&gt; &lt;td&gt;  SqlChars, SqlString   SQLChars is a better match for data transfer and access, and SQLString is a better match for performing String operations. &lt;/td&gt; &lt;td&gt;  String, Char[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  nchar  &lt;/td&gt; &lt;td&gt;  SqlChars, SqlString  &lt;/td&gt; &lt;td&gt;  String, Char[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  text  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  ntext  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  uniqueidentifier  &lt;/td&gt; &lt;td&gt;  SqlGuid  &lt;/td&gt; &lt;td&gt;  Guid  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  rowversion  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt;  Byte[]  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  bit  &lt;/td&gt; &lt;td&gt;  SqlBoolean  &lt;/td&gt; &lt;td&gt;  Boolean  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  tinyint  &lt;/td&gt; &lt;td&gt;  SqlByte  &lt;/td&gt; &lt;td&gt;  Byte  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  smallint  &lt;/td&gt; &lt;td&gt;  SqlInt16  &lt;/td&gt; &lt;td&gt;  Int16 (short in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  int  &lt;/td&gt; &lt;td&gt;  SqlInt32  &lt;/td&gt; &lt;td&gt;  Int32 (int in C#)  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  bigint  &lt;/td&gt; &lt;td&gt;  SqlInt64  &lt;/td&gt; &lt;td&gt;  Int64 (long in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  smallmoney  &lt;/td&gt; &lt;td&gt;  SqlMoney  &lt;/td&gt; &lt;td&gt;  Decimal (decimal in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  money  &lt;/td&gt; &lt;td&gt;  SqlMoney  &lt;/td&gt; &lt;td&gt;  Decimal (decimal in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  numeric  &lt;/td&gt; &lt;td&gt;  SqlDecimal  &lt;/td&gt; &lt;td&gt;  Decimal (decimal in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  decimal  &lt;/td&gt; &lt;td&gt;  SqlDecimal  &lt;/td&gt; &lt;td&gt;  Decimal (decimal in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  real  &lt;/td&gt; &lt;td&gt;  SqlSingle  &lt;/td&gt; &lt;td&gt;  Single (float in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  float  &lt;/td&gt; &lt;td&gt;  SqlDouble  &lt;/td&gt; &lt;td&gt;  Double (double in C#) &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  smalldatetime  &lt;/td&gt; &lt;td&gt;  SqlDateTime  &lt;/td&gt; &lt;td&gt;  DateTime  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  datetime  &lt;/td&gt; &lt;td&gt;  SqlDateTime  &lt;/td&gt; &lt;td&gt;  DateTime  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  sql_variant  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt;  Object  &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  User-defined type(UDT)  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; Same class that is bound to the user-defined type in the same assembly or a dependent assembly. &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  table  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  cursor  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  timestamp  &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;td&gt; None &lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;  xml  &lt;/td&gt; &lt;td&gt;  SqlXml  &lt;/td&gt; &lt;td&gt; None&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Regarding CLR Data Types, Data Types are basically divided in 3 categories:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx"&gt;Value Types&lt;/a&gt; (CLR-defined &lt;a href="http://msdn.microsoft.com/en-us/library/ah19swz4.aspx"&gt;structs&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/sbbt4032.aspx"&gt;Enumerations&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/c8f5xwh7.aspx"&gt;bool&lt;/a&gt;, user-defined &lt;a href="http://msdn.microsoft.com/en-us/library/ah19swz4.aspx"&gt;structs&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/490f96s2.aspx"&gt;Reference Types&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx"&gt;Pointer Types&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Furthermore, 3 types of CLR Data Type structures exist to hold numeric values:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/exx3b86w.aspx"&gt;Integral types&lt;/a&gt;, holding integers&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/9ahet949.aspx"&gt;Floating-point types&lt;/a&gt;, holding reals&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/364x0z75.aspx"&gt;decimal&lt;/a&gt;, holding reals of a smaller range but higher precision&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;See &lt;a href="http://msdn.microsoft.com/en-us/library/3ewxz6et.aspx"&gt;Data Types (C# Reference)&lt;/a&gt; for a complete reference and correspondance between CLR types and C# types.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-7969551950670334885?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/7969551950670334885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=7969551950670334885' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/7969551950670334885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/7969551950670334885'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/06/sql-server-and-net-data-type-mapping.html' title='SQL Server and .Net Data Type mapping'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6142085984384188023</id><published>2008-06-19T15:10:00.003+07:00</published><updated>2008-06-19T15:11:36.338+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Algorithm'/><title type='text'>T-SQL Weighted Round Robin Algorithm</title><content type='html'>In a previous post I was discussing of ways to &lt;a href="http://www.malgreve.net/2008/06/load-balancing-msmq-messages.html"&gt;load balance MSMQ messages&lt;/a&gt; to a group of servers by implementing a &lt;font style="font-style: italic;"&gt;Weighted Round Robin Algorithm&lt;/font&gt; in a software module.&lt;br /&gt;&lt;br /&gt;I chose to implement the load balancing feature in the database for 2 main reasons:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The application is heavily database driven; stored procedures have to run to retrieve the data that will be used to build each MSMQ message. Therefore, the cost of an additional statement or stored procedure to retrieve the MSMQ path the message should be sent to is much less than the existing cost.&lt;/li&gt;&lt;li&gt;All the application configuration information is also database driven. This is because our organization uses custom tools for administrators so that they can configure servers and applications centrally. In the case at hand, they need to be able to modify queue names, machine relative weights as well as to add and remove machines from the load balanced group of server (the cluster).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The Weighted Round Robin algorithm is implemented as a stored procedure returning the next MSMQ path a message should be sent to.  The stored procedure could be bundled or merged with the other stored procedures that have to run before each MSMQ message is sent, so that it would only be one more parameter coming back from the database. This parameter will tell the .Net code to which queue the current MSMQ message build has to be sent to.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;T-SQL Weighted Round Robin Algorithm Implementation.&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Each machine of a cluster should receive a percentage of messages which is relative to its weight:&lt;br /&gt;%age = ((weight of machine) / (sum of weights for all the machines in the cluster)) * 100&lt;br /&gt;Moreover, the distribution of messages to each machine should be function of the weight in real time, not only in average.&lt;br /&gt;&lt;br /&gt;To satisfy these conditions, one way to implement the weighted round robin algorithm and which suits well T-SQL capabilities is to calculate a ratio between the relative number of messages sent to a particular machine of a cluster and the relative weight of that machine within the cluster. The machine having the higher ratio will be the next machine a MSMQ message should be sent to in respect with its relative weight. An ORDER BY clause will easily implement that in T-SQL.&lt;br /&gt;&lt;br /&gt;First of all, we need to create a table where we will hold the different server parameters:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;font style="font-weight: bold;"&gt;Column name&lt;/font&gt;&lt;/td&gt;&lt;td&gt;&lt;font style="font-weight: bold;"&gt;Data type&lt;/font&gt;&lt;/td&gt;&lt;td&gt;&lt;font style="font-weight: bold;"&gt;Purpose&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;server_name&lt;/td&gt;&lt;td&gt;[nvarchar](20)&lt;/td&gt;&lt;td&gt;Machine name&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cluster&lt;/td&gt;&lt;td&gt;[char](10)&lt;/td&gt;&lt;td&gt;Cluster name in which the machine belongs to&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;queue_path&lt;/td&gt;&lt;td&gt;[nvarchar](100)&lt;/td&gt;&lt;td&gt;MSMQ path&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;number_requests_sent&lt;/td&gt;&lt;td&gt;[float]&lt;/td&gt;&lt;td&gt;Number of request sent to this machine so far&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;weight_factor&lt;/td&gt;&lt;td&gt;[float]&lt;/td&gt;&lt;td&gt;Weight factor of this machine&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;enabled_status&lt;/td&gt;&lt;td&gt;[bit]&lt;/td&gt;&lt;td&gt;Says if the machine is active or inactive in the cluster&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Here is the SQL script to create the table:&lt;br /&gt; &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;ANSI_NULLS&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;QUOTED_IDENTIFIER&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;ANSI_PADDING&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;CREATE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;TABLE&lt;/span&gt; [dbo]&lt;span style="color: gray;"&gt;.&lt;/span&gt;[msmq_machines]&lt;span style="color: gray;"&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[server_name] [nvarchar]&lt;span style="color: gray;"&gt;(&lt;/span&gt;20&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[cluster] [char]&lt;span style="color: gray;"&gt;(&lt;/span&gt;10&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[queue_path] [nvarchar]&lt;span style="color: gray;"&gt;(&lt;/span&gt;100&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[number_requests_sent] [float] &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL&lt;/span&gt; &lt;span style="color: blue;"&gt;CONSTRAINT&lt;/span&gt; [DF_msmq_machines_number_requests_sent]&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: blue;"&gt;DEFAULT&lt;/span&gt; &lt;span style="color: gray;"&gt;((&lt;/span&gt;0&lt;span style="color: gray;"&gt;)),&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[weight_factor] [float] &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL&lt;/span&gt; &lt;span style="color: blue;"&gt;CONSTRAINT&lt;/span&gt; [DF_msmq_machines_weight_factor]&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: blue;"&gt;DEFAULT&lt;/span&gt; &lt;span style="color: gray;"&gt;((&lt;/span&gt;100&lt;span style="color: gray;"&gt;)),&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[enabled_status] [bit] &lt;span style="color: gray;"&gt;NOT&lt;/span&gt; &lt;span style="color: gray;"&gt;NULL,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt; &lt;/span&gt;&lt;span style="color: blue;"&gt;CONSTRAINT&lt;/span&gt; [PK_msmq_machines] &lt;span style="color: blue;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color: blue;"&gt;KEY&lt;/span&gt; &lt;span style="color: blue;"&gt;CLUSTERED&lt;/span&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;(&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[server_name] &lt;span style="color: blue;"&gt;ASC&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;[cluster] &lt;span style="color: blue;"&gt;ASC&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;)&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;WITH&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: gray;"&gt;(&lt;/span&gt;&lt;span style="color: blue;"&gt;PAD_INDEX&lt;/span&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: blue;"&gt;OFF&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;/span&gt; &lt;span style="color: blue;"&gt;STATISTICS_NORECOMPUTE&lt;/span&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: blue;"&gt;OFF&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;/span&gt; &lt;span style="color: blue;"&gt;IGNORE_DUP_KEY&lt;/span&gt; &lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: blue;"&gt;OFF&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;/span&gt; &lt;span style="color: blue;"&gt;ALLOW_ROW_LOCKS&lt;/span&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;/span&gt; &lt;span style="color: blue;"&gt;ALLOW_PAGE_LOCKS&lt;/span&gt;&lt;span style=""&gt;  &lt;/span&gt;&lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt;&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt; [PRIMARY]&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;)&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;ON&lt;/span&gt; [PRIMARY]&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;br /&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;ANSI_PADDING&lt;/span&gt; &lt;span style="color: blue;"&gt;OFF&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;br /&gt;&lt;br /&gt;Second we need to create a Stored Procedure that will actually implement the algorithm:&lt;br /&gt;&lt;br /&gt; &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;ANSI_NULLS&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;QUOTED_IDENTIFIER&lt;/span&gt; &lt;span style="color: blue;"&gt;ON&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;GO&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;CREATE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;PROCEDURE&lt;/span&gt; [dbo]&lt;span style="color: gray;"&gt;.&lt;/span&gt;[GetLoadBalancedQueueName]&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;@cluster &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;char&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;10&lt;span style="color: gray;"&gt;),&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;@serverName &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;nvarchar&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;20&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: blue;"&gt;out&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;@queuePath &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;nvarchar&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;100&lt;span style="color: gray;"&gt;)&lt;/span&gt; &lt;span style="color: blue;"&gt;out&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;AS&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;DECLARE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @totalClusterRequestSent &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;float&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;DECLARE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @totalWeight &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;float&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SELECT&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @totalClusterRequestSent &lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: fuchsia;"&gt;sum&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;number_requests_sent&lt;span style="color: gray;"&gt;)+&lt;/span&gt;1&lt;span style="color: gray;"&gt;,&lt;/span&gt; @totalWeight &lt;span style="color: gray;"&gt;=&lt;/span&gt; &lt;span style="color: fuchsia;"&gt;sum&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;weight_factor&lt;span style="color: gray;"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;FROM&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; dbo&lt;span style="color: gray;"&gt;.&lt;/span&gt;msmq_machines&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;WHERE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; cluster &lt;span style="color: gray;"&gt;=&lt;/span&gt; @cluster&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;AND&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; enabled_status &lt;span style="color: gray;"&gt;=&lt;/span&gt; 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SELECT&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;top&lt;/span&gt; 1 @serverName &lt;span style="color: gray;"&gt;=&lt;/span&gt; server_name&lt;span style="color: gray;"&gt;,&lt;/span&gt; @queuePath &lt;span style="color: gray;"&gt;=&lt;/span&gt; queue_path&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;FROM&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; dbo&lt;span style="color: gray;"&gt;.&lt;/span&gt;msmq_machines &lt;span style="color: blue;"&gt;as&lt;/span&gt; A&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;WHERE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; A&lt;span style="color: gray;"&gt;.&lt;/span&gt;cluster &lt;span style="color: gray;"&gt;=&lt;/span&gt; @cluster&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;AND&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; A&lt;span style="color: gray;"&gt;.&lt;/span&gt;enabled_status &lt;span style="color: gray;"&gt;=&lt;/span&gt; 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;order&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; &lt;span style="color: blue;"&gt;by&lt;/span&gt; &lt;span style="color: gray;"&gt;(&lt;/span&gt;number_requests_sent&lt;span style="color: gray;"&gt;/&lt;/span&gt;@totalClusterRequestSent&lt;span style="color: gray;"&gt;)/(&lt;/span&gt;weight_factor&lt;span style="color: gray;"&gt;/&lt;/span&gt;@totalWeight&lt;span style="color: gray;"&gt;),&lt;/span&gt; weight_factor &lt;span style="color: blue;"&gt;desc&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;UPDATE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; dbo&lt;span style="color: gray;"&gt;.&lt;/span&gt;msmq_machines&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;SET&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; number_requests_sent &lt;span style="color: gray;"&gt;=&lt;/span&gt; number_requests_sent &lt;span style="color: gray;"&gt;+&lt;/span&gt; 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;WHERE&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; server_name &lt;span style="color: gray;"&gt;=&lt;/span&gt; @serverName&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: gray;"&gt;AND&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; cluster &lt;span style="color: gray;"&gt;=&lt;/span&gt; @cluster&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note on the T-SQL implementation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In the definition of the table &lt;font style="font-style: italic;"&gt;msmq_machines&lt;/font&gt;, I have chosen data types to be float instead of integers (as they actually will hold only integers values) so that no data type conversion is needed when calculating ratios.&lt;/li&gt;&lt;li&gt;&lt;font style="font-style: italic;"&gt;@totalClusterRequestSent&lt;/font&gt; is calculated as the sum of &lt;font style="font-style: italic;"&gt;number_requests_sent&lt;/font&gt; + 1 so that if the sum of &lt;font style="font-style: italic;"&gt;number_requests_sent&lt;/font&gt; is 0 (zero), no division by zero error occurs.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In addition of this, an SQL job will have to run on a regular basis to re-initialize the &lt;font style="font-style: italic;"&gt;number_requests_sent&lt;/font&gt; column to 0 (zero) so that the value never overflows the data type.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;T-SQL weighted Round Robin algorithm Testing&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;We can test if the algorithm works as expected by creating 3 machines in the msmq_machines table and give them different weights:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/MSMQ_Machines_config_table-721683.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.malgreve.net/uploaded_images/MSMQ_Machines_config_table-721680.jpg" alt="MSMQ Load Balancing Weighted Round Robin Configuration Table" border="0"&gt;&lt;/a&gt;&lt;br /&gt;If we send 100 messages to the cluster “Bangkok”:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DEV1 should receive (100 / 350) * 100 = 28.57 -&gt; 29 messages&lt;/li&gt;&lt;li&gt;DEV2 should receive (200 / 350) * 100 = 57.14 -&gt; 57 messages&lt;/li&gt;&lt;li&gt;DEV3 should receive (50 / 350) * 100 = 14.28 -&gt; 14 messages&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;We can create an SQL script that calls the Stored Procedure 100 times and see if the result is what is expected.&lt;br /&gt;&lt;br /&gt; &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;declare&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @counter &lt;span style="color: blue;"&gt;int&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;set&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @counter &lt;span style="color: gray;"&gt;=&lt;/span&gt; 0&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;while&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt; @counter &lt;span style="color: gray;"&gt;&lt;&lt;/span&gt; 100&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;"&gt;begin&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;span style="color: blue;"&gt;set&lt;/span&gt; @counter &lt;span style="color: gray;"&gt;=&lt;/span&gt; @counter &lt;span style="color: gray;"&gt;+&lt;/span&gt; 1&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;span style="color: blue;"&gt;DECLARE&lt;/span&gt; @server &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;nvarchar&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;20&lt;span style="color: gray;"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;span style="color: blue;"&gt;DECLARE&lt;/span&gt; @msmq &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: blue;"&gt;nvarchar&lt;/span&gt;&lt;span style="color: gray;"&gt;(&lt;/span&gt;100&lt;span style="color: gray;"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;span style="color: blue;"&gt;EXEC&lt;/span&gt; [dbo]&lt;span style="color: gray;"&gt;.&lt;/span&gt;[GetLoadBalancedQueueName] &lt;span style="color: red;"&gt;'Bangkok'&lt;/span&gt; &lt;span style="color: gray;"&gt;,&lt;/span&gt; @serverName &lt;span style="color: gray;"&gt;=&lt;/span&gt; @server &lt;span style="color: blue;"&gt;out&lt;/span&gt;&lt;span style="color: gray;"&gt;,&lt;/span&gt; @queuePath &lt;span style="color: gray;"&gt;=&lt;/span&gt; @msmq &lt;span style="color: blue;"&gt;out&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;; color: blue;" lang="FR"&gt;print&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="FR"&gt; @server&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal;"&gt;&lt;span style="font-size: 10pt; font-family: &amp;quot;Courier New&amp;quot;;" lang="FR"&gt;&lt;span style=""&gt;      &lt;/span&gt;&lt;span style="color: blue;"&gt;print&lt;/span&gt; @msmq&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size: 10pt; line-height: 115%; font-family: &amp;quot;Courier New&amp;quot;; color: blue;" lang="FR"&gt;end&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;br /&gt;Opening the msmq_machines table, we can see that the expected number of messages has been sent to each server of the cluster proving that the implementation works. &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/MSMQ_Machines_config_table_result-749700.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.malgreve.net/uploaded_images/MSMQ_Machines_config_table_result-749697.jpg" alt="MSMQ Load Balancing Weighted Round Robin Configuration Table Result" border="0"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6142085984384188023?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6142085984384188023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6142085984384188023' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6142085984384188023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6142085984384188023'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/06/t-sql-weighted-round-robin-algorithm.html' title='T-SQL Weighted Round Robin Algorithm'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-8667470298014371648</id><published>2008-06-17T14:44:00.003+07:00</published><updated>2008-06-19T15:14:27.774+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MSMQ'/><category scheme='http://www.blogger.com/atom/ns#' term='Load Balancing'/><title type='text'>Load Balancing MSMQ messages</title><content type='html'>I am currently writing a database-driven .Net application which needs to send MSMQ messages load balanced across a &lt;span style="font-weight:bold;"&gt;variable&lt;/span&gt; number of machines.&lt;br /&gt;&lt;br /&gt;The case scenario is the following:&lt;br /&gt;&lt;br /&gt;A server needs to send MSMQ messages to servers A, B and C (we choose 3 MSMQ message recipients for the purpose of this example). The original idea was to put a &lt;span style="font-style:italic;"&gt;network load balancer (NLB)&lt;/span&gt; between the machine sending MSMQ messages and the recipients.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/MSMQLoadBalancer-737181.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/MSMQLoadBalancer-737178.jpg" border="0" alt="MSMQ Messages Load Balancing with Network Load Balancer (NLB)" /&gt;&lt;/a&gt;&lt;br /&gt;If the "MSMQ Sender" machine pictured above sends 75 MSMQ messages, the goal is for machines A, B and C to receive 25 messages each. As we know that a network load balancer distributes load on a connection basis, we were hoping that messages would be load-balanced if the .Net code was creating a new &lt;span style="font-style:italic;"&gt;System.Messaging.MessageQueue&lt;/span&gt; object for each MSMQ messages sent to the NLB. To be more precise, we were hoping that a new connection to the NLB would be created each time we send a MSMQ message with a new instance of the &lt;span style="font-style:italic;"&gt;MessageQueue&lt;/span&gt; object.&lt;br /&gt;&lt;br /&gt;This was pure speculation and a quick test proved that it did not hold; using a simple network load balancer, all the messages were pushed to a single destination server. This happens because connections are re-used within the MSMQ Windows Service, regardless of how the .Net code is written (as a reminder, the .Net class &lt;span style="font-style:italic;"&gt;MessageQueue&lt;/span&gt; is just a wrapper around the MSMQ Windows service).&lt;br /&gt;&lt;br /&gt;Because traffic is load-balanced on a connection basis (not on a message basis) and because the same TCP connection is re-used by the MSMQ service, the NLB forwards all the traffic to the same destination machine. Would the server send 100 MSMQ messages to the NLB, 100 messages would be forwarded to the same target machine as they are all sent using the same underlying TCP connection.&lt;br /&gt;&lt;br /&gt;As we have very little control over the way connections are managed within the MSMQ Windows Service, we had to part away with this simple NLB solution and implement an ad-hoc solution.&lt;br /&gt;We chose to implement the load balancing feature in the .Net application itself. The only addition needed to the existing software is a way to configure it so that it can send MSMQ messages to different queue paths. A simple isolated class, module or piece of code could easily do that. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Server Load Balancing: Algorithms&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Before choosing how to implement the solution, let’s have a look at different ways (algorithms) on how to implement load balancing.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Random Allocation&lt;/span&gt;&lt;br /&gt;In a random allocation, the traffic (MSMQ messages in our case) is assigned to any server picked randomly among the group of destination servers. In such a case, one of the server may be assigned many more requests to process while the other servers are sitting idle. However, on average, each server gets an approximately equal share of the load due to the random selection.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Pros:&lt;/span&gt; Simple to implement.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cons:&lt;/span&gt; Can lead to overloading of one server or more while under-utilization of others.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Round-Robin Allocation&lt;/span&gt;&lt;br /&gt;In a round-robin algorithm, the traffic is sent to the destination server on a rotating basis. The first request is allocated to a server picked randomly from the group of destination server. For subsequent requests, the algorithm follows the circular order destination servers are listed. Once a server is assigned a request, the server is moved to the end of the list and the next server is chosen for the following request. This keeps all the servers equally assigned.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Pros:&lt;/span&gt; Better than random allocation because the requests are equally divided among the available servers in an orderly fashion.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cons:&lt;/span&gt; The round robin algorithm is not good enough for load balancing if technical specification of the servers part of the destination group differs greatly (making that the load each server can handle differs greatly).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Weighted Round-Robin Allocation&lt;/span&gt;&lt;br /&gt;Weighted Round-Robin is an advanced version of the Round-Robin that takes in account server capability. In case of a weighted round-robin, one can assign a weight to each server in the destination group. For example, if the server group consists of 2 servers and that one server is capable of handling twice as much load as the other, the powerful server gets twice the weight factor. In such a case, the application would assign two requests to the powerful server for each request assigned to the weaker one. In effect, a server with more weight will receive load proportionally to their weight factor.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Pros:&lt;/span&gt; Takes care of the capacity of the servers in the group.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Cons:&lt;/span&gt; Does not consider advanced load balancing requirements such as processing time for each individual request.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;We have chosen the Weighted Round Robin algorithm as it is the most advantageous load balancing algorithm to implement easily.&lt;br /&gt;We have chosen to implement the algorithm in T-SQL, but it could be easily implemented in a singleton class in any language such as C# or Java. I will explain why and how in a next blog post: &lt;a href="http://www.malgreve.net/2008/06/t-sql-weighted-round-robin-algorithm.html"&gt;T-SQL Weighted Round Robin Algorithm&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-8667470298014371648?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/8667470298014371648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=8667470298014371648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/8667470298014371648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/8667470298014371648'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/06/load-balancing-msmq-messages.html' title='Load Balancing MSMQ messages'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-1590281662416730789</id><published>2008-05-23T11:54:00.003+07:00</published><updated>2008-05-24T15:14:44.456+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server Performance'/><title type='text'>SQL Server Execution Plan Tutorial</title><content type='html'>Here is a great article written by &lt;a href="http://www.simple-talk.com/sql/performance/execution-plan-basics/"&gt;Grant Fritchey on the basics of analyzing execution plans on SQL Server&lt;/a&gt;. It is actually the first chapter of his book on the topic. Yes, a whole book on SQL Server Execution Plans! I haven’t read the whole book but it should probably reveal itself very interesting for DBAs.&lt;br /&gt;&lt;br /&gt;Most of us are familiar with the graphical representation of execution plans but Grant Fritchey shows us how to also get execution plans in an XML format and how they actually give more information that their graphical counterpart.&lt;br /&gt;&lt;br /&gt;XML executions plans can be saved into files (.sqlplan) and can be viewed either in their XML form or in a graphical form. Being able to save execution plans in a file is very convenient as it makes it easy to share it with DBAs and peers to ask them about their opinion on a slow running query.&lt;br /&gt;&lt;br /&gt;Note that on my machine I actually had to edit the .sqlplan file as the first line of the file was a piece of text reading “Microsoft SQL Server 2005 XML Showplan”. This made that the XML file was not well-formed and so could not be loaded by SQL Server Management Studio - this might be fixed in a later Service Pack or hotfix. Once I removed the line of text, I could successfully open the .sqlplan file in SQL Server Management Studio and see the graphical representation of the execution plan. I could also open the file in a text or XML editor and thus see the execution plan in a textual manner. I think that both approaches can prove themselves being complimentary.&lt;br /&gt;&lt;br /&gt;The article also shows us how to collect XML execution plans through SQL Server 2005’s Profiler tool. Once execution plans are collected from the server they can be analyzed by DBAs and developers. This can reveal very useful when you want to profile and analyze activities on production environment where you can’t play with data as freely as on a development environment.&lt;br /&gt;&lt;br /&gt;For my own sake, I have summarized the introductory materials on the topic hereunder. You might choose to not read it as it is anyway based on the article written by Grant Fritchey.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Execution Plan Introduction.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When you are tuning T-SQL code for performance on SQL Server, the most important information available to you is the &lt;span style="font-weight:bold;"&gt;Execution Plan&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt;. It tells you what kind of JOIN operations and other algorithms are executed as well as what indexes are used. This kind of information will reveal being crucial on poorly performing queries that you need to optimize.&lt;br /&gt;&lt;br /&gt;Please keep in mind that this discussion is focused on DML T-SQL.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;DML&lt;/span&gt; stands for &lt;span style="font-weight:bold;"&gt;Data Manipulation Language&lt;/span&gt; and is aimed at fetching or manipulating data. Basically, it is any SELECT, INSERT, UPDATE and DELETE statement.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;DDL&lt;/span&gt; stands for &lt;span style="font-weight:bold;"&gt;Data Definition Language&lt;/span&gt; and is aimed at defining data structures. Basically, it is any CREATE, DROP and ALTER statement. DDL statements do not need any query optimization because there is always only 1 way to execute those statements. For example, there is only 1 way to create a table or an index.&lt;br /&gt;&lt;br /&gt;When executing a T-SQL query, the T-SQL code is interpreted into instructions understandable by the Database engine. The Database engine is made of multiple processes/sub-engines but 2 are of particular interests regarding &lt;span style="font-style:italic;"&gt;Execution Plans&lt;/span&gt;: the &lt;span style="font-weight:bold;"&gt;Relational Engine&lt;/span&gt; and the &lt;span style="font-weight:bold;"&gt;Storage Engine&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Note that in the context of this text, a &lt;span style="font-style:italic;"&gt;Process&lt;/span&gt; does NOT mean a Windows Process but rather has the more generic meaning of a collection of instructions &lt;span style="font-style:italic;"&gt;processing&lt;/span&gt; some data. It can be seen as a software module or component.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Relational Engine.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style:italic;"&gt;Relational Engine&lt;/span&gt; is responsible for 3 processes which are of interest in our study:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;The Parser&lt;/span&gt;. The Parser receives the T-SQL query as input and outputs a &lt;span style="font-style:italic;"&gt;parse tree&lt;/span&gt; or &lt;span style="font-style:italic;"&gt;query tree&lt;/span&gt;. The &lt;span style="font-style:italic;"&gt;parse tree&lt;/span&gt; represents the logical steps necessary to execute the query.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;The Algebrizer&lt;/span&gt;. The Algebrizer receives the &lt;span style="font-style:italic;"&gt;parse tree&lt;/span&gt; from the Parser process as input and resolves all datatypes, names, aliases and synonyms. The output is binary information called the &lt;span style="font-style:italic;"&gt;query processor tree&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;The Query Optimizer&lt;/span&gt;. The query optimizer is a piece of software that models the way in which the database relational engine works. Using the &lt;span style="font-style:italic;"&gt;query processor tree&lt;/span&gt; together with the &lt;span style="font-weight:bold;"&gt;statistics&lt;/span&gt; it has about the data and applying the model, the Query Optimizer works out heuristically what it thinks will be the optimal way to execute the query – that is, it generates an optimized &lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;estimated execution plan&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The Storage Engine.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Storage Engine will execute the &lt;span style="font-style:italic;"&gt;estimated execution plan&lt;/span&gt; &lt;span style="font-weight:bold;"&gt;except&lt;/span&gt; if it judges that it should be modified. It could be the case if:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;span style="font-style:italic;"&gt;estimated execution plan&lt;/span&gt; exceeds the threshold for parallel execution.&lt;/li&gt;&lt;li&gt;The &lt;span style="font-style:italic;"&gt;statistics&lt;/span&gt; used to generate the plan are out of date.&lt;/li&gt;&lt;li&gt;The estimated execution plan is &lt;span style="font-style:italic;"&gt;invalid&lt;/span&gt; (for example it creates temp table and so contains DDL statement)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The final execution plan, called the &lt;span style="font-weight:bold;"&gt;actual execution plan&lt;span style="font-style:italic;"&gt;&lt;/span&gt;&lt;/span&gt; is what is actually executed by the Storage Engine. It might or might not be the same as the &lt;span style="font-style:italic;"&gt;estimated execution plan&lt;/span&gt;.&lt;br /&gt;Note that generally, there won't be any differences between the esti¬mated and actual execution plans.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Execution Plan Cache.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As it is expensive for the Server to generate execution plans, SQL Server will keep and reuse plans wherever possible. As they are created, plans are stored in a section of memory called the &lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;Plan Cache&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Once the &lt;span style="font-style:italic;"&gt;estimated execution plan&lt;/span&gt; is created, and before it gets passed to the storage engine, the optimizer compares this estimated plan to &lt;span style="font-style:italic;"&gt;actual execution plans&lt;/span&gt; that already exist in the &lt;span style="font-style:italic;"&gt;Plan Cache&lt;/span&gt;. This reuse avoids the overhead of creating actual execution plans. This is obviously beneficial for large and complex queries but also for simple queries which could potentially be called very often (hundreds or thousands of time).&lt;br /&gt;&lt;br /&gt;Execution Plans can be removed from the cache in the following scenarios:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Memory is required by the system.&lt;/li&gt;&lt;li&gt;The "age" of the plan (its time-to-live) has reached zero.&lt;/li&gt;&lt;li&gt;The plan isn't currently being referenced by an existing connection.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Also, cached execution plans might not be reused if an execution plan needs to be recompiled. Certain events and actions can cause a plan to be recompiled. Grant Fritchey enumerates those events in his article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-1590281662416730789?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/1590281662416730789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=1590281662416730789' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/1590281662416730789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/1590281662416730789'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/05/sql-server-execution-plan-tutorial.html' title='SQL Server Execution Plan Tutorial'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4133517930723723030</id><published>2008-05-06T22:15:00.003+07:00</published><updated>2008-05-06T23:53:49.025+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008'/><title type='text'>New Features in Visual Studio 2008</title><content type='html'>In this post I will go through some Visual Studio 2008 tools and features I found interesting.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Unit Test Tool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In VS 2008, Unit Testing is facilitated through a unit test class code generator.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Unit Testing is the act of having a piece of code which only purpose is to test another piece of code, this code being part of the end product&lt;/span&gt;. It is a particularly tedious task, so having a unit test code generator is very handy.&lt;br /&gt;&lt;br /&gt;A Unit Test class is used to test a class that is part of the software being built. If every classes of a software has a matching class used to unit test it, all the code will be unit tested. Unit testing is the lowest level of Quality Assurance, it does not test the software as a whole neither on its external functionalities but rather makes sure that any testable piece of code part of the software is behaving as it should.&lt;br /&gt;&lt;br /&gt;You should consider doing Unit Testing as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It creates test units to check if the code is producing expected results.&lt;/li&gt;&lt;li&gt;It improves code coverage. Code coverage is a number telling how many percent of the code has actually been tested. The higher value the more confident we can be in the quality of the code (as it means that a large part of the code returns expected values).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;To generate a Unit Test class in VS 20008, simply right-click on any class definition and select the &lt;span style="font-style:italic;"&gt;Create Unit Tests&lt;/span&gt; option to call the unit test generator tool.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Create_Unit_Test-718982.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Create_Unit_Test-718979.jpg" border="0" alt="Visual Studio 2008 - Create Unit Test Class" /&gt;&lt;/a&gt;&lt;br /&gt;This will create a Unit Test class in a separated project dedicated for Unit Testing, this way your Unit Test code and the actual code are separated in different projects and so code is neatly kept separated.&lt;br /&gt;&lt;br /&gt;Note that if you try to generate a Unit Test Class for a class that has private or internal modifiers, VS2008 will add a special &lt;span style="font-style:italic;"&gt;InternalsVisibleTo&lt;/span&gt; attribute in your original project so that your Unit Test project (and only that one) has access to all private, internal and protected methods and classes of the original &lt;span style="font-weight:bold;"&gt;project&lt;/span&gt; containing the classes you want to unit test. This means that the attribute is not added at the class level but at the project level in the AssemblyInfo.cs file.&lt;br /&gt;&lt;br /&gt;Moreover, as it can be seen hereunder, only the Unit Test project (here called CalculatorTest) will have access to internal classes and methods:&lt;br /&gt;&lt;br /&gt;[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("CalculatorTest")]&lt;br /&gt;&lt;br /&gt;Once the Unit Test classes are generated, you will have to go into them, inspect the code and set input values that will be used to call the methods that need to be tested and also set the expected result value that should be returned by the method. This way, the actual value returned can be compared with the expected value to decide if the test was conclusive or not. There are TODO sections declared in the generated code so that you can easily locate where to set test values.&lt;br /&gt;&lt;br /&gt;In the example hereunder, values are set for the length and width of the rectangle and the variable expected contains the pre-calculated area of the rectangle so that we can check if the output of the method is equal to what should be returned. If the value returned by the method is not what is expected, that means that the unit test fail and that there is a bug in the tested method. Visual Studio will clearly show in the test results what unit test succeeded or failed.&lt;br /&gt;&lt;br /&gt;Lastly, do not forget to comment out the Assert.Inconclusive() method call.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Initialize_value_Unit_Test_Class-795088.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Initialize_value_Unit_Test_Class-795085.jpg" border="0" alt="Visual Studio 2008 - Initialize parameter values for Unit Test" /&gt;&lt;/a&gt;&lt;br /&gt;The Test project creates a &lt;span style="font-style:italic;"&gt;vsmdi&lt;/span&gt; file in the solution item folder, named after the solution name, &lt;span style="font-style:italic;"&gt;Calculator.vsdmi&lt;/span&gt; for a Visual Studio solution called &lt;span style="font-style:italic;"&gt;Calculator&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;To actually test some or all the unit test methods, open the &lt;span style="font-style:italic;"&gt;vsdmi&lt;/span&gt; file, select the methods that you want to test, right-click on the list of methods and select &lt;span style="font-style:italic;"&gt;Run Checked Tests&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Chose_Unit_Test_Method-764641.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Chose_Unit_Test_Method-764638.jpg" border="0" alt="Visual Studio 2008 - Choose Method To Unit Test" /&gt;&lt;/a&gt;&lt;br /&gt;Once the test ran, the result will be displayed showing if the test succeeded, failed or was inconclusive.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Unit_Test_Result-780270.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Unit_Test_Result-780268.jpg" border="0" alt="Visual Studio 2008 - Unit Test Result Window" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Object Test Bench&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you do not have the time to create full blown Unit Test but still want to test some of your classes and/or methods, there is a quick and dirty way to do it by using the Object Test Bench tool. The tool can call static methods on classes and create object instances of classes so that instance methods can be called ad-hoc. Methods can thus be tested very simply, in a similar way as when you chose to execute a Stored Procedure in SQL Server Management Studio and that a window pops up to let you input the SP parameters.&lt;br /&gt;&lt;br /&gt;To use the Object Test Bench, you need first to create Class Diagram of your project. To do so, click on the Class View of your Visual Studio project, select the root namespace of your project, right-click on it and choose the &lt;span style="font-style:italic;"&gt;View Class Diagram&lt;/span&gt; option.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Create_Class_Diagram-762838.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Create_Class_Diagram-762832.jpg" border="0" alt="Visual Studio 2008 - Generate Class Diagram From Source Code" /&gt;&lt;/a&gt;&lt;br /&gt;Once the class diagram is created you can call the Object Test Bench tool by either calling a static method on the class or one of the class constructor so that you will be able to call an instance methods after the object is instanciated.&lt;br /&gt;&lt;br /&gt;In my case I want to test the Add() method to check if my Calculator object correctly adds numbers. To do so I first instanciate a Calculator object which opens the &lt;span style="font-style:italic;"&gt;Object Test Bench&lt;/span&gt; window under the class diagram. After the object is created in memory and appears in the Object Test Bench window, I can chose to call any method of the object. I will thus dynamically call the Add() method through the Visual Studio IDE and check if the method returns a correct result.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Class_Diagram_Start_Object_Test_Bench-750499.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Class_Diagram_Start_Object_Test_Bench-750492.jpg" border="0" alt="Visual Studio 2008 - Start Object Test Bench Tool - Create Object Instance" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench-772719.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench-772717.jpg" border="0" alt="Visual Studio 2008 - Start Object Test Bench Window" /&gt;&lt;/a&gt;&lt;br /&gt;A window will pop up so that you can give values to the input parameters.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench_Call_Method_Input_Parameter-744118.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench_Call_Method_Input_Parameter-744116.jpg" border="0" alt="Visual Studio 2008 - Object Test Bench Invoke Method And Set Input Parameters" /&gt;&lt;/a&gt;&lt;br /&gt;Once the parameters are entered and you click on OK, a pop up window will display the result. You can choose to save the result in a variable so that you can re-use it later. For example you could re-use the variable as a parameter to call another method that you want to test-bench. This way, in a few clicks, you can create a bunch of objects and then re-use them later to call methods that take complex-type objects as parameter.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench_Call_Method_Result-722417.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Object_Test_Bench_Call_Method_Result-722414.jpg" border="0" alt="Visual Studio 2008 - Object Test Bench Invoke Method Result Window" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. Generate Method Stub (only for C#)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is a code generation feature that creates methods before they exist; the method created is based on the call to that method. Once the call to the method is made, Visual Studio 2008 IntelliSense will give you the option to generate a method stub matching the call to that method, with the matching input parameters and return type.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Generate_Method_Stub-734561.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Generate_Method_Stub-734556.jpg" border="0" alt="Visual Studio 2008 - Generate Method Stub" /&gt;&lt;/a&gt;&lt;br /&gt;The generated method will be created in the matching class and its stub implementation will simply throw a &lt;span style="font-style:italic;"&gt;NotImplementedException&lt;/span&gt;.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Generate_Method_Stub_Generated-734586.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Generate_Method_Stub_Generated-734583.jpg" border="0" alt="Visual Studio 2008 - Generate Method Stub Result" /&gt;&lt;/a&gt;&lt;br /&gt;Note that this code generation feature is only available for C#.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. Refactoring Tools (C# only)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Refactoring is making changes to a body of code in order to improve its internal structure without changing its external behavior.&lt;/blockquote&gt;&lt;br /&gt; - Martin Fowler&lt;br /&gt;&lt;br /&gt;It is useful concept to make code cleaner and more understandable/readable.&lt;br /&gt;&lt;br /&gt;A typical refactoring case is to break up a lengthy method into separate methods. To do so, you can highlight a piece of a code, right-click on it (or go to the Refactor menu of Visual Studio) and choose &lt;span style="font-style:italic;"&gt;Extract Method&lt;/span&gt;.  This will generate a method containing the highlighted code as well as calling the generated method from the original location.&lt;br /&gt;&lt;br /&gt;Refactor menu in Visual Studio 2008:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Refactoring-790824.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Refactoring-790819.jpg" border="0" alt="Visual Studio 2008 - Refactor Menu" /&gt;&lt;/a&gt;&lt;br /&gt;Refactoring code by creating a method to shorten the original code, it is the action of &lt;span style="font-weight:bold;"&gt;extracting a method&lt;/span&gt; from a piece of code.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Refactoring_method-733217.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Refactoring_method-733213.jpg" border="0" alt="Visual Studio 2008 - Refactoring A Method" /&gt;&lt;/a&gt;&lt;br /&gt;The example here above will create a method containing the highlighted code and replace the original code by a call to the generated method (which I called &lt;span style="font-style:italic;"&gt;WriteLogToConsole&lt;/span&gt;):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Refactoring_method_result-784248.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Refactoring_method_result-784221.jpg" border="0" alt="Visual Studio 2008 - Refactoring, Generated Method" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5. The .Net Framework Source Code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is possible to go through the source code of the .Net Framework while debugging. Here are the steps I did to make it work:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1.&lt;/span&gt; Install the &lt;a href="http://support.microsoft.com/kb/944899"&gt;hotfix KB 944899 - Visual Studio 2008 performance decreases when you step through source code that you downloaded from Reference Source Server&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2.&lt;/span&gt; Configure Visual Studio debugger to be able to step in the .Net Framework Source Code:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Uncheck Enable Just My Code (Managed only).&lt;/li&gt;&lt;li&gt;Check Enable source server support.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Config_VS_For_Framework_Source_Code_Debugging-778079.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Config_VS_For_Framework_Source_Code_Debugging-778076.jpg" border="0" alt="Visual Studio 2008 - Configuring Visual Studio For Framework Source Code Debugging" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3.&lt;/span&gt; Configure the Symbols part of the Visual Studio debugger options so that Visual Studio know where to download the .Net Framework debugging symbol (.pdb files) and source code.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Set the &lt;span style="font-style:italic;"&gt;Symbol file (.pdb) location&lt;/span&gt; to be: http://referencesource.microsoft.com/symbols&lt;/li&gt;&lt;li&gt;Set a &lt;span style="font-style:italic;"&gt;Cache location&lt;/span&gt; folder where the .Net Framework pdb and source code files will be stored.  Make sure it is a location that your account has read/write access to. For example, a folder under your user hive.&lt;/li&gt;&lt;li&gt;Clear the &lt;span style="font-style:italic;"&gt;Search the above locations only when symbols are loaded manually&lt;/span&gt; if you want that Visual Studio automatically download symbols and source code while you step in .Net Framework code (F11 shortcut key). Note that if your project is big and references many libraries, downloading all the debugging symbols will be slow at the first debug. If you prefer to load symbols only when needed, keep that box checked. You will then have to download debugging symbols and source code on demand by right-clicking the appropriate dll in the stacktrace and choose &lt;span style="font-style:italic;"&gt;Load Symbol&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Here is how I configured my Visual Studio:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Config_VS_For_Framework_Source_Code_Access-738292.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Config_VS_For_Framework_Source_Code_Access-738287.jpg" border="0" alt="Visual Studio 2008 - Configuring Visual Studio Framework Source Code Symbol Location" /&gt;&lt;/a&gt;&lt;br /&gt;Visual Studio 2008 is now all set to debug and step in .Net Framework Source Code!&lt;br /&gt;&lt;br /&gt;While debugging, we can now see that the debugger call stack contains detailed file and line number information for the .NET Framework classes and methods:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Debugger_Call_Stack-785022.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Debugger_Call_Stack-785019.jpg" border="0" alt="Visual Studio 2008 - Debugger Call Stack" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Example of use:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the following screenshot, I stepped in a line of code that calls the ToString() method on a Double type, this makes that the mscorlib pdb file is downloaded as well as the source code for the Double structure so that I can actually debug into the Double type and see its implementation as written by the .Net team. That is something I find really cool and I think has been missing for a long time!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Step_In_Framework_Source_Code-727353.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Step_In_Framework_Source_Code-727350.jpg" border="0" alt="Visual Studio 2008 - Step In .Net Framework Source Code" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Modules Window:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;While&lt;/span&gt; you are debugging, you can bring up the &lt;span style="font-style:italic;"&gt;Modules&lt;/span&gt; Wwndow by hitting the &lt;span style="font-style:italic;"&gt;ALT+CTRL+U&lt;/span&gt; keys. This window shows all the dll loaded by the debugger and let you see which dll has debug information loaded and which does not. You can manually load debugging symbols from that window by right clicking on the library you want to load the symbols for and select the &lt;span style="font-style:italic;"&gt;Load Symbols&lt;/span&gt; option.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/VS2008_Modules_Debugging_Window-789534.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/VS2008_Modules_Debugging_Window-789529.jpg" border="0" alt="Visual Studio 2008 - Debugger Modules Window" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;List of assemblies currently available at the time of writing for symbol/source loading:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mscorlib.dll&lt;/li&gt;&lt;li&gt;System.dll&lt;/li&gt;&lt;li&gt;System.Data.dll&lt;/li&gt;&lt;li&gt;System.Drawing.dll&lt;/li&gt;&lt;li&gt;System.Web.dll&lt;/li&gt;&lt;li&gt;System.Web.Extensions.dll&lt;/li&gt;&lt;li&gt;System.Windows.Forms.dll&lt;/li&gt;&lt;li&gt;System.XML.dll&lt;/li&gt;&lt;li&gt;WPF (UIAutomation*.dll, System.Windows.dll, System.Printing.dll, System.Speech.dll, WindowsBase.dll, WindowsFormsIntegration.dll, Presentation*.dll, some others)&lt;/li&gt;&lt;li&gt; Microsoft.VisualBasic.dll&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For reference, here is a lengthier blog post by &lt;a href="http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code.aspx"&gt;Shawn Burke&lt;/a&gt; with more information regarding .Net Framework Source Code debugging.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;6. SQL Metal&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;SQL Metal is used to help implementing LINQ to SQL scenarios. It is a command-line utility (sqlmetal.exe).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;SQL Metal can:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Generate source code and mapping attributes or a mapping file from a database.&lt;/li&gt;&lt;li&gt;Generate an intermediate database markup language file (.dbml) for customization from a database.&lt;/li&gt;&lt;li&gt;Generate code and mapping attributes or a mapping file from a .dbml file.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;What is a mapping file?&lt;/span&gt;&lt;br /&gt;A mapping file is an XML file to specify mapping between the data model of the database and the object model of the .Net code. It keeps the mapping code out of the application code which helps in keeping the code cleaner and leaner. Moreover, since it is XML (like any other .config file) it can be changed without having to rebuild the application code.&lt;br /&gt;&lt;br /&gt;Check out MSDN documentation for more information about &lt;a href="http://msdn2.microsoft.com/en-us/library/bb386987.aspx"&gt;SQLMetal&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;7. Visual Studio 2008 Product Comparison&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Great comparison between the different functionalities available on each edition of Visual Studio 2008.&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/vstudio/products/cc149003.aspx"&gt;http://msdn2.microsoft.com/en-us/vstudio/products/cc149003.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4133517930723723030?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4133517930723723030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4133517930723723030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4133517930723723030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4133517930723723030'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/05/new-features-in-visual-studio-2008.html' title='New Features in Visual Studio 2008'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-2479465767308559251</id><published>2008-04-10T11:32:00.012+07:00</published><updated>2008-04-10T16:33:06.522+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006 Architecture'/><title type='text'>Promoted property vs distinguished field - tutorial</title><content type='html'>&lt;span style="font-style:italic;"&gt;First of all while many people talk about &lt;span style="font-weight:bold;"&gt;Promoted Property&lt;/span&gt;, the official term is &lt;span style="font-weight:bold;"&gt;Promoted Field&lt;/span&gt;&lt;/span&gt;, as defined in the MSDN documentation and also visible in Visual Studio’s BizTalk Schema Editor. I will nevertheless keep using the term most people are familiar with but I will consider both terms as synonyms.&lt;br /&gt;&lt;br /&gt;Part 1 &amp; 2 is a tutorial on how to create promoted properties and distinguished fields through the Schema Editor and the BizTalk’s API while part 3 is discussing about performance and differences between Promoted Properties and Distinguished Fields. You might only be interested in the 3rd part of this article if you already are a seasoned BizTalk developer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. Promoted Properties (Promoted Fields)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1.1 What are Promoted Properties?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Promoted Properties are Message Context Properties that are flagged as promoted&lt;/span&gt;; being promoted it allows the Message Engine to route messages based on their value, and being in the message context allows doing so without having to look at the message payload (which would be an expensive operation). Promoted Properties are the most common way to enable content-based routing. They are available to the pipelines, adapters, Message Bus and orchestrations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Promoted Fields (= Promoted Properties) are PROMOTED in the message context by the receive pipeline when a message is received on a port. It is usually the job of the disassembler pipeline component such as the XML and Flat File disassembler but any custom pipeline component can also do it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1.2 How to promote properties?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As stated in a previous post I wrote, &lt;a href="http://www.malgreve.net/2008/03/biztalk-messaging-architecture.html"&gt;BizTalk Messaging Architecture&lt;/a&gt;, &lt;span style="font-style:italic;"&gt;message context properties&lt;/span&gt; are defined within a &lt;span style="font-style:italic;"&gt;property schema&lt;/span&gt; and so all promoted properties must be defined in a &lt;span style="font-style:italic;"&gt;custom property schema&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;The action of promoting a message element to a promoted property creates a message context property that will contain the message element value and flags it as promoted so that it is available for routing.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are 2 ways to promote a message element:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;1. Quick promotion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Quick promotion is the simplest way to create a promoted property. Simply right click on the element’s node and choose &lt;span style="font-style:italic;"&gt;Quick Promotion&lt;/span&gt; (see Fig 1.1). When choosing this option, Visual Studio will create a property schema called &lt;span style="font-style:italic;"&gt;PropertySchema.xsd&lt;/span&gt; and add in the message’s schema a reference to the generated property schema.&lt;br /&gt;&lt;br /&gt;Each property promoted this way will create a corresponding element in the property schema with the same name and type as defined in the message’s schema.&lt;br /&gt;&lt;br /&gt;This means that when using quick promotion, the promoted property element name will always be the same as the message’s element name. If you have several elements with the same name, you might want to use manual promotion instead to avoid confusion or avoid having a property value overridden.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/Quick_Promotion-725596.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/Quick_Promotion-725593.jpg" border="0" alt="Biztalk promoted properties - quick promotion" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig. 1.1 Quick Promotion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;2. Manual Promotion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To manually promote a property, a property schema must be created with the elements that will hold the promoted property values. To create a property schema, you need to add a new item in your BizTalk solution, and chose &lt;span style="font-style:italic;"&gt;Property Schema&lt;/span&gt; as the type of file (see Fig. 1.2). Once all the elements are created in the property schema, you associate the property schema with the message’s schema by right clicking on any node of the message schema and choose &lt;span style="font-style:italic;"&gt;Show Promotions&lt;/span&gt; (see Fig. 1.3), then click on the &lt;span style="font-style:italic;"&gt;Property Fields&lt;/span&gt; tab, click on the &lt;span style="font-style:italic;"&gt;folder icon&lt;/span&gt; and finally select the property schema you just created (see Fig. 1.4). Note that it is actually possible to use more than 1 property schema per message. Anyhow, all promoted properties will end up being written in the message context and available for all BizTalk artifacts having access to message context.&lt;br /&gt;&lt;br /&gt;Once the property schema is picked, you can start promoting message elements as promoted properties. To do so, click a message element and click on the &lt;span style="font-style:italic;"&gt;add&lt;/span&gt; button, the &lt;span style="font-style:italic;"&gt;Node Path&lt;/span&gt; column will display the XPath to the message element you are promoting and the &lt;span style="font-style:italic;"&gt;Property&lt;/span&gt; column let you chose the promoted property that will contain the value of the message element at runtime (see Fig. 1.5).&lt;br /&gt;&lt;br /&gt;An interesting side effect is that Manual Promotion let you have promoted properties with different names that the original message element name. This might be useful when a same property schema is used to hold promoted properties from different message types or when a message has different element with the same name.&lt;br /&gt;&lt;br /&gt;Using Manual Promotion, it is also possible to promote message elements to promoted properties in the system property schemas shipped with BizTalk. To do so, just browse in the &lt;span style="font-style:italic;"&gt;References&lt;/span&gt; sub-tree when picking the property schema (see Fig. 1.4).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/create_property_schema-790031.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/create_property_schema-790028.jpg" border="0" alt="BizTalk - Create a property schema" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig. 1.2 Manually create a custom property schema&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/manual_promotion-776038.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/manual_promotion-776036.jpg" border="0" alt="BizTalk - Promoted Properties, manual promotion" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig. 1.3 Manual Promotion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/manual_promotion_selecting_property_schema-777881.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/manual_promotion_selecting_property_schema-777869.jpg" border="0" alt="BizTalk - Promoted Properties, selecting a Property Schema" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig. 1.4 Selecting a Property Schema&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/manual_promotion_selecting_promoted_property-788151.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/manual_promotion_selecting_promoted_property-788141.jpg" border="0" alt="BizTalk - Promoted Properties, selecting the promoted property" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig. 1.5 Selecting the message element to promote and the promoted property that will contain the message element’s value.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1.3 How to promote properties through the BizTalk API?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I already said in a previous post, &lt;a href="http://www.malgreve.net/2008/03/biztalk-messaging-architecture.html"&gt;BizTalk Messaging Architecture&lt;/a&gt;, context properties are stored in a property bag, an object which implements the &lt;span style="font-style:italic;"&gt;IBaseMessageContext&lt;/span&gt; interface. This interface contains 2 methods which take the same parameters (a property name, an XML namespace, and value for the property).&lt;br /&gt;&lt;br /&gt;a. The &lt;span style="font-weight:bold;"&gt;Write()&lt;/span&gt; method is used to write the property value into the message context without actually promoting it. It can be used to write distinguished fields or to write transient values. Calling the Write() method is &lt;span style="font-weight:bold;"&gt;NOT promoting&lt;/span&gt; a property, it is &lt;span style="font-weight:bold;"&gt;writing&lt;/span&gt; a property.&lt;br /&gt;&lt;br /&gt;b. The &lt;span style="font-weight:bold;"&gt;Promote()&lt;/span&gt; method is used to write the property value into the message context but also flags the property as promoted so that it is available for routing. This is the method that needs to be called to &lt;span style="font-weight:bold;"&gt;promote&lt;/span&gt; a property.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;To promote a property through the API, element name and namespace passed as parameter of the Promote() method &lt;span style="font-weight:bold;"&gt;must&lt;/span&gt; be those of the property defined in the property schema.&lt;/span&gt; They are most easily accessed by referencing the property schema assembly and using the properties on the class created for the property.&lt;br /&gt;&lt;br /&gt;Example of promoting a property through an API call (copied from the BizTalk 2006 MSDN documentation: &lt;a href="http://msdn2.microsoft.com/en-us/library/aa561650.aspx"&gt;Processing the Message&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier"&gt;//create an instance of the property to be promoted&lt;br /&gt;SOAP.MethodName methodName = new SOAP.MethodName();&lt;br /&gt;&lt;br /&gt;//call the promote method on the context using the property class for name and namespace&lt;br /&gt;pInMsg.Context.Promote(methodName.Name.Name, methodName.Name.Namespace, &lt;br /&gt;"theSOAPMethodName");&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As I mentioned before, it is possible to promote properties to the BizTalk system property schema using Manual Promotion in Visual Studio’s Schema Editor for BizTalk. It is possible to achieve the same programmatically and as for other promotion, the name and namespace passed in parameter of the Promote() method is the one of the promoted property in the property schema, the system property schema namespace in this case.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier"&gt;//BizTalk system properties namespace&lt;br /&gt;private const string BTSSystemPropertiesNamespace = “http://schemas.microsoft.com/BizTalk/2003/system-properties”;&lt;br /&gt;&lt;br /&gt;//Promote the MessageType property&lt;br /&gt;string messageType = "http://" + "schemas.abc.com/BizTalk/" + "#" + "Request";&lt;br /&gt;message.Context.Promote("MessageType", BTSSystemPropertiesNamespace, messageType);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. Distinguished fields&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2.1. What are distinguished fields?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Distinguished fields are message elements that are written into the message context. They differ with promoted properties in 2 main aspects:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;They are not flagged as promoted in the message context and so are not available for routing by the Messaging Engine (adapters, pipeline…). Their typical use is instead for the orchestration engine.&lt;/li&gt;&lt;li&gt;They are not defined using a property schema.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Distinguished Fields are WRITTEN in the message context by the pipeline when a message is received on a port. It is usually the job of the disassembler pipeline component such as the XML and Flat File disassembler but any custom pipeline component can also do it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Distinguished fields are useful when a message element value needs to be accessed from an orchestration. Instead of having the orchestration engine search through the message to evaluate an XPath expression (which can be resource-intensive on a large message), a distinguished field can be used. Distinguished fields are populated in the message context when the message is first loaded. Consequently, each time the distinguished field needs to be accessed, the orchestration engine will directly read it from the message context (a property bag object) instead of searching for the original value in the message with XPath. Needless to say that retrieving a single value from a property bag object is much faster than evaluating an XPath expression.&lt;br /&gt;&lt;br /&gt;Distinguished fields also offer IntelliSense in the orchestration expression editor which enhances code readability.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2.1 How to create a distinguished field?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The main source of confusion between distinguished fields and promoted properties is that they are both created in Visual Studio’s Schema Editor through the &lt;span style="font-style:italic;"&gt;Promote -&gt; Show Promotions&lt;/span&gt; contextual menu option of a message schema’s element.  Once the dialog box is open, make sure that you are on the &lt;span style="font-style:italic;"&gt;Distinguished Field&lt;/span&gt; tab, select the message elements and click the &lt;span style="font-style:italic;"&gt;Add&amp;gt;&amp;gt;&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;&amp;lt;&amp;lt;Remove&lt;/span&gt; buttons to add and remove distinguished fields (see Fig 2.1).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/create_distinguished_fields-770216.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/create_distinguished_fields-770214.jpg" border="0" alt="BizTalk - Creating Distinguished Fields" /&gt;&lt;/a&gt;&lt;span style="font-style:italic;"&gt;Fig 2.1 Creating a Distinguished Field.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2.2 How to create a distinguished field through the BizTalk API.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Distinguished fields are written into the context using the &lt;span style="font-weight:bold;"&gt;Write()&lt;/span&gt; method on the &lt;span style="font-style:italic;"&gt;IBaseMessageContext&lt;/span&gt; object. To be recognized as a distinguished field, the namespace of the property must be &lt;span style="font-style:italic;"&gt;“http://schemas.microsoft.com/BizTalk/2003/btsDistinguishedFields”&lt;/span&gt;. Pipeline components delivered with BizTalk do not use those context properties. It is nevertheless possible to read/write distinguished field in the code of custom pipelines, as for any other context properties.&lt;br /&gt;&lt;br /&gt;Example of writing a distinguished field through an API call (taken from the BizTalk 2006 MSDN documentation: &lt;a href="http://msdn2.microsoft.com/en-us/library/aa561650.aspx"&gt;Processing the Message&lt;/a&gt;).&lt;br /&gt;&lt;span style="font-family:courier"&gt;//write a distinguished field to the context&lt;br /&gt;pInMsg.Context.Write("theDistinguishedProperty", &lt;br /&gt;"http://schemas.microsoft.com/BizTalk/2003/btsDistinguishedFields", &lt;br /&gt;"theDistinguishedValue");&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Would you use another namespace, it will result in writing a plain transient value in the property bag and won’t be recognized as a distinguished field by the orchestration engine.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier"&gt;//Write a transient value to the message context&lt;br /&gt;message.Context.Write("MyVariable", "SomeNameSpace", SomeData);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3. Considerations, similarities and differences between promoted properties and distinguished fields.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3.1 Performance considerations:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Promoted properties are limited to 255 characters for routing performance reasons. Properties that are simply written in the context (such as distinguished fields) are not limited in size but large properties decrease performance.&lt;/li&gt;&lt;li&gt;All Context properties (both Promoted and Distinguished Fields) are stored separately from the message in the Message Box Database. Consequently consuming more space in the BizTalk databases but more importantly incurs more load when persisting/reloading the message in/from the DB. Note that if tracking is turned on, Promoted Properties are also stored in the Tracking database.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Distinguished Fields cost less than Promoted Properties in terms of performance.&lt;/span&gt; Both Promoted and Distinguished Fields require the same overhead of writing their values to the context Field bag in the Message Box database, but Promoted Fields have the additional overhead of being written in BOTH to the Message Box context tables AND the subscription tables. Distinguished fields are not stored in the subscription table as they do not participate in routing.&lt;br /&gt;Promoted Fields have an impact every time a message is written in the Message Box because each Promoted Property that exists must be evaluated in a massive T-SQL &lt;span style="font-weight:bold;"&gt;union &lt;/span&gt;statement that builds the list of matching activation subscriptions. &lt;span style="font-weight:bold;"&gt;In short, the more Promoted Fields you have the more costly the subscription process is.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3.2 Other considerations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Both promoted properties and distinguished fields are populated when a &lt;span style="font-style:italic;"&gt;Pipeline Disassembler Component&lt;/span&gt; parses a message and either &lt;span style="font-style:italic;"&gt;Promotes&lt;/span&gt; or &lt;span style="font-style:italic;"&gt;Writes&lt;/span&gt; the value to the message’s context.&lt;/li&gt;&lt;li&gt;Empty pipelines such as the Pass-through pipeline do not promote or write anything in the message context as it lacks a disassembler component.&lt;/li&gt;&lt;li&gt;Writing a value into the context with the same name and namespace that were used previously to promote a property causes that property to no longer be promoted. The write essentially overwrites the promotion.&lt;/li&gt;&lt;li&gt;Writing a property in the context having a null value deletes the context property altogether because null-valued properties are not permitted.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3.3 Distinguished and Property Fields Difference Summary.&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Promoted Fields should be used for routing, correlation and/or tracking.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Distinguished fields should be used when a particular message element is commonly manipulated in one or more orchestration.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Here is a table outlining the main differences between both types of fields:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;Promoted Fields (aka Promoted Properties)&lt;/th&gt;&lt;th&gt;Distinguished Fields&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Used for routing (subscription mechanism)&lt;br /&gt;IsPromoted = true&lt;/td&gt;&lt;td&gt;Do not participate in routing&lt;br /&gt;IsPromoted = false&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Used for tracking&lt;/td&gt;&lt;td&gt;Not used for tracking&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Restricted to 255 characters&lt;/td&gt;&lt;td&gt;No size limitation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Available for use in orchestrations&lt;/td&gt;&lt;td&gt;Available for use in orchestrations&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Require property schema&lt;/td&gt;&lt;td&gt;Do not require property schema&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Used by standard pipeline components&lt;/td&gt;&lt;td&gt;Accessible only by custom pipeline component which would explicitly access them&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4. References.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MSDN - &lt;a href="http://msdn2.microsoft.com/en-us/library/aa560436.aspx"&gt;The BizTalk Server Message&lt;/a&gt;&lt;br /&gt;MSDN - &lt;a href="http://msdn2.microsoft.com/en-us/library/aa561650.aspx"&gt;Processing the Message&lt;/a&gt;&lt;br /&gt;MSDN - &lt;a href="http://msdn2.microsoft.com/en-us/library/aa578366.aspx"&gt;About BizTalk Message Context Properties&lt;/a&gt;&lt;br /&gt;Neudesic's blog - &lt;a href="http://blogs.neudesic.com/blogs/enterprise_integration/archive/2007/10/16/18739.aspx"&gt;Distinguished fields myths&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-2479465767308559251?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/2479465767308559251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=2479465767308559251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/2479465767308559251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/2479465767308559251'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/04/promoted-property-vs-distinguished.html' title='Promoted property vs distinguished field - tutorial'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6423720882494464545</id><published>2008-03-31T18:08:00.005+07:00</published><updated>2008-04-02T10:58:24.114+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Process'/><title type='text'>Windows Process, .Net Application Domain and 2 GB limit on 32-bit Windows</title><content type='html'>A few weeks ago I heard some comments from a colleague about how .Net applications run and that “all .Net applications run in the same runtime (CLR) so that if you start 10 separate .Net applications, they would share together a single 2 GB limit on Windows 32-bit”. This of course not true and it gave me the idea to blog about the 2GB limit on 32-bit systems, Windows Process, .Net applications and the concept of .Net Application Domain.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2 GB limitation on Windows 32-bit.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;32-bit Operating Systems are capped by the number of unique pointers that can exist at a time. On 32-bit processors, only 2^32 distinct addresses can exist. Would all these addresses be used, that would represent 4 GB of memory.  On a Windows Operating System the memory address system is not a 1-to-1 relationship to the physical memory of your hardware otherwise you would be stuck with a maximum of 4 GB of addressable memory for the whole machine. This would include all the I/O address space, kernel memory and so leave much less actual memory for programmers to use.&lt;br /&gt;&lt;br /&gt;This is why when we talk about memory, it is important to realize the distinction between the physical memory (RAM on the motherboard) and the Virtual Memory accessible through the Virtual Address Space. Note that actually, Virtual Memory is not the same as Virtual Address Space and that there are &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2004/08/10/211890.aspx"&gt;ways to use Virtual Memory without using the Virtual Address Space&lt;/a&gt;. I will nevertheless not go into these details; the important thing to remember is that Windows has a complex memory management system that enables the O.S. to use much more than 4 GB as a whole. The inner workings are not for the faint-hearted and are actually not of interest for most .Net programmers living in the managed world.&lt;br /&gt;&lt;br /&gt;Check this blog post for a &lt;a href="http://blogs.technet.com/askperf/archive/2007/02/23/memory-management-101.aspx"&gt;primer on memory management&lt;/a&gt; on Windows Operating System.&lt;br /&gt;&lt;br /&gt;When Windows 32 starts a program, a 32 bit process using 32 bit size pointers is created and so the process has a maximum of 4 GB of addressable memory.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Windows will assign to the process a Virtual Address Space of 4 GB (2^32) split in two; 2 GB of user mode virtual address space and 2 GB of kernel mode virtual address space. The user mode virtual address space is the “memory” (read the virtual address space to be correct) available for your program to use.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;This 2 GB user mode virtual address space limit is what is commonly called the 2 GB memory limit on Windows 32-bit.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;/3 GB switch on 32-bit Windows&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The /3GB switch changes the way the 4GB virtual address space is split up. With the /3GB switch, the split is 3GB of user mode virtual address space and 1GB of kernel mode virtual address space. It is nevertheless &lt;span style="font-weight:bold;"&gt;not recommended to use&lt;/span&gt; this option as it can bring unexpected bug from drivers and other kernel-mode processes which might expect to have 2 GB of kernel virtual address space available (not that a driver would ever need 2 GB, just that an older driver might expect to have addresses from 0x80000000 to 0xFFFFFFFF available).&lt;br /&gt;See &lt;a href="http://blogs.msdn.com/oldnewthing/archive/2004/08/06/209840.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://blogs.technet.com/askperf/archive/2007/03/23/memory-management-demystifying-3gb.aspx"&gt;here&lt;/a&gt; for other problems that can arise when using the /3GB switch.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;AWE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;AWE does not give more virtual address space to a process. AWE stands for Address Windowing Extension and is a Microsoft API (Application Programming Interface) that allows a 32-bit software application to access more physical memory that it has virtual address space. &lt;br /&gt;AWE enables programs to reserve physical memory as non-paged memory and then to dynamically map portions of the non-paged memory to the program’s working set of memory. This process enables memory-intensive programs, such as large database systems, to reserve large amounts of physical memory for data without having to be paged in and out of a paging file for usage.&lt;br /&gt;To be clear, AWE can only be available on programs that actually use the AWE API, it is not an OS switch that can be turned on/off on any program.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Windows 64-bit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;On windows 64-bit there is not 2 GB limit, the user mode virtual address space limit being 8TB. See &lt;a href="http://msdn2.microsoft.com/en-us/library/aa384271(VS.85).aspx"&gt;here&lt;/a&gt; for reference.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Windows Process and Runtime Host&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A Windows &lt;a href="http://en.wikipedia.org/wiki/Process_(computing)"&gt;process&lt;/a&gt; is an instance of a program that is executing over the Windows layer.  A process contains the executable code and data inside the memory reserved for it by the Operating System. There will be at least one thread executing instructions within the process but more in most cases.&lt;br /&gt;&lt;br /&gt;Any program running on Windows is actually working within a process. If you open 2 instances of notepad, you can see that 2 processes running notepad.exe are visible under the &lt;span style="font-style:italic;"&gt;Processes&lt;/span&gt; tab of the &lt;span style="font-style:italic;"&gt;Windows Task Manager&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The concept of a &lt;span style="font-style:italic;"&gt;Process&lt;/span&gt; exists for two main reasons:&lt;ul&gt;&lt;li&gt;To enable &lt;span style="font-weight:bold;"&gt;multitasking&lt;/span&gt; (time sharing), the different processes a CPU is running will have their states changing between running and waiting very quickly and so give the illusion to the end-user that all processes are running in the same time. This brings &lt;span style="font-weight:bold;"&gt;multitasking&lt;/span&gt; as well as &lt;span style="font-weight:bold;"&gt;scalability&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;To provide &lt;span style="font-weight:bold;"&gt;boundaries&lt;/span&gt; between running programs so that a process cannot peak into another one and that erroneous code inside a process cannot corrupt areas outside of that process (so that a process cannot crash another one). This is brings &lt;span style="font-weight:bold;"&gt;security&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;stability&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight:bold;font-style:italic;"&gt;The isolation between processes is achieved by making sure that any given unique virtual address space runs exactly into one process and not any other.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Runtime Host&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;.Net applications are compiled in &lt;span style="font-weight:bold;"&gt;CIL&lt;/span&gt; (Common Intermediate Language, formally called MSIL – Microsoft Intermediate Language), and then are &lt;span style="font-weight:bold;"&gt;JIT&lt;/span&gt;ed (Just-In-Time compiled) by the &lt;span style="font-weight:bold;"&gt;CLR&lt;/span&gt; (Common Language Runtime) into instructions directly understandable by the CPU (native code).&lt;br /&gt;Here is an illustration of this 2 step compilation process:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/Dot_Net_Application_Compilation-707676.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/Dot_Net_Application_Compilation-707670.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;This means that .Net applications are not Win32 applications and so cannot be executed directly by the Operating System. As any application running on Windows has to run through a Windows Process, a Windows Process called a &lt;span style="font-weight:bold;"&gt;Runtime Host&lt;/span&gt; will actually execute (host) the .Net Application. The Runtime Host first loads the CLR dll (a native Windows library – unmanaged code) which in turn loads the .Net application (managed code), JIT compiles it and runs it. The process thus effectively transitions the control of running the application from itself to the CLR.&lt;br /&gt;&lt;br /&gt;There are 2 types of Runtime Host shipped with the .Net Framework, ASP.NET and Shell. Shell runs all Windows-type applications (Windows Form, Windows Service or Console App).&lt;br /&gt;&lt;br /&gt;We can see that this concept actually adds a new layer between the .Net application and the Operating System. This layer, implemented by the CLR, is generically called a &lt;span style="font-weight:bold;"&gt;Virtual Machine&lt;/span&gt; and has OS-like features. It is an abstraction layer between the .Net application and the Operating System. As with Java, this permits any .Net Application to run on any Operating System as long as there is a CLR implemented for that OS.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;2 GB limit for .Net applications&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As the Runtime Host is a Windows Process, the .Net applications run by a Runtime Host is limited to the 2GB barrier on 32-bit Windows OS. Nevertheless, every Runtime Host has a separate 2 GB virtual address space limit. So would you launch 2 instances of a .Net application, each being a separate process in Task Manager, they would each have 2 GB limit.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;.Net Application Domain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;An Application Domain is the CLR equivalent of an Operating System’s process. As the Windows OS brings logical and physical isolation between Windows applications through the use of &lt;span style="font-weight:bold;"&gt;Processes&lt;/span&gt;, a single Runtime Host Windows Process can run several isolated .Net applications through the use of &lt;span style="font-weight:bold;"&gt;Application Domains&lt;/span&gt;. As explained before, Windows isolate processes by assigning different virtual memory address space to each process. In the .Net world, the memory is actively managed by the CLR and so the CLR can make sure that memory addresses are not shared between application domains, effectively isolating different Application Domains running in the same Runtime Host.&lt;br /&gt;&lt;br /&gt;When a Runtime Host starts a .Net application, the CLR will create a default Application Domain to run the .Net application. As multiple Processes can run on a single OS, multiple Application Domains can run within the same Runtime Host.&lt;br /&gt;&lt;br /&gt;An Application Domain is cheaper to create than a Windows Process and has relatively less overhead to maintain. It is thus more efficient to isolate .Net Application through Application Domains rather than Windows Processes. Application Domains are sometimes referenced as lightweight processes but strictly speaking, they are NOT processes.&lt;br /&gt;&lt;br /&gt;To summarize, here is a list of advantages of having Application Domains within a Runtime Host Process (which are for most of them similar to the advantages of having Processes within an Operating System):&lt;ul&gt;&lt;li&gt;An Application Domain is a more lightweight mean to provide isolation between .Net applications than Processes.&lt;/li&gt;&lt;li&gt;A .Net application in an Application Domain can be stopped without affecting the state of another application running in a separate Application Domain.&lt;/li&gt;&lt;li&gt;A crash in an Application Domain will not affect other Application Domains neither the Runtime Host Process hosting the Application Domains.&lt;/li&gt;&lt;li&gt;Configuration information is part of an Application Domain scope, not the process’ scope.&lt;/li&gt;&lt;li&gt;Each Application Domain can have different security access levels assigned to them, all within the same Runtime Host Process.&lt;/li&gt;&lt;li&gt;Code in one .Net Application Domain cannot directly access memory in another Application Domain. If two .Net applications need to communicate across Application Domains, they need to use .Net Remoting to do so. In .Net 1.x, this kind of inter-process communication was expensive because the TCP/IP stack needed to be involved. In .Net 2.0, .Net Remoting supports named pipe remoting which is much more efficient. WCF in .Net 3.x has this feature as well.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6423720882494464545?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6423720882494464545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6423720882494464545' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6423720882494464545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6423720882494464545'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/03/windows-process-net-application-domain.html' title='Windows Process, .Net Application Domain and 2 GB limit on 32-bit Windows'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4885934463802991826</id><published>2008-03-24T11:55:00.001+07:00</published><updated>2008-03-24T11:55:22.689+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Server Installation'/><title type='text'>List of BizTalk prerequesites redistributable CAB files</title><content type='html'>While I was installing BizTalk Server 2006 the other day, I decided to compile a list of links to the redistributable BizTalk prerequisite CAB file so that I do not have to search for it the next time I install BizTalk Server.&lt;br /&gt;&lt;br /&gt;The BizTalk prerequisites CAB file is a compilation of all the prerequisites that are needed to install and run BizTalk Server.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;The redistributable CAB file is different for different Windows versions (Windows XP, Vista, Server 2003, 64-bit or 32-bit) and languages (English, French, ...)&lt;/span&gt;. So, when chosing the prerequesite CAB file, make sure that it is the one matching your Windows Operating System version and language.&lt;br /&gt;&lt;br /&gt;When installing BizTalk Server, the setup procedure gives you the choice to either automatically install the prerequisites from the web or to automatically install the prerequisites from a redistributable CAB file.&lt;br /&gt;Choosing the redistributable CAB file options helps in speeding up the installation process and is necessary if the BizTalk server has a limited access or no access at all to the internet.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;BizTalk Server 2006&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For BizTalk Server 2006, the links to the redistributable prerequisites CAB files are listed in the &lt;a href="http://go.microsoft.com/fwlink/?LinkId=46922"&gt;BizTalk Server 2006 Installation and Upgrade Guides&lt;/a&gt;. The guides are MS Word documents containing links to all the prerequisites CAB files for all supported versions of the Windows Operating System.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;BizTalk Server 2006 R2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For BizTalk Server 2006 R2, the links to the redistributable prerequisites CAB files can be found in the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=df2e8a88-fb23-49a4-9ac7-d17f72517d12&amp;displaylang=en"&gt;BizTalk Server 2006 R2 Installation and Upgrade Guides&lt;/a&gt;. Here again the guides are a bunch of different MS Word documents containing links to all the prerequisites CAB files for all supported versions of the Windows Operating System.&lt;br /&gt;&lt;br /&gt;As BizTalk Server 2006 R2 is the current release of BizTalk Server 2006, the links to the prerequisites CAB files can also directly be found on the MSDN documentation site:&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/aa578652.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa578652.aspx&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For information purpose, here is a list of all requirements for BizTalk 2006 R2:&lt;br /&gt;&lt;a href="http://http://www.microsoft.com/biztalk/techinfo/2006R2/sysreqs.mspx"&gt;http://www.microsoft.com/biztalk/techinfo/2006R2/sysreqs.mspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4885934463802991826?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4885934463802991826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4885934463802991826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4885934463802991826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4885934463802991826'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/03/list-of-biztalk-prerequesites.html' title='List of BizTalk prerequesites redistributable CAB files'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4126169873981606615</id><published>2008-03-19T12:20:00.002+07:00</published><updated>2008-03-19T12:21:56.734+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006 64-bit'/><title type='text'>Biztalk 64 bit high CPU utilization</title><content type='html'>I started to deploy BizTalk server 2006 64-bit edition on Windows Server 2003 64-bit in our production environment and we noticed an unusual high CPU utilization by the BizTalk host processes. &lt;br /&gt;&lt;br /&gt;The symptoms were twofold: &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. The BizTalk 64 bit servers suffered from a high CPU usage&lt;/strong&gt; (one server had its CPU usage constantly stuck at 100%). &lt;strong&gt;This happened even when the load on the server was low, in fact much lower than on other BizTalk Server 32 bit machines running the same applications on a similar hardware&lt;/strong&gt;. &lt;br /&gt;The reason for the server high CPU usage was that &lt;strong&gt;some BizTalk host processes had their CPU usage stuck at a high value even if the BizTalk application(s) run by the host would process very few messages or no message at all&lt;/strong&gt;. Actually, the CPU usage for those hosts would still be stuck at a high value even if the BizTalk application(s) run by the host were stopped!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Even when the CPU utilization was showing 100%, the server was still processing messages as fast as you would expect from a server under little load. No messages were queued for processing and no orchestrations were dehydrated!&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Those 2 points gave me the feeling that nothing could be wrong with the BizTalk server itself (by that I mean the BizTalk code and the BizTalk installation) as the same code is running fine on 32 bit servers and as the performance monitor readings did not match the actual facts.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;I requested help from Microsoft Support and they guided me to the &lt;a href="http://support.microsoft.com/?id=943165"&gt;KB 943165&lt;/a&gt; which has a hotfix solving the high CPU usage problem I encountered on BizTalk Server 64-bit edition.&lt;/strong&gt;&lt;br /&gt;This hotfix fixes a problem brought by the security bulletin &lt;a href="http://support.microsoft.com/?id=931212"&gt;MS07-040&lt;/a&gt;, a security update for the .Net framework which brings CPU usage spikes on BizTalk Server 64 bit (meaning that the problem is only for the 64 bit version of the .Net framework). For information, Microsoft Support told me that the problem is suspected to be caused by an infinite loop in CounterManager.RunCacheThread when System.Threading.ThreadAbortException is raised.&lt;br /&gt;&lt;br /&gt;I should also add that I could not actually find a Windows update directly related to the bulletin MS07-040 in the list of updates installed on the server running BizTalk Server 64-bit. Nevertheless, my Microsoft Support contact told me that the version of mscorwks.dll (found in c:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727) has a timestamp showing that it is later than the hotfixes issued by bulletin MS07-040 and that the problem should then also occur with any later version of the dll (as it is a code change from that version on that brings the problem).&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;To conclude, would you encounter the same symptoms I enumerated above, you will want the check the &lt;a href="http://support.microsoft.com/?id=943165"&gt;KB 943165&lt;/a&gt; and contact Microsoft Product Support to see if your case is applicable for this hotfix. They will then email you the details to download the hotfix.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I installed this hotfix on all my BizTalk Server 2006 64 bit machines and all of them are running smoothly now :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4126169873981606615?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4126169873981606615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4126169873981606615' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4126169873981606615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4126169873981606615'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/03/biztalk-64-bit-high-cpu-utilization.html' title='Biztalk 64 bit high CPU utilization'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4523046153114392706</id><published>2008-03-13T16:20:00.001+07:00</published><updated>2008-03-13T16:20:58.010+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Operation and Maintenance'/><title type='text'>Turn off tracking globally in BizTalk Server 2006</title><content type='html'>The BizTalk Tracking (BizTalkDTADb) database grows in size as BizTalk Server processes data on your system. If the size of the BizTalk Tracking database causes poor disk performance or fills up the disk subsystem, you can manually purge the data from the Tracking database. See my previous post about &lt;a href="http://www.malgreve.net/2008/02/biztalkdtadb-grows-too-large-how-to.html"&gt;how to purge and maintain the BizTalkDTADb database&lt;/a&gt;.&lt;br /&gt;If you repeatedly have issues with the BizTalk tracking database, you may want to configure BizTalk to no longer collect tracking information. This is possible by turning off global tracking for the whole BizTalk Server.&lt;br /&gt;&lt;br /&gt;Here is the procedure to turn off tracking globally for BizTalk server 2006 and 2006 R2:&lt;ul&gt;&lt;li&gt;Open SQL Server Management Studio and connect to the Database Server where the BizTalk Management Database is running, &lt;span style="font-weight:bold;"&gt;BizTalkMgmtDb&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Expand the BizTalkMgmtDb, database, expend Tables, right-click the &lt;span style="font-weight:bold;"&gt;adm_Group&lt;/span&gt; table, and then click Open Table.&lt;/li&gt;&lt;li&gt;In the &lt;span style="font-weight:bold;"&gt;GlobalTrackingOption&lt;/span&gt; column, change the value from &lt;span style="font-weight:bold;"&gt;1 to 0&lt;/span&gt; and then press ENTER. A value of 0 turns off global tracking for the whole BizTalk server while a value of 1 turns it on.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight:bold;"&gt;Restart all your BizTalk hosts&lt;/span&gt; for the change to take effect.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;As when Tracking is turned off, tracking information is not collected so &lt;span style="font-weight:bold;"&gt;no information will be available in HAT anymore&lt;/span&gt; (Health and Activity Tracking). You should consider this effect against keeping tracking data for a shorter time when thinking about turning off Tracking globally. &lt;br /&gt;&lt;br /&gt;An alternative to turn off Tracking globally is to turn it off on an application per application basis.&lt;br /&gt;I think that once a BizTalk application is deployed and running smoothly for a while, there is no reason to still have tracking turned on at all time.&lt;br /&gt;If you deploy new BizTalk applications or keep updating existing ones on your production server regularly, you will probably want to be able to consult HAT after the application is freshly deployed. For that to be possible you would have to keep global tracking on.&lt;br /&gt;In that case, I think that a best practice kind of approach is to have Tracking turned on for the freshly deployed application for a few days until you deem it running fine so that you do not need to consult HAT anymore. Once HAT is not needed regularly anymore, you can use the BizTalk Server Administration Console to disable tracking for all the artifacts belonging to the concerned application (orchestrations, ports, etc.). Would you need to turn it on again, it would just take a few minutes to configure tracking back on for the application's artifacts.&lt;br /&gt;&lt;br /&gt;Reference can be found at the &lt;a href="http://msdn2.microsoft.com/en-us/library/bb203858.aspx"&gt;MSDN BizTalk documentation How to Turn Off Global Tracking&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4523046153114392706?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4523046153114392706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4523046153114392706' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4523046153114392706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4523046153114392706'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/03/turn-off-tracking-globally-in-biztalk.html' title='Turn off tracking globally in BizTalk Server 2006'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-5823784855970586235</id><published>2008-03-10T14:15:00.011+07:00</published><updated>2008-04-10T19:15:42.061+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006 Architecture'/><title type='text'>BizTalk Messaging architecture</title><content type='html'>The core of the BizTalk Server product is the BizTalk Messaging subsystem, called the &lt;strong&gt;Message Bus&lt;/strong&gt;. As said in the BizTalk documentation, The Message Bus is a &lt;strong&gt;publisher/subscriber&lt;/strong&gt; model; indeed the Message Bus queries messages &lt;strong&gt;published&lt;/strong&gt; into the BizTalk Message Box database looking for messages that match a particular &lt;strong&gt;subscription&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;The most important point to understand about the publisher/subscriber model is that &lt;strong&gt;publishing and subscription concepts are relative to the Database&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Here is a picture illustrating the concept:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/biztalk_publisher_subscriber_architecture.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/biztalk_publisher_subscriber_architecture_small.jpg" border="0" alt="BizTalk Server Publisher Subscriber Architecture" /&gt;&lt;/a&gt;&lt;br /&gt;The Messaging infrastructure is composed of the &lt;strong&gt;Message Box database&lt;/strong&gt; and also different software components, called the &lt;strong&gt;Messaging Components&lt;/strong&gt;. The Db and the components together compose the publisher/subscriber BizTalk Messaging subsystem, the &lt;strong&gt;Message Bus&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;An important side effect of this architecture is that in BizTalk Server, &lt;strong&gt;messages are immutable once published (in the Message Box DB)&lt;/strong&gt;. This is because more than one end-point can subscribe to the same message. Would messages be mutable, some end-points might not match the subscriptions rule after the message has been modified. Having the subscription query result vary with time on the same message (due to change in the message payload) would break the publisher/subscription architecture thus making the whole BizTalk product unpredictable (and so useless).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. The Message Box.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The Message Box is an SQL Server database which stores XML messages as well as metadata related to each messages. The message’s metadata is called the &lt;strong&gt;message context&lt;/strong&gt;. Each metadata item (a key/value pair) of the message context is called a &lt;strong&gt;context property&lt;/strong&gt;. The most important information to know about the message context is that it holds all the necessary information for message routing - &lt;strong&gt;message subscription&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Messaging Components.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;While the Message Box database is the message storage facility of the Message Bus, the messaging components are software components that actually move messages between subscribers and publishers. They receive and send messages in and out of the BizTalk Server system.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.1 Host Services.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A &lt;strong&gt;BizTalk host is a logical container&lt;/strong&gt;. It provides the ability to structure the BizTalk application into groups that could be spread across multiple processes or machines.&lt;br /&gt;When you create a host in BizTalk server, it creates a logical unit in which you can run different BizTalk applications or different type of BizTalk artifact.&lt;br /&gt;For example, if your BizTalk applications are pretty small, you could create 1 host per BizTalk application you develop. On the opposite if your applications are big, you can create different hosts to separate logical grouping of your application, such adapters, orchestrations, ports and so on. If each host runs on a separate physical machine this help in balancing the load between processors (some sort of manual load balancing).&lt;br /&gt;&lt;br /&gt;A &lt;strong&gt;host instance is simply a running instance of the host logical grouping&lt;/strong&gt;. It runs as a Windows Service, each host being a separate windows process; a separate instance of BTSNTSvc.exe (or BTSNTSvc64.exe for BizTalk Server 64 bit).&lt;br /&gt;&lt;br /&gt;As explained before, the &lt;strong&gt;host instance&lt;/strong&gt; &lt;em&gt;raison d’être&lt;/em&gt; is to provide logical grouping units. It does not implement itself the BizTalk runtime, &lt;strong&gt;it is a container where the BizTalk subservices run&lt;/strong&gt;. These subservices running inside the host instance implements together the actual runtime of the BizTalk Message Bus.&lt;br /&gt;&lt;br /&gt;Host instances can run all BizTalk subservices or only some of them depending on what type of BizTalk artifacts they are running. To understand which subservice is used by which type of artifact, here is a list of the different subservices running inside a BizTalk host instance - note that the list of services can be found in the the adm_HostInstance_SubServices table in the Management Database:&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Service&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Caching&lt;/td&gt;&lt;td&gt;Service used to cache information that is loaded into the host. Examples of cached information would be assemblies that are loaded, adapter configuration information, custom configuration information, etc.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;End Point Manager (EPM)&lt;/td&gt;&lt;td&gt;Go-between for the Message Agent and the Adapter Framework. The EPM hosts send/receive ports and is responsible for executing pipelines and BizTalk transformations. The Message Agent is responsible to search for messages that match subscriptions and route them to the EPM.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Tracking&lt;/td&gt;&lt;td&gt;Service that moves information from the Message Box to the Tracking Database.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XLANG/s&lt;/td&gt;&lt;td&gt;Host engine for BizTalk Server orchestrations.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MSMQT&lt;/td&gt;&lt;td&gt;MSMQT adapter service; serves as a replacement for the MSMQ protocol when interacting with BizTalk Server. The MSMQT protocol has been deprecated in BizTalk Server 2006 and should only be used to resolve backward compatibility issues.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.2 Subscriptions.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In a publish/subscribe design, you have three components:&lt;ul&gt;&lt;li&gt;Publishers&lt;/li&gt;&lt;li&gt;Subscribers&lt;/li&gt;&lt;li&gt;Events&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;em&gt;Publishers include:&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Receive ports that publish messages that arrive in their receive locations&lt;/li&gt;&lt;li&gt;Orchestrations that publish messages when sending messages (orchestration &lt;em&gt;send&lt;/em&gt; shape)&lt;/li&gt;&lt;li&gt;Orchestrations that start another orchestration asynchronously (&lt;em&gt;start orchestration&lt;/em&gt; shape). On a side note, the &lt;em&gt;call orchestration&lt;/em&gt; shape does not publish the message into the Message Box, the message is just passed as a parameter.&lt;/li&gt;&lt;li&gt;Solicit/response send ports publish messages when they receive a response from the target application or transport.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;em&gt;Subscriptions:&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Subscription is the mechanism by which ports and orchestrations are able to &lt;strong&gt;receive and send&lt;/strong&gt; messages within BizTalk server (see picture above).&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;A subscription is a collection of comparison statements, known as predicates, comparing the values of message context properties and the values specific to the subscription.&lt;/strong&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;There are two types of subscriptions: activation and instance.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;An &lt;strong&gt;activation subscription&lt;/strong&gt; is one specifying that a message fulfilling a subscription should create a new instance of the subscriber when it is received. Examples of things that create activation subscriptions include:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Send ports with filters&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;send ports that are bound to orchestrations&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;orchestration receive shapes that have their Activate property set to true&lt;/strong&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;An &lt;strong&gt;instance subscription&lt;/strong&gt; indicates that messages fulfilling the subscription should be routed to an already-running instance of the subscriber. Examples of things that create instance subscriptions are:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Orchestrations with correlated receives&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;request/response-style ports&lt;/strong&gt; waiting for a response.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;It is also important to know that when you define filter criteria on a send port, you are actually modifying the subscription of the port. As a reminder, filter expressions determine which messages are routed to the send port from the Message Box.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Enlisting:&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;The process of enlisting a port simply means that a subscription is written for that port in the Message Box. Consequently, un-enlisted ports do not have subscriptions in the Message Box.&lt;br /&gt;The same is true for other BizTalk artifacts. An un-enlisted orchestration is an orchestration ready to process messages but having no way to receive messages from the Messaging Engine as no subscription is created for it yet.&lt;br /&gt;&lt;br /&gt;The &lt;strong&gt;difference between an un-enlisted artifacts and a stopped artifacts&lt;/strong&gt; is that ports and orchestrations that are enlisted, but not started, will have any messages with matching subscription information queued within the Message Box and ready to be processed once the artifact is started. If the port or orchestration is not enlisted, the message routing will fail, since no subscription is available and the message will produce a “No matching subscriptions were found for the incoming message” exception within the Windows Event Log.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Typical port usage with an orchestration:&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;What happens in an orchestration that as a send shape connected to a logical port which is in turn bound to a physical port, is that the message sent by the send shape will have a TransportID context property set to a value that matches the physical port TransportID. As the TransportID uniquely defines the port, this mechanism assures that the physical port will &lt;strong&gt;always&lt;/strong&gt; receive the messages coming from the orchestration. It does &lt;strong&gt;not&lt;/strong&gt; mean that &lt;strong&gt;only&lt;/strong&gt; that port will receive the message as due to the nature of a publisher/subscriber architecture, any other port having a subscription matching the message context will also receives the message.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.3 Messages&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;As said earlier a Message is more than just an XML document. It is actually a message containing both data and context.  To be more precise, &lt;strong&gt;a message is composed of context properties and zero or more message parts&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Keep in mind that &lt;strong&gt;message parts are not always XML document&lt;/strong&gt;. If the message is received through a port using the pass-through pipeline, the message can be any kind of data including binary data. On a side note, a pass-through pipeline does not promote context properties; this makes sense as the message is not even supposed to be XML in a pass-through pipeline, so it is not possible to evaluate XPath expression on the message to determine the value of the context property.&lt;br /&gt;&lt;br /&gt;As said earlier &lt;strong&gt;a message is immutable once it is published&lt;/strong&gt;. This means that once stored in the MessageBox DB, it can’t be changed. A message can nevertheless be changed once it is out of the database. In a &lt;strong&gt;receive pipeline component&lt;/strong&gt;, a message can be modified &lt;strong&gt;before it is published&lt;/strong&gt; in the MessageBox. In a &lt;strong&gt;send pipeline component&lt;/strong&gt;, a message can be modified &lt;strong&gt;after&lt;/strong&gt; being received from the MessageBox.  A typical place to create or modify a message is also inside an orchestration.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.4 Message Context Properties&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Message context properties&lt;/strong&gt; are used for the subscription mechanism (routing the message to its appropriate end point). They are defined in a &lt;strong&gt;property schema&lt;/strong&gt;. At runtime, the property values are stored into a &lt;strong&gt;context property bag&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;The property schema is associated with the message schema within BizTalk so that every inbound schema-based message has a schema and a property schema attached to it.&lt;br /&gt;&lt;br /&gt;The property schema consists of a &lt;strong&gt;global property schema&lt;/strong&gt; that every message can use by default and of an optional &lt;strong&gt;custom property schema&lt;/strong&gt; which can be created to define application-specific properties. Both types of properties are essentially the same at runtime and both are stored in the context property bag.&lt;br /&gt;&lt;br /&gt;So, both types of properties can be used by the subscription mechanism to evaluate which endpoints have a subscription matching the message. The most common subscription is based on a global property called the &lt;em&gt;messageType&lt;/em&gt; which is a combination of the XML namespace of the message and the root node name separated by a # character. Ex: http://www.abc.com#RootElementName.&lt;br /&gt;&lt;br /&gt;Using subscription to route documents to the proper endpoint is called Content Based Routing (CBR).&lt;br /&gt;For information, if the message is not schema-based, there will be no MessageType property value. Such is the case for binary data message.&lt;br /&gt;&lt;br /&gt;Message context properties are populated by the BizTalk runtime in 2 artifacts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The adapter writes and promotes into the message context properties related to the location, adapter type, and others properties related to the adapter.&lt;/li&gt;&lt;li&gt;The Receive Pipeline can write and promote properties into the message context in any of its pipeline components. Disassembling components are of particular interest because they promote the messageType property which is commonly used for Content Based Routing.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Property bag.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;It is possible to use the BizTalk API in pipeline component code to read/write context properties from the property bag. The property bag is an object implementing the &lt;em&gt;&lt;strong&gt;IBasePropertyBag&lt;/strong&gt;&lt;/em&gt; interface. If you intend to use that interface in a custom pipeline to write properties that will be used for routing, you have to keep in mind that &lt;strong&gt;properties that are simply written into the property bag using the Write() method are not available for routing.&lt;/strong&gt; &lt;strong&gt;To have a property available for routing, you need to promote the property with a different API call, the Promote() method. This method writes the property and its value in the property bag but ALSO flag the property as promoted and so make it available for routing.&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-5823784855970586235?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/5823784855970586235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=5823784855970586235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/5823784855970586235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/5823784855970586235'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/03/biztalk-messaging-architecture.html' title='BizTalk Messaging architecture'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-2640195391181596449</id><published>2008-02-19T18:02:00.009+07:00</published><updated>2008-02-19T19:15:54.012+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Operation and Maintenance'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>BizTalkDTADb grows too large – How to purge and maintain the database?</title><content type='html'>The &lt;span style="font-style:italic;"&gt;BizTalkDTADb&lt;/span&gt; is a BizTalk database that stores health monitoring data tracked by the BizTalk Server tracking engine. It is commonly called the “&lt;span style="font-style:italic;"&gt;BizTalk Tracking Database&lt;/span&gt;”. This database can grow relatively quickly in size depending of the kind of load your server is under.&lt;br /&gt;&lt;br /&gt;I will explain first what should be done to keep the database healthy (by which I mean to keep it under a reasonable size) and after how to clean up the database if it grew up so large that the normal clean up method doesn't work anymore.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1. How to maintain the BizTalkDTADb?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Each BizTalk service instance running is processing data and while the data is processed, BizTalk tracks it and saves it in the BiztTalk Tracking Database. This means that the Tracking Database will grow indefinitely over time which is obviously not a viable option.&lt;br /&gt;There is an SQL job called “&lt;span style="font-style:italic;"&gt;DTA Purge and Archive (BizTalkDTADb)&lt;/span&gt;” that is installed on the BizTalk SQL Server which is used for cleaning up (deleting old tracking information) the BizTalkDTADb. &lt;span style="font-weight:bold;"&gt;That job is not enabled by default so the first thing that should be done after installing BizTalk server is to configure and enable the job&lt;/span&gt;. See &lt;a href="http://msdn2.microsoft.com/en-us/library/aa560754.aspx"&gt;here&lt;/a&gt; for information about how the cleanup process works and &lt;a href="http://msdn2.microsoft.com/en-us/library/aa558715.aspx"&gt;here&lt;/a&gt; for information on how to configure the SQL job.  Basically, the job calls a single stored procedure on the BizTalkDTADb and once edited should looks like the following:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;exec [dbo].[dtasp_BackupAndPurgeTrackingDatabase] 1, 0, 1, '\\MyBizTalkServer\backup', null, 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The 4 first parameters are the one that you need to know about. The 2 first are the number of hours and days for which completed instances will be cleaned up. The third one is the number of days after which even non completed instance will be cleaned up. The fourth is the location of the backup folder.&lt;br /&gt;This means that the SQL job will back up the BizTalkDTADb &lt;span style="font-weight:bold;"&gt;each time&lt;/span&gt; it runs, making that backup files will fill up your disk subsystem pretty quickly if nothing is done about it! Backups are important in case of a Database crash and that the Tracking Database needs to be restored.&lt;br /&gt;&lt;br /&gt;If you do not consider the Tracking Database to be of enough importance to be backed up and have the extra burden to manage the backups, you can modify the “DTA Purge and Archive (BizTalkDTADb)”  SQL job as explained &lt;a href="http://msdn2.microsoft.com/en-us/library/aa578470.aspx"&gt;here&lt;/a&gt;. This way, the job will only purge the tracking database without backing it up. It is especially applicable for development and QA environments and might also apply to your production environment.&lt;br /&gt;In short, the only change that needs to be done in the SQL job is to modify the T-SQL statement run by the job. It needs to execute the SP &lt;span style="font-style:italic;"&gt;dtasp_PurgeTrackingDatabase&lt;/span&gt;  instead of &lt;span style="font-style:italic;"&gt;dtasp_BackupAndPurgeTrackingDatabase&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The final T-SQL statement executed by the SQL job will be similar to the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;declare @now as datetime&lt;br /&gt;set @now = GetUTCDate()&lt;br /&gt;exec [dbo].[dtasp_PurgeTrackingDatabase] 0, 3, 6, @now&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In this case I keep complete instances in the Tracking DB for 3 days and incomplete one for 6 days, everything older should be purged. As you see there is no path to specify for the backup location as no database backup is executed.&lt;br /&gt;&lt;br /&gt;Instead of modifying the original SQL job you could alternatively disable it and create a new job with the appropriate T-SQL call. That is how I have done it myself and consider it to be a best practice.&lt;br /&gt;Moreover, I scheduled the job to run every 5 minutes. This has proven to be a good time interval. I used to run the job every 30 minutes only but I ever encountered cases where the clean up procedure did not keep up with the amount of tracked data and I ended up with a huge tracking database which I had to purge manually, as I will explain next.&lt;br /&gt;So, a 5 minutes interval to run the job seems to also be a best practice from my experience.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2. How to manually purge the BizTalkDTADb?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You will have to manually purge the BizTalkDTADb database if it grew too large either because the clean up procedure was not started or the clean up procedure could not keep up with the amount of data saved in the Tracking Database.&lt;br /&gt;This is explained in details &lt;a href="http://msdn2.microsoft.com/en-us/library/aa561918.aspx"&gt;here&lt;/a&gt; but, in short, the important points are:&lt;br /&gt;&lt;br /&gt;- All the BizTalk services used by BizTalk needs to be stopped. This means all the BizTalk host service instances, Enterprise SSO, BizTalk Rules Engine, EDI service, BAM, BAS and IIS if they are used.&lt;br /&gt;&lt;br /&gt;- Open Microsoft SQL Server Management Studio and run the following SQL statement on the BizTalkDTADb: &lt;span style="font-style:italic;"&gt;exec dtasp_PurgeAllCompletedTrackingData&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once the procedure is executed, a lot of space will have been freed in the Tracking Database. The database will nevertheless still take the same amount of space on the disk subsystem because deleting data in a database does not reduce the size the database takes on the disk. If you want to reduce its size on the disk, you need to shrink it. You can do that in 2 ways:&lt;br /&gt;&lt;br /&gt;1. Through SQL Server Management Studio, right click on the BizTalkDTADb database, click on Tasks &gt; Shrink &gt; Database&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/Shrink_BizTalkDTADb-787728.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/Shrink_BizTalkDTADb-787725.jpg" border="0" alt="How to shrink BizTalkDTADb database using SQL Server Management Studio" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. Through T-SQL using the DBCC SHRINKDATABASE command:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;DBCC SHRINKDATABASE (BizTalkDTADb);&lt;/span&gt;&lt;br /&gt;The reference of the T-SQL DBCC SHRINKDATABASE command can be found &lt;a href="http://technet.microsoft.com/en-us/library/ms190488.aspx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-2640195391181596449?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/2640195391181596449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=2640195391181596449' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/2640195391181596449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/2640195391181596449'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/02/biztalkdtadb-grows-too-large-how-to.html' title='BizTalkDTADb grows too large – How to purge and maintain the database?'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-4479164432472033788</id><published>2008-01-17T17:04:00.001+07:00</published><updated>2008-03-04T12:27:07.022+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AdWords API'/><title type='text'>AdWords API and .Net client</title><content type='html'>I have been recently given the task to be in charge of a project using the &lt;a href="http://www.google.com/apis/adwords/"&gt;AdWords API&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The AdWords API actually consists of a serie of Web Services which let you access to your AdWord account through an API instead of a normal user interface. The documentation regarding the Web Services can be found at: &lt;a href="http://www.google.com/apis/adwords/developer/index.html"&gt;http://www.google.com/apis/adwords/developer/index.html&lt;/a&gt;&lt;br /&gt;To access the AdWords API using a .Net client, there is a .Net solution with pre-generated Web Service proxies that you can find at &lt;a href="http://www.google.com/apis/adwords/net.html"&gt;http://www.google.com/apis/adwords/net.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The documentation regarding the .Net client is pretty scarce but there is an &lt;a href="http://groups.google.dm/group/adwords-api"&gt;AdWords API forum&lt;/a&gt; where you can find solutions to your problems and also post your own questions.&lt;br /&gt;&lt;br /&gt;Please note that the problem I describe hereunder applies to the latest .Net client available at time of writing (mid-January). This blog post applies only if you encounter the same problem with your version of the .Net client code. Would a future release not show the problem, no fix will be needed.&lt;br /&gt;&lt;br /&gt;The only problem I have had so far with the proxy classes is that they constantly threw me an error message saying that “The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.”&lt;br /&gt;This problem is similar to what I have previously encountered in BizTalk projects when .Net HTTP requests access a Web Server which ignores the keepAlive instruction. This is often the case with Apache servers (or should I say their administrators? – I am not sure if this is a setting they can change). Anyway, for people interested, I have posted more details about the problem in a previous post: &lt;a href="http://www.malgreve.net/2007/09/http-adapter-and-apache-keep-alive.html"&gt;BizTalk HTTP Adapter and Apache Keep-Alive issue&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;So, the first thing I had to do to fix the issue is to modify every Web Service proxy classes so that the HTTP request used to make the Web Service call has its KeepAlive setting set to false.&lt;br /&gt;All Web Service proxy classes that are using SOAP extends from the SoapHttpClientProtocol class. Web methods belonging to  the WebService are called using the Invoke() method.  Nevertheless, we, as client programmers, do not call the Invoke method directly, it is instead the proxy class which wraps the Invoke() call into a method matching the WebService method signature. For example, the ReportService proxy class delivered in the AdWords API .Net client has a method validateReportJob() which matches the &lt;a href="http://www.google.com/apis/adwords/developer/ReportService.html#validateReportJob"&gt;WebService method defined on the server&lt;/a&gt; and which encapsulates the call to the Invoke() method:&lt;br /&gt;public void validateReportJob(ReportJob job) &lt;br /&gt;{&lt;br /&gt;    this.Invoke("validateReportJob", new object[] {job});&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The SoapHttpClientProtocol.Invoke() method  is implemented using the protected method GetWebRequest () which creates an instance of a WebRequest object that the Invoke() method uses to establish an HTTP connection with the web server.&lt;br /&gt;&lt;br /&gt;With this in mind, all we have to do is to override the GetWebRequest() method in our ReportService proxy class so that we can intercept the WebRequest object created and modify the properties we want to customize.&lt;br /&gt;&lt;br /&gt;Note that the WebRequest class is in fact an abstract classs and that the actual object returned at runtime is a class implementing the protocol used. In cases of Web Services and everything that runs over HTTP, it is the HttpWebRequest class.&lt;br /&gt;So in our case, I have added the following code in the ReportService proxy class:&lt;br /&gt;&lt;br /&gt;protected override System.Net.WebRequest GetWebRequest(Uri uri)&lt;br /&gt;{&lt;br /&gt;    System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);&lt;br /&gt;    webRequest.KeepAlive = false;  //set the HTTP Header to not keep connections alive between requests&lt;br /&gt;    webRequest.Timeout = 1200000; // The length of time, in milliseconds, until the request times out (20 minutes here)&lt;br /&gt;    return webRequest;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;With this piece of code in each of the Web Service classe proxies, “the connection closed” exception is not thrown anymore as both the .Net client and the Apache server that runs on &lt;a href="http://adwords.google.com"&gt;http://adwords.google.com&lt;/a&gt; have the same KeepAlive setting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-4479164432472033788?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/4479164432472033788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=4479164432472033788' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4479164432472033788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/4479164432472033788'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2008/01/adwords-api-and-net-client.html' title='AdWords API and .Net client'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-27489057637136891</id><published>2007-11-11T00:26:00.001+07:00</published><updated>2007-11-11T00:38:07.596+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><category scheme='http://www.blogger.com/atom/ns#' term='Custom Pipeline'/><title type='text'>Custom Pipeline Component deployment gotcha.</title><content type='html'>When you create custom pipeline, you might want to compile and install the custom pipeline component in the GAC first before adding the pipeline component in the toolbox. That way, the custom pipeline solution will reference the custom pipeline component from the GAC instead of its location on the disk.&lt;br /&gt;The reason behind this is that if you install the pipeline component library on your production servers only in the GAC and if you did not GACed the pipeline component before using it in the custom pipeline, an exception is raised saying that the custom pipeline cannot be found (as the custom pipeline refers to a custom pipeline component on the local drive instead of the GAC). See a full explanation of the problem on &lt;a href="http://geekswithblogs.net/sthomas/archive/2006/09/27/92513.aspx"&gt;Stephen W. Thomas' blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Note that if you follow the BizTalk documentation on &lt;a href="http://msdn2.microsoft.com/en-us/library/aa577482.aspx"&gt;Deploying Pipeline Components&lt;/a&gt;, it is advised that the assembly should be deployed in &lt;strong&gt;both&lt;/strong&gt; the &lt;strong&gt;GAC&lt;/strong&gt; and the &lt;&lt;strong&gt;installation directory&gt;\Pipeline Components&lt;/strong&gt; folder. I would advise to follow this way so it won’t matter how you or your developers create and compile the pipeline and their components; it will always work when the code is moved to the production environment and thus avoid unnecessary stress in the case it would have gone wrong because one developer referenced his component in a different way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;EDIT for BizTalk Server 2006 R2:&lt;/span&gt;&lt;br /&gt;I have just notice after having published the post that the documentation has been changed for BizTalk Server 2006 R2 and that now the documentation says:&lt;br /&gt;&lt;blockquote&gt;All the .NET pipeline component assemblies (native and custom) must be located in the &lt;installation directory&gt;\Pipeline Components folder to be executed by the server.&lt;/blockquote&gt;and:&lt;br /&gt;&lt;blockquote&gt;You do not need to add a custom pipeline component to be used by the BizTalk Runtime to the Global Assembly Cache (GAC).&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So now, Microsoft officially advises to put the custom pipeline component libraries only in the &lt;span style="font-weight:bold;"&gt;&lt;installation directory&gt;\Pipeline Components&lt;/span&gt; and not in the GAC anymore. If you still have BizTalk Server 2006 installed on your machine like I do, you will see that the local BizTalk documentation still says as mentioned in my original post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-27489057637136891?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/27489057637136891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=27489057637136891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/27489057637136891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/27489057637136891'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/11/custom-pipeline-component-deployment.html' title='Custom Pipeline Component deployment gotcha.'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6474292021731993329</id><published>2007-11-09T18:14:00.000+07:00</published><updated>2007-11-09T18:41:03.319+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Custom Functoid'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>BizTalk Server 2006 Custom Functoid Documentation Mistake</title><content type='html'>When you develop a custom functoid, there are 5 important tasks to do:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create a resource file with the various resources such as functoid’s name, description, tooltip and icon.&lt;/li&gt;&lt;li&gt;Create the class that will implement the functoid. This class must derive from the &lt;span style="font-style:italic;"&gt;Microsoft.BizTalk.BaseFunctoids.BaseFunctoid&lt;/span&gt; class.The constructor must override the bas class constructor and call a certain number of methods and properties so that the custom functoid can run properly at run-time as well as integrate well into the Visual Studio’s mapper.&lt;/li&gt;&lt;li&gt;Create a member method in the functoid class that will actually implement the functionality of the custom functoid (its business logic).&lt;/li&gt;&lt;li&gt;Compile and sign the functoid project into an assembly with a strong name key file (so that the assembly containing the custom functoid can be deployed in the GAC).&lt;/li&gt;&lt;li&gt;Copy the assembly to &lt;span style="font-style:italic;"&gt;C:\Program Files\Microsoft BizTalk Server 2006\Developer Tools\Mapper Extensions&lt;/span&gt; and add the functoid in Visual Studio’s ToolBox. You must also install the assembly into the GAC so that the functoid is available to BizTalk at runtime.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Today I found out that the BizTalk Server 2006 documentation has a mistake in the custom functoid development section: &lt;a href="http://technet.microsoft.com/en-us/library/aa562075.aspx"&gt;Using BaseFunctoid&lt;/a&gt;, which relates to the point number 2 in my previous list of tasks.&lt;br /&gt;That section says that the constructor of the functoid must make a call to the &lt;span style="font-style:italic;"&gt;SetupResourceAssembly&lt;/span&gt; method to point to the resource assembly. It details:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Include a resource file with your project. If building with Visual Studio, the resource assembly must be &lt;span style="font-weight:bold;"&gt;ProjectName.ResourceName&lt;/span&gt;.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;In my experience this is not true, when I build my custom functoid assembly in Visual Studio, I have to call the &lt;span style="font-style:italic;"&gt;SetupResourceAssembly&lt;/span&gt; method with &lt;span style="font-weight:bold;"&gt;FunctoidNameSpace.ResourceName&lt;/span&gt; as parameter instead of &lt;span style="font-weight:bold;"&gt;ProjectName.ResourceName&lt;/span&gt;. If I follow the documentation’s advice, the resource information such as functoid’s name and icon do not appear in Visual Studio’s toolbox, proving that the resources could not be found by the IDE.&lt;br /&gt;&lt;br /&gt;The only case that it would work as mentioned in the documentation would be if the project name and the namespace of the functoid were identical, which happens by default in Visual Studio. Indeed, when you create a new project with Visual Studio 2005, a default namespace will be created for the project, its value being the project name. You can see the default namespace value by right-clicking on your project files and click “properties”.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6474292021731993329?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6474292021731993329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6474292021731993329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6474292021731993329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6474292021731993329'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/11/biztalk-server-2006-custom-functoid.html' title='BizTalk Server 2006 Custom Functoid Documentation Mistake'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-3994390060396727694</id><published>2007-11-06T13:29:00.000+07:00</published><updated>2007-11-06T14:03:56.273+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IntelliSense'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio'/><title type='text'>BizTalk Expression Shape IntelliSense</title><content type='html'>Whenever you want to call IntelliSense from the Expression Shape editor, you can do so by just hitting the keys CTRL + SPACE. You will see the different namespaces, classes and objects (such as local variables and messages) available from the scope of your Expression Shape.&lt;br /&gt;&lt;br /&gt;Note that this shortcut key combination actually comes from the Visual Studio .Net IDE. Thus, it is available for any “traditional” .Net project types (C#, VB.NET, Windows form, Web App…)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.malgreve.net/uploaded_images/BizTalk_Expression_Editor_Intellisense-771493.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/BizTalk_Expression_Editor_Intellisense-771490.jpg" border="0" alt="BizTalk Expression Shape IntelliSense" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-3994390060396727694?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/3994390060396727694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=3994390060396727694' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/3994390060396727694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/3994390060396727694'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/11/biztalk-expression-shape-intellisense.html' title='BizTalk Expression Shape IntelliSense'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-7629438704172544078</id><published>2007-09-14T12:38:00.000+07:00</published><updated>2007-11-02T22:15:10.205+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTTP Connection'/><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>HTTP Adapter and Apache Keep-Alive issue</title><content type='html'>&lt;strong&gt;Problem.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you notice a high rate of suspended messages due to communication failures between your BizTalk Server and an HTTP server, you should verify if the HTTP Web server you are accessing is Apache, Resin or another similar server of the UNIX / LINUX / Java family. Note that this could apply to other web servers as well, these are just examples I know of.&lt;br /&gt;&lt;br /&gt;BizTalk Server always sends HTTP request with the HTTP header setting &lt;em&gt;Connection: Keep-Alive&lt;/em&gt;. Moreover, BizTalk expects that the foreign HTTP server obeys to the header setting and does not check the &lt;em&gt;Connection&lt;/em&gt; header setting received in the HTTP response.&lt;br /&gt;To be more precise, the problem is double:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Apache is not obeying to the Connection HTTP header setting and always closes the HTTP connection after every request (as in an HTTP 1.0 fashion). The &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html"&gt;HTTP/1.1 protocol&lt;/a&gt; allows this even if it is not the prefered behaviour.&lt;/li&gt;&lt;li&gt;BizTalk Server does not react accordingly to the Connection header that is returned back in the HTTP response. This is wrong, following the HTTP/1.1 protocol definition, the client should always check the &lt;em&gt;Connection&lt;/em&gt; header returned.&lt;/li&gt;&lt;/ul&gt;So, on one side there is a Apache closing connections for every HTTP request and on the other side BizTalk is expecting connections to be kept open between requests.&lt;br /&gt;&lt;br /&gt;Actually, the source of the problem is not that the Web Server is Apache or not but related to how the Web Server is configured and how it behaves with the connection. Nevertheless, in my experience, this kind of problem only happened with Apache. But I also ever encountered 1 Apache server which kept the HTTP connection open between requests and so no fix was required for that case as no communication problem arose.&lt;br /&gt;&lt;br /&gt;For this reason, if you have communication problems between BizTalk and a foreign web server, you should first check if the web server is explicitly closing the HTTP connection after every request.&lt;br /&gt;&lt;br /&gt;There is a &lt;a href="http://support.microsoft.com/kb/924638"&gt;Microsoft KB&lt;/a&gt; that explains the issue and also how to fix it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Identification of the problem.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;As mentioned in the KB, it is important to make sure that your problem is exactly what the KB refers to, so, I will explain how I diagnosed it on my BizTalk Server.&lt;br /&gt;&lt;br /&gt;Looking in the BizTalk Administration Console, I saw an abnormal amount of suspended service instances, most of them being of the type “Message”. I also noticed that all the suspended messages belonged to only a subset of our BizTalk applications.&lt;br /&gt;There was clearly something wrong and by checking the Windows Event Viewer, I saw that some BizTalk send ports had an unusual failure rate at the communication level. This explained why so many messages were suspended as messages failing to be sent through a port will be suspended.&lt;br /&gt;The Windows Event Viewer showed messages such as:&lt;br /&gt;&lt;blockquote&gt;A message sent to adapter "HTTP" on send port "XXX" with URI "http://www.zzz.com/Service" is suspended.&lt;br /&gt;Error details: Cannot access a disposed object.&lt;br /&gt;Object name: 'System.Net.Sockets.NetworkStream'.&lt;/blockquote&gt;And&lt;br /&gt;&lt;blockquote&gt;A message sent to adapter "HTTP" on send port "XXX" with URI "http://www.zzz.com/Service" is suspended.&lt;br /&gt;Error details: The underlying connection was closed: A connection that was expected to be kept alive was closed by the server.&lt;/blockquote&gt;&lt;br /&gt;After scratching my head on this issue for a while, I found out that all failing messages where those sent to a port using an HTTP adapter configured with an &lt;strong&gt;URI pointing to an Apache server&lt;/strong&gt;. Other ports using the HTTP adapter but configured to access an IIS server were working fine!&lt;br /&gt;&lt;br /&gt;I then used a network sniffer to see what was going on exactly and I saw something inconsistent in the HTTP headers:&lt;br /&gt;The header of the HTTP request contained:&lt;br /&gt;&lt;em&gt;Connection: Keep-Alive&lt;/em&gt;&lt;br /&gt;But the header of the HTTP response contained:&lt;br /&gt;&lt;em&gt;Connection: close&lt;br /&gt;server: IBM_HTTP_Server/6.0.2.3 Apache/2.0.47&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;So, even if the HTTP request specifies “&lt;em&gt;Connection: Keep-Alive&lt;/em&gt;”, the Apache Server still close the connection and replies with a “&lt;em&gt;Connection: close&lt;/em&gt;” in the header of the HTTP response. For reference regarding the &lt;em&gt;Connection&lt;/em&gt; HTTP header, see: &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10"&gt;http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solution.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;As it is not possible to change the &lt;em&gt;Connection: Keep-Alive&lt;/em&gt; header setting in the HTTP adapter shipped with BizTalk Server 2006, I googled a bit and found out the &lt;a href="http://support.microsoft.com/kb/924638"&gt;KB 924638&lt;/a&gt; I mentioned earlier in this article which provides 1 solution and 1 workaround for the problem.&lt;br /&gt;&lt;br /&gt;The hotfix mentioned in the KB contains a library that makes it possible to modify the Keep-Alive configuration for the HTTP connection. However, as there is no option to set the header setting from the BizTalk Administration Console, it is required to create a custom pipeline which writes a &lt;em&gt;KeepAlive&lt;/em&gt; property in the context of the message going through the pipeline. Later on, the HTTP adapter will read the &lt;em&gt;KeepAlive&lt;/em&gt; message context property value and create the HTTP connection accordingly.&lt;br /&gt;&lt;br /&gt;You can find &lt;a href="http://www.malgreve.net/blog_files/HttpKeepAlive.zip"&gt;here&lt;/a&gt; a zip file containing 2 Visual Studio projects, one for the Custom Pipeline Component and another one for the Custom Pipeline. In this custom pipeline, the &lt;em&gt;KeepAlive&lt;/em&gt; property is not hard-coded and so its value can be set either from the BizTalk Administration Console at run-time or from Visual Studio at design-time.&lt;br /&gt;&lt;br /&gt;To summarize, there are 3 steps to apply the solution:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Call Microsoft Support so that they email you the hotfix containing an executable which updates the Microsoft.BizTalk.HttpTransport.dll (as the hotfix is not directly available to download from the KB).&lt;/li&gt;&lt;li&gt;Create a custom pipeline which has a property that permits the user to specify the Keep-Alive setting.&lt;/li&gt;&lt;li&gt;Use the custom pipeline in the send ports that are pointing to web servers explicitly closing connections, such as some Apache web server.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-7629438704172544078?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/7629438704172544078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=7629438704172544078' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/7629438704172544078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/7629438704172544078'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/09/http-adapter-and-apache-keep-alive.html' title='HTTP Adapter and Apache Keep-Alive issue'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-6116293002399763114</id><published>2007-09-12T01:41:00.001+07:00</published><updated>2007-09-12T01:44:24.760+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk Server 2006 R2'/><title type='text'>BizTalk Server 2006 R2 released</title><content type='html'>&lt;a href="http://www.microsoft.com/biztalk/default.mspx"&gt;BizTalk Server 2006 R2&lt;/a&gt; has just been released.&lt;br /&gt;&lt;br /&gt;The key new features differentiating the new release from BizTalk Server 2006 are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Native support for Electronic Data Interchange (EDI).&lt;/li&gt;&lt;li&gt;Native support of Radio Frequency Identification (RFID).&lt;/li&gt;&lt;li&gt;While BizTalk Server 2006 integrates with Microsoft Office 2003 components and Windows XP (on a client OS), BizTalk Server 2006 R2 integrates with Office 2007 and Windows Vista.&lt;/li&gt;&lt;li&gt;Can make use of .Net 3.0 technologies such as Windows Communication Foundation (WCF) for messaging and Windows Workflow Foundation for BAM (Business Activity Monitoring).&lt;/li&gt;&lt;li&gt;New edition of BizTalk, called BizTalk Server &lt;em&gt;Branch&lt;/em&gt; Edition. This edition is ideal for &lt;em&gt;Hub and Spoke&lt;/em&gt; deployment scenarios for which only 1 BizTalk application is running in the &lt;em&gt;Spoke&lt;/em&gt; nodes. Its official price is 1,800 USD; making it less than a quarter of the price of BizTalk Server Standard Edition. See &lt;a href="http://www.microsoft.com/biztalk/editions/default.mspx"&gt;BizTalk Server Editions&lt;/a&gt; for more details. &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Both BizTalk Server 2006 and 2006 R2 supports only Visual Studio 2005 so far.&lt;br /&gt;Visual Studio 2008 will be supported through a BizTalk Server Service Pack so that the BizTalk installation routine will be able to detect VS2008 and run with it.&lt;br /&gt;&lt;br /&gt;For some, RFID is the most exciting feature introduced with BizTalk Server 2006 R2. The BizTalk RFID features include:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Data management capabilities.&lt;/li&gt;&lt;li&gt;Device abstraction and management capabilities.&lt;/li&gt;&lt;li&gt;Event processing engine that allows the creation of business rules and manage the execution of event pipelines for RFID events.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For more details about the new features of BizTalk Server 2006 R2, check the &lt;a href="http://www.microsoft.com/biztalk/evaluation/roadmap/default.mspx"&gt;BizTalk Server roadmap&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-6116293002399763114?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/6116293002399763114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=6116293002399763114' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6116293002399763114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/6116293002399763114'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/09/biztalk-server-2006-r2-released.html' title='BizTalk Server 2006 R2 released'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-5667412704192276319</id><published>2007-09-05T23:48:00.001+07:00</published><updated>2007-09-05T23:48:31.665+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>Functoid and BizTalk Application Versioning Problem</title><content type='html'>&lt;strong&gt;1. Problem:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I encountered a problem difficult to diagnose related to deploying a BizTalk Server 2006 application and a functoid that have been compiled together but then deployed with different versions.&lt;br /&gt;For example, let’s say you have developed and compiled a BizTalk application “A” version 1 using a functoid “F” version 1. Later on, you change some of the code inside the functoid and so you have a new version of the functoid, let’s call it functoid “F” version 2. &lt;br /&gt;Note that by version 1 and 2, I do not mean the assembly version number; it is just a nomenclature I use to differentiate the versions. In my case, the assembly’s version number is fixed.&lt;br /&gt;I often deploy new versions of functoids without having to recompile neither redeploy the BizTalk application but this time, the following error message appeared:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Microsoft.XLANGs.Core.XTransformationFailureException: Error encountered while executing the transform XXXX. Error:Unable to create the transform.. ---&gt; System.ArgumentNullException: Value cannot be null.&lt;br /&gt;Parameter name: extension&lt;br /&gt;   at System.Xml.Xsl.XsltArgumentList.AddExtensionObject(String namespaceUri, Object extension)&lt;br /&gt;   at Microsoft.XLANGs.BaseTypes.TransformBase.get_TransformArgs()&lt;br /&gt;   at Microsoft.XLANGs.RuntimeTypes.TransformMetaData..ctor(Type transformBaseType)&lt;br /&gt;   at Microsoft.XLANGs.RuntimeTypes.TransformMetaData._creator(Type t)&lt;br /&gt;   at Microsoft.XLANGs.RuntimeTypes.MetadataCache._slowFor(Type t)&lt;br /&gt;   at Microsoft.XLANGs.RuntimeTypes.MetadataCache.For(Type t)&lt;br /&gt;   at Microsoft.XLANGs.RuntimeTypes.TransformMetaData.For(Type t)&lt;br /&gt;   at Microsoft.XLANGs.Core.Service.ApplyTransform(Type mapRef, Object[] outParams, Object[] inParams)&lt;br /&gt;   --- End of inner exception stack trace ---&lt;br /&gt;   at Microsoft.XLANGs.Core.Service.ApplyTransform(Type mapRef, Object[] outParams, Object[] inParams)&lt;br /&gt;   at Tourico.Tourico_SmartSearch.segment2(StopConditions stopOn)&lt;br /&gt;   at Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception&amp; exp)&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Solution:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The message was &lt;strong&gt;not&lt;/strong&gt; recorded in the Windows Event Log but as I catch and log exceptions in an exception handler; I could see the exception in my log.&lt;br /&gt;As the message is rather vague, I spent quite a lot of time checking the maps and schemas used in the orchestration but found no clue.&lt;br /&gt;I finally noticed that a functoid’s code had been changed and once &lt;strong&gt;I recompiled and re-deployed the BizTalk Application, everything worked fine!&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I am not sure of the exact reason as normally you don’t need to redeploy the BizTalk application after having updated and GACed a functoid.&lt;br /&gt;Anyway, if one day you encounter an error message of the same flavor, recompiling and redeploying the application might just work fine. Maybe this hint can help someone in the future :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. Note about exception handler in BizTalk Server 2006.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;For the people who do not know, you just need to use a scope shape and its exception handler to have the equivalent of a try-catch block in a BizTalk orchestration. That gives you the opportunity to take action and/or log errors when exceptions are thrown from the orchestration.&lt;br /&gt;&lt;br /&gt;To create an exception handler, drop a scope shape into your orchestration, right click on it and select “New Exception Handler”. Note that only scopes that are non-transactional or long running transactional can have an exception handler.&lt;br /&gt;Here is how it looks like:&lt;br /&gt;&lt;a href="http://www.malgreve.net/uploaded_images/scope_shape_with_exception_handler-708515.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.malgreve.net/uploaded_images/scope_shape_with_exception_handler-708511.jpg" border="0" alt="Scope shape with its exception handler" /&gt;&lt;/a&gt;&lt;em&gt;Everything in the first square (Scope_1) will be the “try” part and everything in the second square (CatchException_1) will be the “catch” part.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-5667412704192276319?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/5667412704192276319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=5667412704192276319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/5667412704192276319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/5667412704192276319'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/09/functoid-and-biztalk-application.html' title='Functoid and BizTalk Application Versioning Problem'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2349891517694519380.post-12814174674159266</id><published>2007-08-27T21:23:00.000+07:00</published><updated>2007-10-19T18:51:47.949+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BizTalk 2006'/><title type='text'>Biztalk 2006 multiserver installation</title><content type='html'>This article explains how to install BizTalk Server 2006 on multiple servers for a configuration with 1 SQL Server and 1 BizTalk Server.&lt;br /&gt;&lt;br /&gt;Doing a multiserver BizTalk installation should be done once for practice before doing it on the production servers so that all the specificities to a multiserver install are well understood.&lt;br /&gt;I will here share my experience in a practice multiserver BizTalk installation done on 2 Virtual Machines.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Simplified BizTalk Server Installation scenario.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;For a first multiserver installation, I will keep a simplified scenario with only 2 servers and neither BAS nor BAM features installed. Only the following components will be installed:&lt;br /&gt;  - Enterprise Single Sign-On (SSO).&lt;br /&gt;  - BizTalk Group.&lt;br /&gt;  - BizTalk Runtime.&lt;br /&gt;  - MSMQT.&lt;br /&gt;  - Business Rule Engine.&lt;br /&gt;&lt;br /&gt;There will be 2 virtual servers:&lt;br /&gt;  - 1 Virtual Machine to host SQL Server and act as a Domain Controller&lt;br /&gt;  - 1 Virtual Machine to host BizTalk Server.&lt;br /&gt;&lt;br /&gt;This is the most basic multi-server install possible. It will nevertheless help you to understand how a multi-server BizTalk installation works.&lt;br /&gt;For more complex installation scenarios with BAM, BAS and/or clustered servers, Microsoft provides a complete installation guide document, “BizTalk Server 2006 Installation Guide - Multiserver”. See in the reference section of this article for a link to the documentation.&lt;br /&gt;&lt;br /&gt;Note that to follow this article as a lab, you will need the following software:&lt;br /&gt;- Microsoft Virtual PC 2007 (Virtual PC is now free and you can download it &lt;a href="http://www.microsoft.com/windows/products/winfamily/virtualpc/default.mspx"&gt;here&lt;/a&gt;)&lt;br /&gt;- Windows Server 2003&lt;br /&gt;- SQL Server 2005&lt;br /&gt;- BizTalk Server 2006&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;The need for a Domain Controller.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A very important difference between a single server and a multi-server installation is that the multi-server configuration requires you to use domain users and groups to run the various BizTalk services making having a domain controller a necessity.&lt;br /&gt;On the other hand, a single server configuration can run with local windows groups and users.&lt;br /&gt;To be more precise, these domain accounts and groups are used for the security configuration of the BizTalk Server databases. Indeed, the user account which runs the BizTalk server service must have access to the SQL Server. As SQL Server is installed on a separate machine, the use of a domain user account is therefore a necessity so that the account can have access rights on both the BizTalk machine and the SQL Server machine.&lt;br /&gt;&lt;br /&gt;The important point to remember is that when you plan to install a multi-server configuration of BizTalk in your production environment, you will have to check with your hosting company to have access to a domain controller or to have them create all the necessary domain users and groups.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Create Domain Groups and Users.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;For a single server installation, the setup procedure is able to create the Windows Groups and Users necessary for BizTalk as they are created on the local machine.&lt;br /&gt;On a multi server installation, &lt;strong&gt;BizTalk Windows Groups and Users must be created manually on the Domain Controller&lt;/strong&gt;. The setup procedure is &lt;strong&gt;not&lt;/strong&gt; able to create the Windows Groups and Users on a Domain Controller.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;BizTalk Installation, Configuration and Applications Deployment considerations.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;To be able to install and configure BizTalk Server 2006, &lt;em&gt;you have to log on the server using a Domain User who has &lt;strong&gt;Administrator&lt;/strong&gt; rights on both the SQL Server and the BizTalk Server&lt;/em&gt;. Moreover, that domain user must also be part of the &lt;em&gt;&lt;strong&gt;BizTalk Server Administrators&lt;/strong&gt;&lt;/em&gt; group and the &lt;em&gt;&lt;strong&gt;SSO Administrators group&lt;/strong&gt;&lt;/em&gt;.&lt;br /&gt;The user must also have the &lt;em&gt;&lt;strong&gt;sysadmin&lt;/strong&gt; role on the SQL Server&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;I found out something that is, as far as I know,&lt;span style="font-weight:bold;"&gt; NOT mentionned in the BizTalk documentation:&lt;/span&gt; &lt;span style="font-style:italic;"&gt;the user installing BizTalk Server must also have the &lt;span style="font-weight:bold;"&gt;Domain Administrator&lt;/span&gt; role&lt;/span&gt;. Technically,  this privilege does not have to be granted when installing BizTalk Server but only when configuring it. It is because when the BizTalk Server Configuration tool runs, the tool must be able to check if the Windows accounts assigned to the various BizTalk services belong to the Windows groups set for these services. Only a user being domain administrator has the right to check other users properties.&lt;br /&gt;&lt;br /&gt;After BizTalk Server is configured and installed, the user does not have to be part of the Domain Administrators group anymore. Moreover, its privileges on the SQL Server can be lowered to dbo instead of administrator. That way the user can be used to install BizTalk Applications without having unnecessary privileges.&lt;br /&gt;FYI, installing BizTalk application creates tables, and executes SP on the BizTalk DBs.&lt;br /&gt;&lt;br /&gt;To simplify things I advise to create a “&lt;em&gt;BTSAdmin&lt;/em&gt;” domain user who has these rights. Only the person who will install, configure and manage BizTalk applications should have that user login information.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B273269C-97E0-411D-8849-5A8070698E4A&amp;amp;displaylang=en"&gt;The BizTalk Server 2006 installation guide&lt;/a&gt; provides a list of all the necessary Groups and User that need to be created. Microsoft also provides a &lt;a href="http://msdn2.microsoft.com/en-us/library/aa950047.aspx"&gt;best practice guide on how to implement the Windows Groups and Users for BizTalk Server 2006&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Microsoft Distributed Transaction Coordinator (MS DTC) considerations.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Network DTC access&lt;/em&gt; and &lt;em&gt;Network COM+ access&lt;/em&gt; must but enabled for all BizTalk and SQL servers. It is turned off by default on Windows Server 2003.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SQL Server Considerations.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;SQL Server client tools must be installed on all BizTalk servers. The client Tools installed must be of the same version as the SQL Server installed.&lt;br /&gt;SQL server must be started and running when running the BizTalk Server Configuration tool.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. Creating the Virtual Servers.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;To install the Virtual Servers, you will need Microsoft Virtual PC 2007 and Windows Server 2003.&lt;br /&gt;&lt;br /&gt;In this step, we will create 2 Virtual Machines, one named &lt;strong&gt;SQLServer&lt;/strong&gt; and another one named &lt;strong&gt;BizTalkServer&lt;/strong&gt;. Windows Server 2003 will be the OS installed on both of them.&lt;br /&gt;The machine named &lt;strong&gt;SQLServer&lt;/strong&gt; will run SQL Server and also act as a Domain Controller while &lt;strong&gt;BizTalkServer&lt;/strong&gt; will host BizTalk Server.&lt;br /&gt;&lt;br /&gt;As installing Windows Server 2003 on a virtual machine is particularly slow, please refer to a previous post that explains &lt;a href="http://www.malgreve.net/2007/08/cloning-virtual-server-machine.html"&gt;how to install and clone virtual servers efficiently&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Once the 2 virtual machines are ready, set their networking setting to “&lt;strong&gt;Local only&lt;/strong&gt;”. This option gives you networking support between virtual machines only. For a description of the different network settings available for Virtual PC, check the following link: &lt;a href="http://support.microsoft.com/kb/833134"&gt;http://support.microsoft.com/kb/833134&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Installing the Domain Controller and creating Windows User and Groups.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.1. Complete the setup of the SQLServer Virtual Machine.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;1. Rename the VM&lt;/em&gt;&lt;/strong&gt;. If you created the &lt;strong&gt;SQLServer&lt;/strong&gt; Virtual Machine by using a base virtual machine and “sysprepped” it, you will need to rename it first. To do so, go to Control Panel &gt; System &gt; Computer Name and click “&lt;em&gt;Change&lt;/em&gt;”. Input “&lt;strong&gt;&lt;em&gt;SQLServer&lt;/em&gt;&lt;/strong&gt;” in the machine name field. When prompted, do not restart the machine yet.&lt;br /&gt;&lt;strong&gt;&lt;em&gt;2. Set the Virtual Machine IP address&lt;/em&gt;.&lt;/strong&gt; Set the SQLServer VM to have a static IP address of 192.168.0.1 - The 192.168.x.x address range is a typical IP range for &lt;a href="http://en.wikipedia.org/wiki/Private_network"&gt;private networks&lt;/a&gt;.&lt;br /&gt;To modify the IP address of the VM, go to Control panel -&gt; Network Connections -&gt; Local Area Connection -&gt; Properties -&gt; TCP/IP -&gt; Properties and use 192.168.0.1 for the IP address as well as the DNS server. In the subnet mask field type in 255.255.255.0 and leave the default gateway blank.&lt;br /&gt;&lt;br /&gt;You &lt;strong&gt;must&lt;/strong&gt; now reboot the &lt;strong&gt;SQLServer&lt;/strong&gt; virtual machine.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.2. Installing the Domain Controller.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Start the &lt;strong&gt;SQLServer&lt;/strong&gt; virtual machine as it is the machine chosen to act as a Domain Controller (DC).&lt;br /&gt;For this step, have the Windows Server 2003 installation disk at hand as it might be needed.&lt;br /&gt;&lt;br /&gt;1. Make sure that you restarted the server after it has been renamed. This is because Active Directory can’t be installed after you changed the computer name without rebooting first.&lt;br /&gt;2. Run “&lt;em&gt;Manage Your Server&lt;/em&gt;”, and click “&lt;em&gt;Add or Remove a Role&lt;/em&gt;” (next to “&lt;em&gt;Adding Roles to Your Server&lt;/em&gt;” area).&lt;br /&gt;3. Select the radio button “&lt;em&gt;Typical configuration for a first server&lt;/em&gt;” and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;4. Type in “&lt;em&gt;&lt;strong&gt;biztalk.local&lt;/strong&gt;&lt;/em&gt;” for your Active Directory domain name and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. In the NetBIOS Name screen, accept the default setting and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;6. In the Forwarding DNS Queries screen, select “&lt;em&gt;No, do not forward queries&lt;/em&gt;” and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;7. Click “&lt;em&gt;Next&lt;/em&gt;” again and “&lt;em&gt;OK&lt;/em&gt;” in the pop up window. If prompted to insert Windows Server 2003 disk, click on “&lt;em&gt;Use Physical Drive&lt;/em&gt;” in the “&lt;em&gt;CD&lt;/em&gt;” menu of the windows containing the Virtual Machine. You might additionally have to point to some files in the &lt;em&gt;\I386&lt;/em&gt; folder located on the Windows Server installation disk.&lt;br /&gt;8. When the installation is almost complete, the VM will restart and finish the DC setup. Once the virtual machine has rebooted itself, a “&lt;em&gt;Server Configuration Progress&lt;/em&gt;” window will open; click “&lt;em&gt;Next&lt;/em&gt;” and “&lt;em&gt;Finish&lt;/em&gt;”. The domain controller installation is now completed.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note&lt;/strong&gt;: Once your server is promoted to be a Domain Controller, the local administrator is promoted to become the domain administrator.&lt;br /&gt;Moreover, it is not possible to log on the local machine anymore; you can only log on the domain. The concept of local Users and Groups doesn’t exist anymore and if you try to run &lt;em&gt;lusrmgr.msc&lt;/em&gt;, a message will be displayed saying that is not possible to manage local groups and users on a Domain Controller. Only domain groups and users can be created and managed.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.3. Create BizTalk Domain Users and Groups.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Start the Domain Controller, the &lt;strong&gt;SQLServer&lt;/strong&gt; VM.&lt;br /&gt;As we don’t install all the features of BizTalk Server, we create only a subset of the Windows Users and Groups defined for BizTalk Server 2006. This subset of Groups and Users is tailored for the features installed in this article.&lt;br /&gt;&lt;br /&gt;1. Run “&lt;em&gt;Manage Your Server&lt;/em&gt;” and click on “&lt;em&gt;Manage users and computers in Active Directory&lt;/em&gt;”, located next to the “&lt;em&gt;Domain controller (Active Directory)&lt;/em&gt;” area. This will open the &lt;em&gt;Active Directory Users and Computers MMC&lt;/em&gt; (Microsoft Management Console). Alternatively, you can open it by going to: Control Panel &gt; Administrative Tools &gt; Active Directory Users and Computers.&lt;br /&gt;2. Expand &lt;em&gt;biztalk.local&lt;/em&gt;&lt;br /&gt;3. &lt;em&gt;&lt;strong&gt;Create a BizTalk Organizational Unit&lt;/strong&gt;&lt;/em&gt;. To keep things tidy, we place the BizTalk Users and Groups in an Organizational Unit (OU). To do so, right click on “&lt;em&gt;biztalk.local&lt;/em&gt;” and click New -&gt; Organizational Unit. For the Organizational Unit name, enter “&lt;em&gt;&lt;strong&gt;Biztalk&lt;/strong&gt;&lt;/em&gt;”.&lt;br /&gt;4. &lt;em&gt;&lt;strong&gt;Create the Windows Groups&lt;/strong&gt;&lt;/em&gt;. These groups will be used for the security configuration of the BizTalk Server databases. Right click on the Organizational Unit “&lt;em&gt;BizTalk&lt;/em&gt;” and click New -&gt; Group. For each group created, enter the group name specified in the table bellow, keep the default settings and click “&lt;em&gt;OK&lt;/em&gt;”.&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Group Name&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SSO Administrators&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SSO Affiliate Administrators&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Server Administrators&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Server Operators&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Application Users&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Isolated Host Users&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;There are 6 Groups created in total.&lt;br /&gt;5. &lt;em&gt;&lt;strong&gt;Create the BizTalk Windows Service Accounts (Windows Users)&lt;/strong&gt;&lt;/em&gt;. Windows Users are required for the various BizTalk services. You might want to set all the users to use the same password so that managing them is easier. Right click on the Organizational Unit “&lt;em&gt;BizTalk&lt;/em&gt;” and click New -&gt; User. For each user created, enter the full name and the user logon name specified in the following table (under the “&lt;em&gt;Full Name&lt;/em&gt;” and “&lt;em&gt;User logon name&lt;/em&gt;” columns) and click “&lt;em&gt;Next&lt;/em&gt;”. In the following screen, enter the user’s password, uncheck “&lt;em&gt;User must change password at next logon&lt;/em&gt;”, check “&lt;em&gt;User cannot change password&lt;/em&gt;” and “&lt;em&gt;Password never expires&lt;/em&gt;”. Finally, click “&lt;em&gt;Next&lt;/em&gt;” and “&lt;em&gt;Finish&lt;/em&gt;”. Repeat the procedure for every Windows User.&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Full Name&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;User logon name&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Enterprise Single Sign-On Service&lt;/td&gt;&lt;td&gt;SSOService&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Administrator&lt;/td&gt;&lt;td&gt;BTSAdmin&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Host Instance Account&lt;/td&gt;&lt;td&gt;BTSAppHost&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Isolated Host Instance Account&lt;/td&gt;&lt;td&gt;BTSIsolatedHost&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Business Rule Engine Update Service Account&lt;/td&gt;&lt;td&gt;ReuService&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;6. &lt;em&gt;&lt;strong&gt;Add the Windows Service Accounts to their respective Groups&lt;/strong&gt;&lt;/em&gt;.&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Windows Group&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Windows User&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Server Administrators&lt;/td&gt;&lt;td&gt;biztalk\BTSAdmin&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SSO Administrators&lt;/td&gt;&lt;td&gt;biztalk\BTSAdmin and biztalk\SSOService&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Application Users&lt;/td&gt;&lt;td&gt;biztalk\BTSAppHost&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BizTalk Isolated Host Users&lt;/td&gt;&lt;td&gt;biztalk\BTSIsolatedHost&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;7. Close the Active Directory Users and Computers MMC.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;Remember that the Windows Users will be used to run the different BizTalk services and the Windows Groups are used to manage security and access rights to the SQL Server.&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;In case you would install all the BizTalk server features, you can find a complete list of Windows Users and Groups needed for BizTalk Server in &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B273269C-97E0-411D-8849-5A8070698E4A&amp;amp;displaylang=en"&gt;the BizTalk Server 2006 installation guide&lt;/a&gt;. You should also read the Microsoft &lt;a href="http://msdn2.microsoft.com/en-us/library/aa950047.aspx"&gt;guideline to implement Windows Groups and Users for BizTalk Server 2006&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.4. Chose the Domain User performing the BizTalk multiserver installation.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If you continue the installation procedure logged on the virtual servers with the Domain Administrator, you don’t need to do this step. Nevertheless, in real environments, you will most likely not want or have the possibility to use the Domain Administrator to install BizTalk Server. In that case, you will have to create a domain user who is &lt;em&gt;Administrator&lt;/em&gt; on both BizTalk and SQL Server machines and also member of the “&lt;em&gt;BizTalk Server Administrators&lt;/em&gt;” and “&lt;em&gt;SSO Administrators&lt;/em&gt;” groups.&lt;br /&gt;&lt;br /&gt;In this practice installation, we will choose the &lt;em&gt;BTSAdmin&lt;/em&gt; domain user that we have just created to execute the BizTalk Server 2006 multi-server installation. As we added &lt;em&gt;BTSAdmin&lt;/em&gt; in the “&lt;em&gt;BizTalk Server Administrators&lt;/em&gt;” and “&lt;em&gt;SSO Administrators&lt;/em&gt;” groups already, the remaining task is to give the user administrator privileges on both the &lt;strong&gt;SQLServer&lt;/strong&gt; and the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VMs.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2.5. Configure the SQLServer VM Administrator and SQL Server sysadmin Role.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;To give &lt;em&gt;BTSAdmin&lt;/em&gt; administrator privileges of the &lt;strong&gt;SQLServer&lt;/strong&gt; VM:&lt;br /&gt;1. Run “&lt;em&gt;Manage Your Server&lt;/em&gt;” and click on “&lt;em&gt;Manage users and computers in Active Directory&lt;/em&gt;”, next to the “&lt;em&gt;Domain controller (Active Directory)&lt;/em&gt;” zone.&lt;br /&gt;2. Under the “&lt;em&gt;Builtin&lt;/em&gt;” folder, add “&lt;em&gt;biztalk\BTSAdmin&lt;/em&gt;” to the “&lt;em&gt;Administrators&lt;/em&gt;” group. Note that in our lab this will unintentionally make the BTSAdmin user a domain administrator, but in a normal scenario, SQL Server would not be a Domain Controller and so BTSAdmin would just be administrator of the local machine.&lt;br /&gt;&lt;br /&gt;As by default the Windows &lt;em&gt;Builtin\Administrators&lt;/em&gt; group has the &lt;em&gt;sysadmin&lt;/em&gt; SQL role on the SQL Server, the &lt;em&gt;BTSAdmin&lt;/em&gt; user will also have the &lt;em&gt;sysadmin&lt;/em&gt; role as &lt;em&gt;BTSAdmin&lt;/em&gt; is now part of the Administrators group. Once SQL Server is installed, you will be able to check that by opening the SQL Server Management Console, go to “&lt;em&gt;Security\Server Roles&lt;/em&gt;” and double click on the “&lt;em&gt;sysadmin&lt;/em&gt;” role. The pop up window will show all the windows and SQL logins having the &lt;em&gt;sysadmin&lt;/em&gt; role.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. Installing SQL Server.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3.1. Install SQL Server.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In this step, we will install SQL Server 2005 on the virtual machine that will host the BizTalk databases.&lt;br /&gt;&lt;br /&gt;Only a subset of the SQL Server 2005 components are needed for the BizTalk features we have chosen to install. These are: “&lt;em&gt;SQL Server Database Services&lt;/em&gt;” and “&lt;em&gt;Workstation components, Books Online and Development tools&lt;/em&gt;”.&lt;br /&gt;If you plan to install the BAM component of BizTalk Server, you will have to additionally install the following SQL Server 2005 components: “&lt;em&gt;Analysis Services&lt;/em&gt;”, “&lt;em&gt;Notification Services&lt;/em&gt;” and “&lt;em&gt;Integration Services&lt;/em&gt;”.&lt;br /&gt;&lt;br /&gt;The SQL Server service should use the &lt;em&gt;&lt;strong&gt;Local System account&lt;/strong&gt;&lt;/em&gt; as the &lt;em&gt;&lt;strong&gt;Service Account&lt;/strong&gt;&lt;/em&gt;, and you should configure the &lt;em&gt;&lt;strong&gt;SQL Server Agent&lt;/strong&gt;&lt;/em&gt; to start at the end of the setup.&lt;br /&gt;&lt;br /&gt;SQL Server 2005 installation procedure:&lt;br /&gt;1. Start the Virtual Machine &lt;strong&gt;SQLServer&lt;/strong&gt;. Log on using the domain user you have chosen to use for the BizTalk multiserver installation (see paragraph 2.4).&lt;br /&gt;2. Start the setup of SQL Server from its installation disk.&lt;br /&gt;3. On the &lt;em&gt;SQL Server Installation welcome&lt;/em&gt; screen, click “&lt;em&gt;Server components, tools, Books Online, and samples&lt;/em&gt;”.&lt;br /&gt;4. Accept the license terms and conditions and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. On the &lt;em&gt;Installing Prerequisites&lt;/em&gt; screen, click “&lt;em&gt;Install&lt;/em&gt;”. Note that all the necessary prerequisites, such as the .Net Framework 2.0, are present on the installation disk.&lt;br /&gt;6. Once the prerequisites are installed, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;7. On the &lt;em&gt;Welcome to the Microsoft SQL Server Installation wizard&lt;/em&gt;, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;8. On the &lt;em&gt;System Configuration Check&lt;/em&gt;, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;9. Enter the registration information on the &lt;em&gt;Registration&lt;/em&gt; screen, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;10. On the &lt;em&gt;Components to Install&lt;/em&gt; screen, chose the 2 components “&lt;em&gt;SQL Server Database Services&lt;/em&gt;” and “&lt;em&gt;Workstation components, Books Online and Development tools&lt;/em&gt;”, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;11. Leave the “&lt;em&gt;default instance&lt;/em&gt;” radio button selected on the Instance Name screen, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;12. On the &lt;em&gt;Service Account&lt;/em&gt; screen, make sure that the check box “&lt;em&gt;Customize for each service account&lt;/em&gt;” is cleared; select the radio button “&lt;em&gt;Use the built-in System account&lt;/em&gt;” with “&lt;em&gt;Local System&lt;/em&gt;” selected in the dropdown list. Note that you could also use a Windows User account instead and if you do so, enter a local account or domain account and its password. Lastly, tick the check box “&lt;em&gt;SQL Server Agent&lt;/em&gt;” in the “&lt;em&gt;Start Services&lt;/em&gt;” section so that the SQL Server Agent starts once the setup is completed. Click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;13. In the &lt;em&gt;Authentication mode&lt;/em&gt; select “&lt;em&gt;Windows Authentication Mode&lt;/em&gt;”. Note that Mixed Mode can also be used but it is potentially less secure and not advised by Microsoft. Click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;14. On the &lt;em&gt;Collation Settings&lt;/em&gt; screen leave the default and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;15. Click “&lt;em&gt;Next&lt;/em&gt;” again and then “&lt;em&gt;Install&lt;/em&gt;”.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3.2. Configuring the SQL Server Virtual Machine.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Once SQL Server is installed, you need to configure it.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3.2.1 Configure SQL Server for Remote Connections.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In order for the BizTalk servers to connect to SQL Server, remote connections need to be enabled.&lt;br /&gt;To do so you need to:&lt;br /&gt;1. Run &lt;em&gt;SQL Server Surface Area Configuration&lt;/em&gt;, found in Programs -&gt; Microsoft SQL Server 2005 -&gt; Configuration Tools&lt;br /&gt;2. Once the tool opens, click on &lt;em&gt;Surface Area Configuration for Services and Connections&lt;/em&gt;.&lt;br /&gt;3. Locate “&lt;em&gt;Remote connection&lt;/em&gt;” under the Database Engine tree and enable local and remote connections for both protocols by selecting “&lt;em&gt;Local and remote connections&lt;/em&gt;” and “&lt;em&gt;Using both TCP/IP and named pipes&lt;/em&gt;” radio buttons.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3.2.2. Configure Microsoft Distributed Transaction Coordinator (MS DTC).&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In order for BizTalk to run against its databases located on a remote SQL server, you will need to turn on MS DTC options (both on the SQL Server and BizTalk Server).&lt;br /&gt;Follow the next steps on the &lt;strong&gt;SQLServer&lt;/strong&gt; VM:&lt;br /&gt;1. Open the Control Panel and open “&lt;em&gt;Add or Remove Programs&lt;/em&gt;”. Once open, click “&lt;em&gt;Add/Remove Windows Components&lt;/em&gt;”.&lt;br /&gt;2. Once the Windows Components Wizard open, select “&lt;em&gt;Application Server&lt;/em&gt;” and click on de “&lt;em&gt;Details&lt;/em&gt;” button.&lt;br /&gt;3. Select the check boxes in front of “&lt;em&gt;Enable network COM+ access&lt;/em&gt;” and “&lt;em&gt;Enable network DTC access&lt;/em&gt;”. Click “&lt;em&gt;OK&lt;/em&gt;”&lt;br /&gt;4. You are now back to the Windows Components Wizard window; click “&lt;em&gt;Next&lt;/em&gt;” and then “&lt;em&gt;Finish&lt;/em&gt;”.&lt;br /&gt;5. Restart the server.&lt;br /&gt;&lt;br /&gt;If your SQL Server is installed on the Domain Controller like in this practice installation, enabling &lt;em&gt;Network DTC Access&lt;/em&gt; will not work as there is a bug between DTC and the Domain Controller service. I posted a previous article explaining the problem and how to solve it, see: &lt;a href="http://www.malgreve.net/2007/08/enabling-network-dtc-access-fails-on.html"&gt;Enabling network DTC access fails on a Domain Controller server&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3.3 Install and Configure Enterprise Single Sign-On Master Secret Server.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I chose to install the &lt;em&gt;Enterprise Single Sign-On Master Secret Server&lt;/em&gt; on the SQL Server virtual machine so that I could try it out.&lt;br /&gt;Nevertheless, it is more common to install the &lt;em&gt;Master Secret Server&lt;/em&gt; on the BizTalk Server machine when there is only 1 BizTalk machine.&lt;br /&gt;In case you have a cluster of several BizTalk Server machines, you can chose to either install the Master Secret Server on a separate machine (such as in this example) or install it on one of the BizTalk Server.&lt;br /&gt;&lt;em&gt;&lt;strong&gt;The points to remember are:&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;- There can be only &lt;strong&gt;1&lt;/strong&gt; machine being the Master Secret Server. It can either be one of the machines hosting BizTalk Server or any other.&lt;br /&gt;- All machines running BizTalk and the machine being the Master Secret Server will have the Enterprise Single Sign On Windows Service running.&lt;br /&gt;&lt;br /&gt;See the Microsoft documentation on installing BizTalk Server 2006 for more details on how to cluster SSO.&lt;br /&gt;&lt;br /&gt;1. Start up the BizTalk Server 2006 Installation.&lt;br /&gt;2. On the Microsoft BizTalk Server 2006 Installation Wizard page, click “&lt;em&gt;Install Microsoft BizTalk Server 2006 on this computer&lt;/em&gt;”.&lt;br /&gt;3. On the Customer Information page, type your user name and organization, and then click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;4. Accept the License Agreement and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. On the Component Installation page, select ONLY “&lt;em&gt;ESSO Administration Module&lt;/em&gt;” and “&lt;em&gt;ESSO Master Secret Server&lt;/em&gt;”, found under “&lt;em&gt;Additional Software&lt;/em&gt;”. Unselect all other components.&lt;br /&gt;6. After the installation, make sure that the checkbox “&lt;em&gt;Launch BizTalk Server Configuration&lt;/em&gt;” is selected and click on “&lt;em&gt;Finish&lt;/em&gt;”. The BizTalk Server Configuration will start.&lt;br /&gt;7. In the BizTalk Configuration, select the “&lt;em&gt;Custom Configuration&lt;/em&gt;” radio button. In the “&lt;em&gt;Service Credential&lt;/em&gt;” zone, type in “&lt;em&gt;&lt;strong&gt;BIZTALK\SsoService&lt;/strong&gt;&lt;/em&gt;” and its password. It is the domain account that will run the SSO Windows Service. Click “&lt;em&gt;Configure&lt;/em&gt;”.&lt;br /&gt;8. In the summary window, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;9. On the final window, click “&lt;em&gt;Finish&lt;/em&gt;”&lt;br /&gt;10. Use Event Viewer to verify the ENTSSO service has started successfully.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4. Installing BizTalk Server.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In this step, we will install the BizTalk prerequisites, BizTalk Server 2006 and operate the necessary configuration.&lt;br /&gt;&lt;em&gt;Before starting the BizTalk virtual machine, make sure that its network configuration setting is set to “&lt;strong&gt;local only&lt;/strong&gt;”.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.1. Complete the setup of the BizTalkServer VM.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;1. Start the virtual machine &lt;strong&gt;BizTalkServer&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;2. &lt;em&gt;&lt;strong&gt;Change machine name and join the domain&lt;/strong&gt;&lt;/em&gt;. If you created the &lt;strong&gt;BizTalkServer&lt;/strong&gt; Virtual Machine by using a base virtual machine and “sysprepped” it, you will have to rename the VM first. To do so, go to Control Panel -&gt; System -&gt; Computer Name and click “&lt;em&gt;Change&lt;/em&gt;”. Change the computer name to “&lt;strong&gt;BizTalkServer&lt;/strong&gt;”.&lt;br /&gt;In the same window, join the domain by selecting the “&lt;em&gt;Domain&lt;/em&gt;” radio button and type “&lt;strong&gt;biztalk.local&lt;/strong&gt;” for the Domain name. Click “&lt;em&gt;OK&lt;/em&gt;”. You will be prompted to enter the Domain Administrator user name and password.&lt;br /&gt;Before restarting the Virtual Machine you should execute the next step.&lt;br /&gt;&lt;br /&gt;3. &lt;em&gt;&lt;strong&gt;Set static IP address&lt;/strong&gt;&lt;/em&gt;. To modify the IP address of the VM, go to Control panel -&gt; Network Connections -&gt; Local Area Connection -&gt; Properties -&gt; TCP/IP -&gt; Properties and use 192.168.0.2 for the IP address, 255.255.255.0 for the subnet mask, leave the default gateway blank and set the DNS server IP to 192.168.0.1&lt;br /&gt;&lt;br /&gt;You can now reboot the &lt;strong&gt;BizTalkServer&lt;/strong&gt; virtual machine. Note that for the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM to boot and run properly as being part of the Domain, the virtual machine acting as the Domain Controller will have to be running as well. This means that from now on, the &lt;strong&gt;SQLServer&lt;/strong&gt; VM must already be running when you start the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.2. Configure BizTalkServer VM Administrator.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;strong&gt;From now on, you will always log on the BizTalkServer VM using a domain account so that you are logged on the domain.&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;If you chose to execute the installation of Biztalk Server 2006 for a multi-server environment using the Domain Administrator, you don’t need to do this step and you will log on the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM using the domain administrator account to you install BizTalk Server. Otherwise, continue.&lt;br /&gt;See paragraph 2.4 for more details about choosing a domain account to install BizTalk Server 2006.&lt;br /&gt;&lt;br /&gt;Once you have rebooted the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM, &lt;strong&gt;log on the machine using the Domain Administrator account&lt;/strong&gt;, so you have to log on the domain, not the local machine which is the default choice.&lt;br /&gt;&lt;br /&gt;We have previously chosen to give the domain user &lt;em&gt;BTSAdmin&lt;/em&gt; administrator privileges on both the &lt;strong&gt;SQLServer&lt;/strong&gt; and the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VMs so that it can execute the BizTalk setup procedure.&lt;br /&gt;&lt;br /&gt;To add &lt;em&gt;BTSAdmin&lt;/em&gt; user as an Administrator of the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM;&lt;br /&gt;1. Open “&lt;em&gt;Computer Management&lt;/em&gt;” found under Control Panel -&gt; Administrative Tools.&lt;br /&gt;2. Under the “&lt;em&gt;Builtin&lt;/em&gt;” folder, add “&lt;em&gt;biztalk\BTSAdmin&lt;/em&gt;” to the “&lt;em&gt;Administrators&lt;/em&gt;” group.&lt;br /&gt;&lt;br /&gt;You can know log off or reboot the &lt;strong&gt;BizTalkServer&lt;/strong&gt; VM and log on again using the &lt;strong&gt;BTSAdmin&lt;/strong&gt; domain user which is now administrator of the &lt;strong&gt;BizTalkServer&lt;/strong&gt; machine.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.3. Installing prerequisites.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.3.1 Install IIS 6.0.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;BizTalk server requires IIS for the HTTP Adapter, SOAP Adapter, Windows SharePoint Services Adapter, SSL encryption, Business Activity Services (BAS), Human Workflow Services (HWS).&lt;br /&gt;&lt;br /&gt;In this step you might need access to the Windows Server 2003 installation disk.&lt;br /&gt;&lt;br /&gt;IIS 6.0 installation procedure:&lt;br /&gt;1. Click Start, point to Control Panel, and then click “&lt;em&gt;Add or Remove Programs&lt;/em&gt;”.&lt;br /&gt;2. In the Add or Remove Programs dialog box, click “&lt;em&gt;Add/Remove Windows Components&lt;/em&gt;”.&lt;br /&gt;3. In the Windows Components Wizard, select “&lt;em&gt;Application Server&lt;/em&gt;” and then click “&lt;em&gt;Details&lt;/em&gt;”.&lt;br /&gt;4. Select “&lt;em&gt;ASP.NET&lt;/em&gt;” and make sure that “&lt;em&gt;Internet Information Services (IIS)&lt;/em&gt;”and “&lt;em&gt;Enable network COM+ access&lt;/em&gt;” are selected as well. Click “&lt;em&gt;OK&lt;/em&gt;”, and then click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. On the &lt;em&gt;Completing the Windows Components Wizard&lt;/em&gt; page, click “&lt;em&gt;Finish&lt;/em&gt;”.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.3.2 Install the .Net framework 2.0 or Visual Studio 2005.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;If the machine is used for the BizTalk runtime-only (such as on a production environment), you should install the .Net framework 2.0. You can download a redistributable version of .Net 2.0 framework &lt;a href="http://msdn2.microsoft.com/en-us/netframework/aa731542.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;If the machine is used for the BizTalk runtime and/or development, Visual Studio 2005 or the .Net Framework 2.0 SDK should be installed instead.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.3.3. Install SQL Server 2005 Client Tools.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;1. Insert the SQL Server 2005 DVD in the DVD-ROM drive and browse to the &lt;em&gt;\Tools&lt;/em&gt; folder and double click "&lt;em&gt;setup.exe&lt;/em&gt;".&lt;br /&gt;2. Accept the licensing agreement on the &lt;em&gt;End User License Agreement&lt;/em&gt; page and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;3. On the &lt;em&gt;Installing Prerequisites&lt;/em&gt; page, click “&lt;em&gt;Install&lt;/em&gt;”. Once the prerequisites are installed, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;4. On the &lt;em&gt;Welcome to the Microsoft SQL Server Installation Wizard&lt;/em&gt; page, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. On the &lt;em&gt;System Configuration Check&lt;/em&gt; page, ensure that there are no errors before you continue. Note that as we are running on a virtual machine there will be a warning for the “&lt;em&gt;Minimal Hardware Requirement&lt;/em&gt;”, ignore it and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;6. On the &lt;em&gt;Registration Information&lt;/em&gt; page, click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;7. On the &lt;em&gt;Feature Selection&lt;/em&gt; page, under “&lt;em&gt;Client Components&lt;/em&gt;”, select “&lt;em&gt;Will be installed on local hard drive&lt;/em&gt;” for the following Components: “&lt;em&gt;Connectivity Components&lt;/em&gt;”, “&lt;em&gt;Management Tools&lt;/em&gt;”, “&lt;em&gt;SQLXML Client Features&lt;/em&gt;” and “&lt;em&gt;Legacy Components&lt;/em&gt;”. Click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;8. Once the components are installed, click “&lt;em&gt;Next&lt;/em&gt;” and then “&lt;em&gt;Install&lt;/em&gt;”.&lt;br /&gt;9. Once the setup is finished, click “&lt;em&gt;Next&lt;/em&gt;” and then “&lt;em&gt;Finish&lt;/em&gt;”.&lt;br /&gt;10. Restart the virtual machine.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.3.4. Configure Microsoft Distributed Transaction Coordinator (MS DTC).&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;To be able to install BizTalk server (run the BizTalk Configuration tool, to be more precise), install BizTalk applications and run BizTalk applications, &lt;em&gt;network DTC access&lt;/em&gt; must be enabled.&lt;br /&gt;&lt;br /&gt;Follow the next steps to do so:&lt;br /&gt;1. Open the Control Panel and open “&lt;em&gt;Add or Remove Programs&lt;/em&gt;”. Once open, click “&lt;em&gt;Add/Remove Windows Components&lt;/em&gt;”.&lt;br /&gt;2. Once the &lt;em&gt;Windows Components Wizard&lt;/em&gt; open, select “&lt;em&gt;Application Server&lt;/em&gt;” and click on the “&lt;em&gt;Details&lt;/em&gt;” button.&lt;br /&gt;3. Select the check box in front of “&lt;em&gt;Enable network DTC access&lt;/em&gt;” and make sure that “&lt;em&gt;Enable network COM+ access&lt;/em&gt;” is also selected. Click “&lt;em&gt;OK&lt;/em&gt;”&lt;br /&gt;4. You are now back to the &lt;em&gt;Windows Components Wizard&lt;/em&gt; window; click “&lt;em&gt;Next&lt;/em&gt;” and then “&lt;em&gt;Finish&lt;/em&gt;”.&lt;br /&gt;5. Restart the VM.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.4. Installing BizTalk Server 2006.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.4.1. Considerations:&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Before you install BizTalk Server 2006, consider the following:&lt;br /&gt;- If your computer name is longer than 15 characters, BizTalk Server Configuration will not work.&lt;br /&gt;- The account you are logged on as must be part of the local administrators group and have DBA rights on SQL Server. After configuration is complete, you can lower the privileges to DBO.&lt;br /&gt;- When installing BizTalk Server, there will be prerequisites components to install such as ADOMD.NET, SQLXML 3.0 SP3... You can either let the BizTalk Installation Wizard download them and install them for you or you can pre-download a cab file that contains all the prerequisites. You can see a list of all the prerequisite components required by BizTalk server &lt;a href="http://msdn2.microsoft.com/en-us/library/aa577356.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;As we don’t have access to the internet from the Virtual Machine in this practice installation (we set the VM Network settings to "Local only"), we first need to download the &lt;a href="http://go.microsoft.com/fwlink/?LinkId=54668"&gt;BizTalk Server 2006 redistributable prerequisites cab file for Windows Server 2003 (32-bit) (BtsRedistW2k3EN32.cab)&lt;/a&gt; and then copy it on the virtual machine hard disk.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.4.2 Install BizTalk Server 2006.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;1. Start the &lt;strong&gt;BizTalkServer&lt;/strong&gt; Virtual Machine and log on using the domain user you have chosen to use for the BizTalk multiserver installation (see paragraph 2.4).&lt;br /&gt;2. Start up the BizTalk Server 2006 Installation; Double click on “&lt;em&gt;Setup.exe&lt;/em&gt;” located on the root of the BizTalk Server 2006 installation disk.&lt;br /&gt;3. On the &lt;em&gt;Microsoft BizTalk Server 2006 Installation Wizard&lt;/em&gt; page, click “&lt;em&gt;Install Microsoft BizTalk Server 2006 on this computer&lt;/em&gt;”.&lt;br /&gt;4. On the &lt;em&gt;Customer Information&lt;/em&gt; page, type your user name and organization, and then click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;5. Accept the License Agreement and click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;6. On the &lt;em&gt;Component Installation&lt;/em&gt; page, select the following components: “&lt;em&gt;Documentation&lt;/em&gt;”, “&lt;em&gt;Server Runtime (without Base EDI Adapter)&lt;/em&gt;”, “&lt;em&gt;Administration Tools&lt;/em&gt;” and “&lt;em&gt;Business Rules Components&lt;/em&gt;”. Click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;7. On the &lt;em&gt;Redistributable Prerequisites&lt;/em&gt; page, select “&lt;em&gt;Automatically install the redistributable prerequisites from a CAB file&lt;/em&gt;” and specify the cab file location. This is the cab file that we pre-downloaded in paragraph 4.4.1. Click “&lt;em&gt;Next&lt;/em&gt;”.&lt;br /&gt;8. On the &lt;em&gt;Summary&lt;/em&gt; page, verify that the components you selected to install are correct. Click “&lt;em&gt;Install&lt;/em&gt;”.&lt;br /&gt;9. On the &lt;em&gt;Installation Completed&lt;/em&gt; page, &lt;strong&gt;unselect&lt;/strong&gt; the “&lt;em&gt;Launch BizTalk Server Configuration&lt;/em&gt;” check box, and then click “&lt;em&gt;Finish&lt;/em&gt;”.&lt;br /&gt;10. You can eventually stop your virtual machine and commit your change if you are using undo disk so that you start a new session when you are running the &lt;em&gt;BizTalk Server Configuration&lt;/em&gt; tool.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.5. Check that MS DTC network access is enabled on all servers participating in the BizTalk multiserver installation.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The last step to install BizTalk Server 2006 is to run the Configuration Tool. For the BizTalk Server Configuration Tool to run, all SQL Server and BizTalk Server machines must have &lt;em&gt;Network DTC access&lt;/em&gt; and &lt;em&gt;Network COM+ access&lt;/em&gt; &lt;strong&gt;enabled&lt;/strong&gt;. So, before continuing and configure BizTalk, verify that this is the case on all the machines participating in the BizTalk multiserver installation.&lt;br /&gt;In paragraph 3.2.2, I highlighted that there is a bug in turning on Network DTC access on a machine which is a Domain Controller so, double checking that &lt;em&gt;Network DTC access&lt;/em&gt; is enabled on all machines can save you from a lot of trouble.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.6. Configure BizTalk Server and other components.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The BizTalk configuration is the most likely point of failure of the BizTalk multiserver installation. If you use Virtual Machine with undo disks, you should commit your changes to the VM’s virtual hard disk before running the &lt;em&gt;BizTalk Server Configuration Tool&lt;/em&gt; so that you have a fresh session when starting the configuration process. In that case, if the configuration fails, you will be able to cancel the change and go back to the state the Virtual Machine was before starting the BizTalk configuration. This means that the only thing you would have to re-do is to run the BizTalk Configuration again (after fixing the cause of the problem) but all previous installation tasks will be preserved.&lt;br /&gt;&lt;br /&gt;1. Starts the &lt;em&gt;BizTalk Server Configuration&lt;/em&gt; from the Microsoft BizTalk Server 2006 menu (Programs -&gt; Microsoft BizTalk Server 2006).&lt;br /&gt;2. Select the “&lt;em&gt;Custom configuration&lt;/em&gt;” radio button. “&lt;em&gt;Basic configuration&lt;/em&gt;” can be used for single server installation only. For the “&lt;em&gt;Database server name&lt;/em&gt;”, type in the name of the machine hosting SQL Server: "&lt;strong&gt;SQLServer&lt;/strong&gt;". For the “&lt;em&gt;User Name&lt;/em&gt;” type in "&lt;strong&gt;BIZTALK\BTSAdmin&lt;/strong&gt;" and its password. Click “&lt;em&gt;Configure&lt;/em&gt;”.&lt;br /&gt;3. You are now on the &lt;em&gt;Overview Panel&lt;/em&gt; of the BizTalk Configuration tool. You will now configure all the BizTalk components per section.&lt;br /&gt;4. &lt;em&gt;&lt;strong&gt;Enterprise SSO&lt;/strong&gt;&lt;/em&gt;. Click on Enterprise SSO; tick the checkbox “&lt;em&gt;Enable Enterprise Single Sign-On on this computer&lt;/em&gt;”. Select the radio Button “&lt;em&gt;Join an existing SSO Sytem&lt;/em&gt;”. For the Database configuration, make sure the Server Name is “&lt;em&gt;SQLServer&lt;/em&gt;” and the DB Name is “&lt;em&gt;SSODB&lt;/em&gt;”. Set the account name to “&lt;em&gt;&lt;strong&gt;BIZTALK\SsoService&lt;/strong&gt;&lt;/em&gt;” for running the SSO Windows Service.&lt;br /&gt;5. &lt;em&gt;&lt;strong&gt;Enterprise SSO Secret Backup&lt;/strong&gt;&lt;/em&gt;. No change as the &lt;em&gt;Master Secret Server&lt;/em&gt; is the &lt;strong&gt;SQLServer&lt;/strong&gt; machine, not the &lt;strong&gt;BizTalkServer&lt;/strong&gt; machine. See paragraph 3.3 in which we installed the &lt;em&gt;Enterprise SSO Master Secret Server&lt;/em&gt;. Once BizTalk is fully configured, you will be able to verify that by running the SSO Administration snap-in and check the value of "&lt;em&gt;SSO Secret Server&lt;/em&gt;" field under the "&lt;em&gt;system&lt;/em&gt;" sub-tree.&lt;br /&gt;6. &lt;em&gt;&lt;strong&gt;Group&lt;/strong&gt;&lt;/em&gt;. Tick the checkbox “&lt;em&gt;Enable BizTalk Server Group on this computer&lt;/em&gt;”. Select the radio button “&lt;em&gt;Create a new BizTalk Group&lt;/em&gt;”. Under “&lt;em&gt;Data Stores&lt;/em&gt;”, check that the Database Server Name is set to “&lt;em&gt;SQLServer&lt;/em&gt;” for the 3 BizTalk databases that will be created. Under “&lt;em&gt;BizTalk Administrative Roles&lt;/em&gt;”, change the Windows Group to use “&lt;em&gt;&lt;strong&gt;BIZTALK\BizTalk Server Administrators&lt;/strong&gt;&lt;/em&gt;” and “&lt;em&gt;&lt;strong&gt;BIZTALK\BizTalk Server Operators&lt;/strong&gt;&lt;/em&gt;”. Be careful that the default values are Windows Groups with the same name but local to the BizTalk machine (not the Groups defined in the Domain).&lt;br /&gt;7. &lt;em&gt;&lt;strong&gt;BizTalk Runtime&lt;/strong&gt;&lt;/em&gt;.  Tick the checkbox “&lt;em&gt;Register the BizTalk Server runtime components&lt;/em&gt;”. Make sure that both checkboxes “&lt;em&gt;Create BizTalk In-Process Host and Instance&lt;/em&gt;” and “&lt;em&gt;Create BizTalk Isolated Host and Instance&lt;/em&gt;” are checked. There is no need to tick the “&lt;em&gt;Trusted&lt;/em&gt;” checkboxes. Select “&lt;em&gt;Trusted&lt;/em&gt;” only if you want to pass the credentials (SSID and/or Party ID) of the sender when submitting messages to the MessageBox database. This is equivalent to creating a trust relationship between the servers.&lt;br /&gt;Under “&lt;em&gt;Windows Service&lt;/em&gt;”, Change the account names to “&lt;em&gt;&lt;strong&gt;BIZTALK\BTSAppHost&lt;/strong&gt;&lt;/em&gt;” for the BizTalk Host Instance Account and “&lt;em&gt;&lt;strong&gt;BIZTALK\BTSIsolatedHost&lt;/strong&gt;&lt;/em&gt;” for the BizTalk Isolated Host Instance Account.&lt;br /&gt;Under “&lt;em&gt;Windows Group&lt;/em&gt;”, change the Windows Group to “&lt;em&gt;&lt;strong&gt;BIZTALK\BizTalk Application Users&lt;/strong&gt;&lt;/em&gt;” and “&lt;em&gt;&lt;strong&gt;BIZTALK\BizTalk Isolated Host Users&lt;/strong&gt;&lt;/em&gt;”. Be careful that the default values are Windows Groups with the same name but local to the BizTalk machine.&lt;br /&gt;8. &lt;em&gt;&lt;strong&gt;MSMQT&lt;/strong&gt;&lt;/em&gt;. No changes.&lt;br /&gt;9. &lt;em&gt;&lt;strong&gt;Business Rule Engine&lt;/strong&gt;&lt;/em&gt;. Tick the checkbox “&lt;em&gt;Enable Business Rules Engine on this computer&lt;/em&gt;”. Make sure that the Server Name is “&lt;em&gt;SQLServer&lt;/em&gt;” and the Database Name is “&lt;em&gt;BizTalkRuleEngineDB&lt;/em&gt;”.&lt;br /&gt;Under “&lt;em&gt;Windows Service&lt;/em&gt;”, set the Account name to “&lt;em&gt;&lt;strong&gt;BIZTALK\ReuService&lt;/strong&gt;&lt;/em&gt;”.&lt;br /&gt;10. &lt;em&gt;&lt;strong&gt;HWS Runtime&lt;/strong&gt;&lt;/em&gt;. No changes.&lt;br /&gt;11. &lt;em&gt;&lt;strong&gt;BAM Tools&lt;/strong&gt;&lt;/em&gt;. No changes.&lt;br /&gt;12. &lt;em&gt;&lt;strong&gt;BAM Alerts&lt;/strong&gt;&lt;/em&gt;. No changes.&lt;br /&gt;13. The configuration is now finished. Click on “&lt;em&gt;Apply configuration&lt;/em&gt;”. Review the configuration settings and click “&lt;em&gt;Next&lt;/em&gt;”. This is the most likely point of failure in this lab, hence the usefulness of undo disks. If things go bad, look at the problem carefully (you can find clues from the log file generated by the BizTalk Server Configuration tool) and check that you have completed every step of the setup correctly on each server.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4.7. Verify Configuration.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;You can check if the configuration went well by having a look at the Windows Event Log, there should be a lot of Information entries and no errors or warning related to BizTalk.&lt;br /&gt;&lt;br /&gt;You should also start the BizTalk Server administration console and verify the BizTalk Server host instance is started (found under BizTalk Group\Platform Settings\ Host Instances). Try stopping and starting the host instance.&lt;br /&gt;&lt;br /&gt;Finally, deploy and test a simple orchestration, such as the &lt;a href="http://msdn2.microsoft.com/en-us/library/aa559831.aspx"&gt;HelloWorld orchestration&lt;/a&gt; found in the BizTalk SDK samples.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;5. References.&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B273269C-97E0-411D-8849-5A8070698E4A&amp;amp;displaylang=en"&gt;MS documentation - BizTalk Server 2006 Installation and Upgrade Guides&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download.microsoft.com/download/1/A/6/1A67C784-8802-4E7E-A3BF-2772C34BB4AE/BTS2006_Setup.doc%20"&gt;Simplified BizTalk Server 2006 Installation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/aa950047.aspx"&gt;Guidelines for Implementing Active Directory Permissions on Multi Server BizTalk Installations&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='http://res1.blogblog.com/tracker/2349891517694519380-12814174674159266?l=www.malgreve.net%2Findex.html'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/12814174674159266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=2349891517694519380&amp;postID=12814174674159266' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/12814174674159266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2349891517694519380/posts/default/12814174674159266'/><link rel='alternate' type='text/html' href='http://www.malgreve.net/2007/08/biztalk-2006-multiserver-installation.html' title='Biztalk 2006 multiserver installation'/><author><name>Francois Malgreve</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry></feed>
