tag:blogger.com,1999:blog-74926422024-03-18T12:56:17.607+01:00Martijn's blog - E-Commerce, EAI, BizTalk and .NETMartijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.comBlogger95125tag:blogger.com,1999:blog-7492642.post-1168251997966465532007-01-08T11:24:00.000+01:002007-01-08T11:26:37.986+01:00Moving my blog to MSDNJanuary 1st, 2007, I started working for Microsoft and will be moving to http://blogs.msdn.com/martijnh/. Hope to see you there!Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com12tag:blogger.com,1999:blog-7492642.post-1167144236892558652006-12-26T15:41:00.000+01:002006-12-26T15:44:38.326+01:00Outlook: Recovering e-mail messages from attachmentsRecently, I was what I thought to be dragging e-mail from my Inbox into my Personal Folders. Outlook warned me that the process could take some time due to the amount of messages selected, but I went ahead with the move. After a while, Outlook popped up a freshly created e-mail message containing my 1000+ e-mail messages! <br /><br />The new e-mail was about 85MB and the original message were gone from my inbox... I really wanted those e-mails in my Personal Folders. However, Outlook programming is something I've always shied away from. After some experimenting, I discovered what I wanted couldn't be easily done using Outlook APIs...<br /><br />I wanted to:<br /><ol><li>Open the e-mail message containing the attached 1000+ 'backups'</li><li>Iterate the attachments</li><li>Save the attachments as e-mails into my Personal Folders box</li></ol>After a lot of headache, I discovered Redemption (see http://www.dimastr.com/redemption/). Redemption provides interop between .NET and the Extended MAPI. Using redemption, I finally succeeded in achieving my goal. Just in case someone else outthere is as silly as I am, here's how I did it:<br /><blockquote>// To use this namespace you must set a<br />// reference to the Microsoft Outlook 11.0<br />// COM server. <br />using Microsoft.Office.Interop.Outlook;<br />using OutLookApp = Microsoft.Office.Interop.Outlook.Application;<br />using System.IO;<br />using rd = Redemption;<br /><br />ApplicationClass outLookApp = new ApplicationClass();<br />NameSpace outlookNS = outlookApp.GetNamespace("MAPI");<br /><br />MailItem attachmentsItem = (MailItem)outlookNS.GetItemFromID(messageId, null);<br /><br />// left out for clarity: find the Personal Folders->Inbox folder<br /><br />rd.MAPIUtils utils = new rd.MAPIUtils();<br />utils.MAPIOBJECT = outlookNS.MAPIOBJECT;<br /><br />foreach (Attachment a in attachmentsItem.Attachments)<br />{<br /> string attachmentFile = Path.GetTempFileName();<br /> a.SaveAsFile(attachmentFile);<br /><br /> MailItem underlyingItem = <br /> (MailItem)personalFolder.Items.Add(OlItemType.olMailItem);<br /><br /> rd.MessageItem neww = <br /> utils.GetItemFromMsgFile(attachmentFile, false);<br /><br /> underlyingItem.Save();<br /> <br /> MailItem placedItem = <br /> (MailItem)underlyingItem.Move(personalFolder);<br /><br /> neww.CopyTo(placedItem);<br />}</blockquote><br />This code misses all kinds of nice sanity checks, like whether the attachment actually is a MSG file, etc. It sufficed for my scenario and I now have the e-mails back. FYI :-DMartijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com7tag:blogger.com,1999:blog-7492642.post-1166961675867567802006-12-24T12:57:00.000+01:002006-12-24T13:01:15.883+01:00WPF - themes in SDKI'm probably the last one to notice, but just in case I'm not... The themes included in PresentationFramework are included in the SDK (zipped in WPFSamples.zip) under <br /><br />WPFSamples\Core\AeroTheme<br />WPFSamples\Core\ClassicTheme<br />WPFSamples\Core\LunaTheme<br />WPFSamples\Core\RoyaleTheme<br /><br />:-D Definitely inspirational stuff!Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1162579601072665712006-11-03T19:15:00.000+01:002006-11-03T19:46:41.110+01:00WPF - Writing an IMultiValueConverter (update)What I didn't realize in the previous blog entry regarding the subject was the fact that binding to a DependencyProperty and performing a string.Format blindly could lead to weird results, e.g.:<br /><blockquote><TextBlock><br /> <TextBlock.Text><br /> <MultiBinding <br /> Converter="{StaticResource StringFormatterConverter}" <br /> ConverterParameter="{}{0}, {1}"><br /> <Binding Path="Customer.Lastname" /><br /> <Binding Path="Customer.Firstname" /><br /> </MultiBinding><br /> </TextBlock.Text><br /></TextBlock></blockquote><br />Could convert to "<strong>DependencyProperty.UnsetValue, DependencyProperty.UnsetValue</strong>" The solution is pretty simple:<br /><blockquote>bool argumentsAreNullOrEmpty = true;<br /><br />// Check whether all values are null or unset.<br />foreach (object value in values)<br />{<br /> if (value != null && value != DependencyProperty.UnsetValue)<br /> {<br /> argumentsAreNullOrEmpty = false;<br /> break;<br /> }<br />}<br /><br />// If we have all empty or null arguments, we do nothing.<br />if (argumentsAreNullOrEmpty)<br />{<br /> return Binding.DoNothing;<br />}</blockquote><br />Happy WPFing!Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com7tag:blogger.com,1999:blog-7492642.post-1162486864715570822006-11-02T17:18:00.000+01:002006-11-02T18:01:05.863+01:00CAB: load your modules from your App.ConfigIn CAB, there's a 'special voodoo magic' file which defines which modules are to be loaded in the IoC process. The file is called ProfileCatalog.xml by default. <br /><br />We're currently using CAB in combination with an XBAP application. This leads to deployment issues, as ProfileCatalog.xml will be deployed in to a folder called Data by default and the modules configured in the file cannot be located. You can work around this issue, but I took the issue as an opportunity to replace the default implementation of IModuleEnumerator in CAB with my own. <br /><br />My implementation looks at the App.Config file for it's modules. All that's needed to use the new enumerator is to configure it:<br /><blockquote><configSections><br /> <section <br /> name="SolutionProfile" <br /> type="BankTellerModule.Services.ModulesSection, BankTellerModule" /><br /> <section <br /> name="CompositeUI" <br /> type="Microsoft.Practices.CompositeUI.Configuration.SettingsSection, Microsoft.Practices.CompositeUI" /><br /></configSections><br /><br /><CompositeUI><br /> <services><br /> <add<br /> serviceType="Microsoft.Practices.CompositeUI.Services.IModuleEnumerator, Microsoft.Practices.CompositeUI" instanceType="BankTellerModule.Services.ConfigurationModuleEnumerator, BankTellerModule" /><br /> </services><br /></CompositeUI><br /><br /><strong><SolutionProfile><br /> <Modules><br /> <add assemblyFile="BankTellerModule.dll" /><br /> </Modules><br /></SolutionProfile></strong></blockquote><br />The code for this behaviour will be available <a href="http://www.tachyons.demon.nl/ConfigurationModuleEnumerator.zip">here</a> in a few hours...Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com1tag:blogger.com,1999:blog-7492642.post-1162479572133908132006-11-02T15:48:00.000+01:002006-11-02T15:59:32.153+01:00ClickOnce deployment of XBAP application to remote IISTo ensure you don't encounter the issues we encountered, make sure you set the option "Rename all application files using the .deploy file extension". <br />You can find the option under Project properties -> Publish -> Options. <br /><br />If you don't use this option and your IIS is hardened, as it should be, you'll see your assemblies being rejected (404.2 return code in you W3 log files). The .2 subcode means the server is not allowed to serve .dll files. <br /><br />The deployment renames the files from e.g. BankTellerModule.dll -> BankTellerModule.dll.deploy. This ensures the files get served by IIS. Locally, the files are stored in C:\Documents and Settings\<user account>\local Settings\Apps\2.0 and renamed back to .dll.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1162477812977221532006-11-02T15:28:00.000+01:002006-11-02T15:30:12.996+01:00ClickOnce publishing XBAP applications and F5 debugging not workingSome times, when you publish an XBAP application using ClickOnce, you cannot debug the same application afterwards using F5. This is due to a change to the project settings (debug tab). The extension is removed from the command-line argument to PresentationHost.exe (-debug <insert shell>.xbap). Insert the .xbap extension and things work alright again.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com4tag:blogger.com,1999:blog-7492642.post-1162138751208528572006-10-29T17:18:00.000+01:002006-10-29T17:55:02.786+01:00Supporting WPF XML Browser Applications (XBAP) in a CompositeUI Application Block applicationCurrently, we’re building a real application in WPF for a local government. The application uses the MVC pattern quite heavily, so I did a test to see whether we could use the Composite UI Application Block (CAB, <a href="http://msdn.microsoft.com/practices/default.aspx?pull=/library/en-us/dnpag2/html/cab.asp">read</a> more about it’s architecture and use, <a href="http://www.microsoft.com/downloads/details.aspx?familyid=7B9BA1A7-DD6D-4144-8AC6-DF88223AEE19&displaylang=en">download</a> it from MSDN, play with the <a href="http://www.microsoft.com/downloads/details.aspx?familyid=AB44F082-3ABE-4583-8844-7252FF7C9638&displaylang=en">labs</a> to understand it) to enable easier composability in order to distribute our use cases more easily throughout the development team, decouple logic from UI even more, etc. <br /><br />It turns out the CAB currently doesn’t support WPF. After some searching, I discovered <a href="http://kentb.blogspot.com/2006/10/wpf-cab.html">Kent Boogaart</a> from Australia (thanks Dion!) is busy writing a support layer for WPF in CAB. So far, so good. Testing the <a href="http://www.users.on.net/kentcb/cab_wpf/CAB_WPF.zip">download</a> he provided, however, revealed the implementation doesn’t support so-called XBAP applications. <br /><br />XBAP application are browser hosted WPF applications and are different in some aspects to ‘traditional’ WPF applications. For instance, the Application object which is the root for all WPF applications, doesn’t allow you to call the Run method if the WPF application is running within a browser. This is because of the asynchronous nature of the webbrowser. <br /><br />After a few simple modifications to Kent’s code and a little more trickery, I had the BankTeller application working in XBAP. Well, sort of… The thing with CAB is that it assumes synchronous applications. An example of this (taken straight from Microsoft.Practices.CompositeUI.CabApplication):<br /><blockquote>public void Run()<br />{<br /> RegisterUnhandledExceptionHandler();<br /> Builder builder = CreateBuilder();<br /> AddBuilderStrategies(builder);<br /> CreateRootWorkItem(builder);<br /><br /> ...<br /><br /> rootWorkItem.FinishInitialization();<br /> rootWorkItem.Run();<br /> Start();<br /><br /><strong> // Whoops for non-blocking Start()s<br /> rootWorkItem.Dispose();<br /> if (visualizer != null)<br /> visualizer.Dispose();</strong><br />}</blockquote><br />As I explained earlier, XBAP applications take offense to calling the Run method on their Application, they’re asynchronous. In order to make XBAP applications work, a few modifications have to be made to CAB itself.<br /><ol><li>Don’t call Run on the Application class.</li><li>Ensure the correct UI element get’s displayed.</li><li>Remove the dispose calling from the main Run() method of Microsoft.Practices.CompositeUI.CabApplication.</li><li>Implement a correct IDisposable pattern for cleaning up resources once the Application is actually done with them.</li><li>Ensure we call Dispose to clean up used resources.</li></ol>For those just interested in the endresult, a modified WPF port capable of supporting CAB based applications in XBAP, you can download the <a href="http://www.tachyons.demon.nl/CAB_XBAP.zip">example</a>.<br /><br />If you’re interested in more detail about the changes I made and how I did this, please read the whitepaper I wrote, which can be downloaded <a href="http://www.tachyons.demon.nl/Supporting%20XML%20Browser%20Applications%20within%20CAB.doc">here</a>.<br /><br />A special thanks to Kent Boogaart for creating the WPF port for CAB, without which I wouldn’t have been able to put CAB to use in my WPF scenario!Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com10tag:blogger.com,1999:blog-7492642.post-1161111923586948802006-10-17T20:59:00.000+02:002006-10-17T21:17:14.876+02:00WPF - Using CompositeCollection to combine multiple sources for databindingAs I said before, I'll blog about things I learn and find interesting... ;-) Today, I realized there's a very easy way to combine different sources for a binding. It's done using what's called a <em>CompositeCollection</em>. Here's how it works:<br /><ol><li>Create a datasource (XmlDataProvider, ObjectDataProvider, ...)</li><li>Create a CollectionViewSource to look at the data in a specific way</li><li>Bind a control's Source/ItemsSource/... property to the CollectionViewSource</li><li>Add a view 'static' items</li><li>Bind to another view at the same or different data</li></ol>An example:<br /><blockquote><XmlDataProvider x:Key="MyData" XPath="/Info"><br /> <x:XData><br /> <Info xmlns=""><br /> <Item ID="12345" Name="Book 1" Price="$10.00" /><br /> <Item ID="24678" Name="Book 3" Price="$9.00" /><br /> </Info><br /> </x:XData><br /></XmlDataProvider><br /><br /><CollectionViewSource <strong>x:Key='a'</strong> Source="{Binding Source={StaticResource MyData}, XPath=<strong>Item/@Price</strong>}" /><br /><CollectionViewSource <strong>x:Key='b'</strong> Source="{Binding Source={StaticResource MyData}, XPath=<strong>Item/@Name</strong>}" /><br /></blockquote><br />We now have the two CollectionViewSource instances up and running. For example purposes, they're looking at the same datasource, but this could be anything else. Now, let's create a simple <em>ListBox</em> control which binds to both these CollectionViewSource instances and adds constant items..<br /><blockquote><ListBox><br /> <ListBox.ItemsSource><br /> <Binding><br /> <Binding.Source><br /> <<strong>CompositeCollection</strong>><br /> <em><ListBoxItem>My Constant Item</ListBoxItem></em><br /> <<strong>CollectionContainer</strong> Collection="{Binding Source={StaticResource a}}" /><br /> <<strong>CollectionContainer</strong> Collection="{Binding Source={StaticResource b}}" /><br /> </<strong>CompositeCollection</strong>><br /> </Binding.Source><br /> </Binding><br /> </ListBox.ItemsSource><br /></ListBox></blockquote><br />It's as easy as that. The output would be:<br /><br />My Constant Item<br />$10.00<br />$9.00<br />Book 1<br />Book 3<br /><br />Just like the <em>MergedDictionaries</em> within the <em>ResourceDictionary</em>, you can easily combine different sources of data and bind to those sources, even <em>TwoWay</em>.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com4tag:blogger.com,1999:blog-7492642.post-1160907912593765702006-10-15T11:45:00.000+02:002006-10-15T12:29:29.850+02:00WPF - Writing an IMultiValueConverterCurrently, I'm working on a project involving <a href="http://wpf.netfx3.com">WPF</a>. I will post my experiences from time to time. This week, I wrote a simple <a href="http://windowssdk.msdn.microsoft.com/en-us/library/system.windows.data.imultivalueconverter(VS.80).aspx"><em>IMultiValueConverter</em></a> implementation which can be used to format a set of bindings in a String.Format fashion. This is how it works:<br /><br />Define the class and assign a key to refer to it:<blockquote><Window.Resources><br /> <c:StringFormatterConverter<br /> x:Key="<em>StringFormatterConverter</em>" /><br /></Window.Resources></blockquote><br />Bind some element (GridViewColumn in this case) to a datasource, in this case something which has properties called LASTNAME and FIRSTNAME on it:<blockquote><GridViewColumn.DisplayMemberBinding><br /> <MultiBinding><br /> <Binding Path="LASTNAME" /><br /> <Binding Path="FIRSTNAME" /><br /> </MultiBinding><br /></GridViewColumn.DisplayMemberBinding></blockquote><br />Now set a converter on the MultiBinding:<br /><blockquote><MultiBinding <strong>Converter="{StaticResource <em>StringFormatterConverter</em>}" <em>ConverterParameter</em>="{}{0}, {1}"</strong>></blockquote><br />Both IValueConverter and IMultiValueConverter implement two methods:<br /><br /><ul><li>Convert</li><li>ConvertBack</li></ul>One for binding one direction and the other for the opposite direction (from->to).<br /><br />The <em>ConverterParameter</em> in the Converter is used to pass the format we'll be using to display the bound elements.<br />Let's look at a code sample (sanity checks are removed for readability purposes):<br /><blockquote>public class StringFormatterConverter : IMultiValueConverter<br />{<br /> public object Convert(<br /> object[] values,<br /> Type targetType,<br /> object parameter,<br /> System.Globalization.CultureInfo culture)<br /> {<br /> <strong>return string.Format(<br /> culture,<br /> formatArgument,<br /> values);</strong><br /> }<br /><br /> public object[] ConvertBack(<br /> object value,<br /> Type[] targetTypes,<br /> object parameter,<br /> System.Globalization.CultureInfo culture)<br /> {<br /> throw new NotImplementedException(<br /> "Unable to convert a formatted argument string back.");<br /> }<br />}</blockquote><br />It's that simple, WPF will pass the <em>values</em> to the converter and expects a converted value back. We format the values using the other supplied arguments, <em>parameter</em> ('{0}, {1}') and <em>culture</em>. <br /><br />You can use any string.Format argument you'd like; just remember to escape the first '{' sign, so the Xaml interpreter knows you don't mean to use a <a href="http://windowssdk.msdn.microsoft.com/en-us/library/ms747254(VS.80).aspx">Markup Extension</a>.<br /><br />Escaping the first brace is done by placing an empty mark extension in front of<br />the character ('{}{'). <br /><br />The namespace prefix 'c' refers to the assembly and namespace implementing the converter (e.g. <xmlns:c="clr-namespace:Martijn.Wpf.Converters" />Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1159636144699940652006-09-30T19:02:00.000+02:002006-09-30T19:09:04.740+02:00Clustering under Virtual Server - Don't forget to update the SID!When using Virtual Machines, I often copy an existing image to duplicate it. However, currently I'm clustering my BizTalk Server 2006 environment for high availability <a href="http://www.microsoft.com/technet/prodtechnol/virtualserver/deploy/cvs2005.mspx">using Virtual Server 2005</a>.<br /><br />After setting up the cluster, adding the secondary node didn't work, it kept saying 'Access Denied'. Normally, things like changing the LanManServer parameters or LMCompatibilityLevel fix this, but in this case, no dice..<br /><br />Until I remembered something trivial when using cloned images, the computer SID is the same in both images! Using the <a href="http://www.sysinternals.com/Utilities/NewSid.html">NewSID</a> tool, I updated the SID, rejoined the domain and added the secondary node to the cluster without trouble.<br /><br />Using my blog as a post-it note ;-)Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com1tag:blogger.com,1999:blog-7492642.post-1159617551881821322006-09-30T12:50:00.000+02:002006-09-30T13:59:11.936+02:00Renaming your BizTalk Server and Sql Server Agent jobsAfter renaming a BizTalk Server host, you need to configure the server using the BizTalk Server Configuration Wizard (in 2006). However, during the reconfiguration, you might encounter a state I did. In my case, a dialog came up stating <br /><br />'Failed to create Management database "BizTalkMgmtDb" on server "...". Cannot add, update, or delete a job (or its steps or schedules) that originated from an MSX server.<br /><br />SQL script file: "C:\Program Files\Microsoft BizTalk Server 2006\Schema\\btf_message_logic.sql"'<br /><br />This failure is caused by the Sql Server Agent still having the jobs configured by the old server. You cannot simply delete/update those jobs as Sql Server doesn't allow you to. <br /><br />A remedy to this situation is stated in <a href="http://support.microsoft.com/kb/281642/">this</a> KB article. <br /><br />However, this involves renaming the server back to the original name, rebooting, etc. A simpler solution is to update the <em>msdb..sysjobs</em> table and set the <em>originating_server</em> field to reflect the new name. <br /><br />After this update, the BizTalk Server Configuration Wizard will complete it's work successfully.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1158780774602936852006-09-20T21:06:00.000+02:002006-09-21T06:40:09.150+02:00Confusion regarding upgrading an Orchestration in BizTalk ServerThere seems to be some confusion regarding upgrading Orchestrations. Doug Girard has documented this in a blog post <a href="http://blogs.msdn.com/csdcustomerexperience/archive/2006/04/21/581032.aspx">here</a>, but recent webcasts indicate to the contrary. I thought I'd save others some time and confirm that Doug's absolutely right, upgrading an Orchestration version is a fact of<ol><li>deploying and binding the new version</li><li>unenlisting the current Orchestration (which doesn't suspend running Orchestration instances, but in fact removes instance subscriptions for the Orchestration)</li><li>starting the new version</li></ol>If you drop in a message between steps 2 and 3, BizTalk will fail with a "No Subscriptions Found" exception in the EventViewer. This means that to ensure your system will be able to pick up messages correctly, step 2 and 3 need to be executed within the scope of a transaction, as Doug suggests. All Orchestration actions for the v1 version will be dealt with appropriately.<br /><br />Doug Girard mentions a script for performing steps 2 and 3 in a single transaction to avoid dropped messages. <br /><br />The location of the script within the documentation is <a href="ms-help://MS.BTS.2006/BTS06Operations/html/f90025ec-3641-49ef-8918-88238d6ad420.htm">this</a> (copy+paste the location, clicking will not work). <br /><br />You can also find the C# code (it's not really a script) within the contents under Operations -> Managing BizTalk Server -> Deploying and Managing BizTalk Applications -> Updating BizTalk Applications -> Deploying and Starting a New Version of an Orchestration Programmatically.<br /><br />UPDATE: A colleague of mine, Martin Rienstra, mentioned that in spite of documentation to the contrary, the last two version number elements <strong>do</strong> matter in side by side and upgrading scenarios. I've tested it and he is right.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com0tag:blogger.com,1999:blog-7492642.post-1156582495231937942006-08-26T10:52:00.000+02:002006-08-26T10:54:55.246+02:00BizTalk Server Best Practices AnalyzerA bit late on noticing the download, but I thought I'd direct your attention to it if you missed it like I did. The Best Practices Analyzer is a tool which can do precisely what it says on the cover. It analyzes a lot of aspects regarding a BizTalk environment to see whether best practices have been implemented. A must have for any release manager, IT pro, and even developers!<br /><br />The tool can be downloaded <a href="http://www.microsoft.com/technet/prodtechnol/biztalk/downloads/bpa.mspx">here</a>.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com0tag:blogger.com,1999:blog-7492642.post-1145949178664606852006-04-25T07:43:00.000+02:002006-04-26T14:26:46.703+02:00Microsoft Business Rules Engine (MS-BRE) - XmlTrackingInterceptorA lot of businesses have a need to prove what their software has done in evaluating certain requests from customers, such as loan applications, mortgage application, etc. Using the BRE, there's a few ways to accomplish this goal. <br /><br />One of them is implementing an interface called the IRuleSetTrackingInterceptor. Implementing this interface consists of writing code for the following methods, then called by the BRE as it's executing a RuleSet:<br /><br /><ul><li><strong>SetTrackingConfig</strong><br /><em>Sets the rule set tracking GUID and tracking configuration.</em></li><li><strong>TrackAgendaUpdate</strong><br /><em>Tracks updates to the rule engine agenda.</em></li><li><strong>TrackConditionEvaluation</strong><br /><em>Tracks the evaluation of rule conditions.</em></li><li><strong>TrackFactActivity</strong><br /><em>Tracks changes to working memory.</em></li><li><strong>TrackRuleFiring</strong><br /><em>Tracks the firing of a rule.</em></li><li><strong>TrackRuleSetEngineAssociation</strong><br /><em>Tracks the association of a rule set with a rule engine instance.</em></ul>Once your custom implementation is done, you can associate the class with a RuleSet to be tracked by passing it from code when calling Policy.Execute, e.g.:<br /><blockquote>Policy executingPolicy = new Policy("My Policy", 1, 4);<br />executingPolicy.Execute((object[]) facts.ToArray(typeof(object)), <strong>interceptor</strong>);</blockquote><br />After the BRE is done executing the specified Policy, the interceptor class has been called for each task and might contain valueable information as to the execution of the Policy.<br /><br />The BRE supplies a standard implementation of IRuleSetTrackingInterceptor, called the DebugTrackingInterceptor. This interceptor is also used if you have any "Call Rules" shapes within your Orchestrations. It's the way for the HAT to enable viewing what went on within the business process, BRE wise.<br /><br />The DebugTrackingInterceptor, however, uses a plain text file format, which can be cumbersome to parse using tools. I've implemented a Xml version, which can be downloaded <a href="http://www.gotdotnet.com/workspaces/workspace.aspx?id=d70546aa-1981-4e7d-bafc-f85c27fa0dd0">here</a>. Using it you can track the same information as the DebugTrackingInterceptor does, but in a Xml format.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1145194008339608292006-04-16T15:13:00.000+02:002006-04-16T15:27:44.513+02:00Tool update: Policy ExporterWhen working with the BRE, the stringent way the Business Rule Composer manages versioning can be a real pain. Undeploying / unpublishing policies and/or unpublishing vocabularies can be very handy. This tool allows you to:<br /><br /><ul><li>Import multiple exported items at once</li><li>Delete multiple policies / vocabularies at once</li><li>Export multiple policies / vocabularies at once</li><li>Undeploy policies</li><li>Unpublish policies / vocabularies</li></ul>Ofcourse, one should not use this tool in a production environment, as the versioning itself has a valid purpose. The tool is meant to ease development.<br /><br />I previously published this tool under the name "Policy Exporter". This is an update to that tool and a name change to better reflect it's purpose. It's now called "BRE Policy and Vocabulary manager" (what's in a name ;-) ) and it's current version is 1.1.<br /><br />The tool itself, including full sourcecode, can be downloaded from <a href="http://www.tachyons.demon.nl/BRE Policy Vocabulary manager v1.1.zip">this</a> location.<br /><br /><u>A scenario example</u><br /><br />While developing a Policy, you need a Vocabulary item added to the Vocabulary used in the current Policy:<br /><ol><li>Save the Policy.</li><li>Unpublish the Vocabulary using the tool</li><li>Press F5 in the Business Rule Composer</li><li>Ammend the Vocabulary</li><li>Publish the Vocabulary</li><li>Press F5 once again</li><li>Use the new item within the Policy</li></ol>Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1144173330185354872006-04-04T19:53:00.000+02:002006-04-04T19:55:30.196+02:00Woohoo!I've been awarded the Microsoft Most Valuable Professional (MVP) Award again! Thanks to everyone who asked me questions or help this year ;-)Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com6tag:blogger.com,1999:blog-7492642.post-1144056190093809912006-04-03T11:20:00.000+02:002006-04-03T11:23:10.106+02:00FWD: Retrieving context properties within a mapOK, first off, I'm not sure if you really want this, but people are asking for it a lot and I ran across a solution, so read <a href="http://biztalkblogs.com/carlosmedina/archive/2006/03/23/355.aspx">this</a> article if you want to retrieve a context property for the current message within the mapper (using a custom functoid).Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com0tag:blogger.com,1999:blog-7492642.post-1143753769636997422006-03-30T23:09:00.000+02:002006-03-30T23:22:49.683+02:00[offtopic] Windows Media Center 2005 - configuring more then 2 tunersFyi, <a href="http://www.thegreenbutton.com/community/shwmessage.aspx?ForumID=27&MessageID=106105">this</a> Green Button Community article on installing more then 2 tuners in Media Center 2005 works. However, when trying it, I bumped onto the reply the forum moderator gave (Posted 5/2/2005 7:29 PM). <br /><br />It turns out, Media Center recognizes all tuners automatically, at least in my case. Just starting up the Registry editor and copying the "User Settings" hive from a configured device under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Media Center\Service\Video\Tuners\{A799A800-A46D-11D0-A18C-00A02401DCD4} to the unconfigured device, altering it's properties (UserDefName, [RecordOrder]) and it worked :-D.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com0tag:blogger.com,1999:blog-7492642.post-1141244745639526342006-03-01T21:04:00.000+01:002006-03-01T21:29:28.946+01:00XPathMutatorStreamIt seems this little gem is hidden as almost no one I talk to knows of it's existence. <br /><br />Within the Microsoft.BizTalk.XPath namespace in the (GAC) assembly Microsoft.BizTalk.XPathReader.dll, a class is contained called XPathReader. Relying on this reader it's possible to match XPath expressions in a streaming fashion. This information is out on the web and discussed on many occasions.<br /><br />However, within the Microsoft.BizTalk.Streaming namespace in the (GAC) assembly Microsoft.BizTalk.Streaming.dll, another class named XPathMutatorStream is defined. The class does what it's name implies, it allows for a callback to alter the value of specified XPathExpressions (hence the reference to XPathReader first). A basic implementation could look like this:<br /><br />---<br /><br /><blockquote>MemoryStream stream = new MemoryStream();<br /><br />StreamWriter sw = new StreamWriter(stream);<br /><br />string xmldocInstance = "<Order><OrderLines><OrderLine id =\"1\">bla</OrderLine></OrderLines></Order>";<br /><br />sw.WriteLine(xmldocInstance);<br />sw.Flush();<br />stream.Position = 0;<br /><br />XPathCollection queries = new XPathCollection();<br /><br />queries.Add(new XPathExpression("/*[local-name()='Order']/*[local-name()='OrderLines']/*[local-name()='OrderLine']"));<br /><br />ValueMutator mutator = new ValueMutator(this.XPathCallBack);<br /><br />XPathMutatorStream mutatorStream = new XPathMutatorStream(stream, queries, mutator);<br /><br />XmlTextReader reader = new XmlTextReader(mutatorStream);<br /><br />while (reader.Read());<br /><br />***<br /> <br />private void XPathCallBack(<br /> int matchIdx, <br /> XPathExpression matchExpr, <br /> string origVal,<br /> ref string finalVal)<br />{<br /> MessageBox.Show("hit!");<br /><br /> finalVal = "bli";<br />}</blockquote>Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com200tag:blogger.com,1999:blog-7492642.post-1138230269738927142006-01-25T23:54:00.000+01:002006-01-26T00:04:29.786+01:00BizTalk Server 2006 - Pipeline Component Side-By-Side deploymentIn BizTalk Server 2004, it was impossible to perform a side-by-side deployment of pipeline components (if someone knows an approach to implement this without renaming the assembly, please let me know ;-) ). Every aspect of BizTalk Server components was deployed into the GAC, but the pipeline components themselfs.<br /><br />It turns out, however, the team did a tremendous job in altering this 'feature' to support GAC-ed pipeline components within BizTalk Server 2006. The trick to enable this is to:<br /><br /><ul><li>Version the pipeline component (sign the assembly)</li><li>reference the component by placing it into the "Pipeline Components" folder at development time in order to use it in your pipelines</li><li>remove it from this folder after building the pipeline or in deploying your solution to production</li><li>GAC the component</li></ul>The compiled pipeline assembly will reference the correct version and the AppDomain used by BizTalk Server 2006 will search the GAC before resorting to it's private paths, amongst which is the "Pipeline Components" folder.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2tag:blogger.com,1999:blog-7492642.post-1137859330586204912006-01-21T16:51:00.000+01:002006-01-21T17:02:10.660+01:00Using the BRE in content-based routing scenariosAfter writing Schema Editor extensions, I got the idea of creating a Pipeline Component which can be used in content-based routing scenarios. Also, I've attached a 'whitepaper' which explains the sample solution as well as the IExtension interface used to implement the Schema Editor extension. The idea is simple:<br /><br /><ul><li>A message comes into / flies out of the system through a Pipeline;</li><li>The Pipeline contains a component which looks at the schema for the passing message;</li><li>The Schema contains an annotation which states the Policy that applies to the Schema;</li><li>The appropriate Policy is executed by calling the BRE;</li><li>The Policy alters the message;</li><li>The message flying by is modified to contain the altered message from the BRE.</li></ul>After this, any following component or system will deal with the altered message.<br /><br /><em>One thing I haven't implemented due to the fact I haven't currently got a BizTalk 2004 VPC image is AppDomain caching of the Schema lookup. This caching would greatly improve performance of the Pipeline Component.</em><br /><br />The associated whitepaper can be downloaded <a href="http://www.tachyons.demon.nl/Using the BRE in content-based routing scenarios.doc">here</a>. The source code is <a href="http://www.tachyons.demon.nl/BRECallPolicy example - using the BRE in content-based routing scenarios.zip">here</a>.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com5tag:blogger.com,1999:blog-7492642.post-1137359688228264142006-01-15T22:10:00.000+01:002006-01-15T22:14:48.246+01:00BizTalk Server 2006 - export Orchestration as imageThe UK SDC BizTalk 2004 Documenter tool, which can be found over <a href="http://www.gotdotnet.com/Workspaces/Workspace.aspx?id=41c1faa9-13a6-478b-af81-d87ca946a222">here</a>, does an excellent job of generating documentation for BizTalk projects. <br /><br />However, I often need to take snapshots of my BizTalk Orchestration and I'm currently using BizTalk Server 2006, which the tool doesn't support (yet?). I've written my own 'tool' for this, by stealing, euhm, borrowing, some code from them and throwing some of my own in as well. <br /><br />It's downloadable <a href="http://www.tachyons.demon.nl/BizTalkPictureExporter.zip">here</a> for anyone to use. Sourcecode is included as always.<br /><br />Have fun using it and let me know if you run into trouble ;-)Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com14tag:blogger.com,1999:blog-7492642.post-1137063784299213012006-01-12T12:00:00.000+01:002006-01-12T13:58:26.650+01:00Of BizTalk Server Schema Editor Extensions...Ever wanted to add your own annotations to your schemas for some purpose like the Flat File extension, property promotion, the HWS extension or the TPM extension does? You can edit the schema by hand, but that wouldn’t be any fun, right? ;-) As an exercise, I’ve created two extensions which can easily be used in Visual Studio and extend the default schema editor, like the flat file extension does. <br /><br />One of the extensions allows an annotation to be added to the root schema element which can be read somewhere else in order to execute a specific BRE policy belonging to the message. This solution could be used to execute a policy from a pipeline in a content-based routing scenario.<br /><br />The other extension solves an issue a guy with me on a recent course has in processing COBOL copybooks. He needs to determine whether a field should be treated (and validated) as a date field instead of the normal numeric value. The extension allows for adding a property on any field stating it’s a date field according to the COBOL copybook standards.<br /><br />Figuring out how and what with schema extensibility can be a daunting task, as documentation is scarce. If you end up developing with these extensions, look into these properties, as there are not used, but very interesting (and hopefully, self-descriptive):<br /><br />InstanceGenerator<br />InstanceValidator<br />SchemaValidator<br /><br />Also, note the custom tab on the CopyBookExtension. It stems from a method called by the schema editor called GetCustomViews and the tab shows which fields will be interpreted as a date.<br /><br />Sourcecode for the CopyBookExtension is <a href="http://www.gotdotnet.com/workspaces/releases/checkfordownload.aspx?id=90253271-85be-4993-b0f3-333ca4bedca2&ReleaseId=18f00fa1-5255-430a-ae28-165a536e0a4f">here</a>, sourcecode for the BRECallPolicyExtension can be found <a href="http://www.gotdotnet.com/workspaces/releases/checkfordownload.aspx?id=90253271-85be-4993-b0f3-333ca4bedca2&ReleaseId=b94808be-d8fb-45e9-949d-9710fe8a0be9">here</a>.<br /><br />Using the extension is easy:<ol><li>Compile the extension. A post-build action will copy the output to the schema editor extension folder of BizTalk</li><li>Open up a schema in Visual Studio</li><li>Select the extension</li><li>In case of the CopyBook extension, select a field and note the “CopyBook” group in the PropertyGrid</li><li>In case of the BRECallPolicy extension, select the <schema> node and note the “BRE” group having a dropdown list of all published policies (latest only) or the error if nothing is found on the local host BizTalkRuleEngineDb ;-)</li></ol><strong>Let me know what you think!</strong>Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com3tag:blogger.com,1999:blog-7492642.post-1136982096678262552006-01-11T13:03:00.000+01:002006-01-11T13:21:36.690+01:00Default values in maps - better option in BizTalk 2006In a course I'm following today we discussed different ways of keeping nodes from dissapearing after a map has been applied. We discovered a new option in 2006 b2, which I'm very font of. Basically, up until now, we had a few ways (maybe even more?) of ensuring output nodes were created correctly:<br /><ol><li>default value in schema (space) - drawback: not visible in editor, schema specific, where as we might want to leave some nodes out in other mappings.<br /></li><li>space in value in map - drawback: not visible in editor.<br /></li><li>use some string functoid to fill the value (empty argument for the functoid) - drawback: non-functional functoids in the map, warning if the datatype is not string.<br /></li><li>scripting functoid - ability to return a null value, which works with any datatype on the right hand side. drawback: non-functional functoids in the map</li><li>map a record (any record) into the elements or attributes - drawback: clutters the map with non-functional and illegal links.</li></ol>in 2006 b2, there's a 6th possibility:<br /><br />The value property of the right hand side map now has a dropdown, containing '<empty>', which greatly enhances the functional aspect of the property.Martijn Hoogendoornhttp://www.blogger.com/profile/04936853262718403065noreply@blogger.com2