<?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' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-362796945673239800</id><updated>2012-01-12T22:42:12.179-05:00</updated><title type='text'>Technical Is As Technical Does - Hugh Ang's Blog</title><subtitle type='html'>Adventure with .NET and Windows</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-159651364685143466</id><published>2011-12-21T21:08:00.005-05:00</published><updated>2011-12-21T21:51:19.373-05:00</updated><title type='text'>How to Make Tracing and Caching Providers Work for EF 4.1 Code First</title><content type='html'>The &lt;a href="http://code.msdn.microsoft.com/EFProviderWrappers-c0b88f32"&gt;tracing and caching providers&lt;/a&gt; (or &lt;a href="http://blogs.msdn.com/b/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx"&gt;here&lt;/a&gt;) provide an excellent way to trace and cache EF queries. Unlike those that attempt to do the same above the EF API, these providers work under the covers and make tracing and caching non-invasive for the application code. Specifically, for cases where entities are lazy-loaded via EF and those entities are to be cached, this caching provider is truly more advantageous. &lt;br /&gt;&lt;br /&gt;However, these providers were written before EF 4.1 code first and they wouldn't work if you just follow the old sample. Luckily, it is not too difficult to make them work. The trick is to create a wrapping EFCachingConnection or EFTracingConnection that wraps a DbConnection (such as SqlConnection) and pass it to the DbContext constructor. I will just demonstrate the caching related code here but you should be able to chain tracing, caching and then the underlying SqlConnection using the same pattern.&lt;br /&gt;&lt;br /&gt;First, a minor modification to the EFCachingConnection constructor is needed. As shown in the following code, we need to be able to set the wrappedProviderInvariantName via the ctor:&lt;br /&gt;&lt;br /&gt;&lt;div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"&gt;&lt;br /&gt;&lt;div style="background: #fff; max-height: 300px; overflow: auto"&gt;&lt;br /&gt;&lt;ol start="26" style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"&gt;&lt;br /&gt;&lt;li&gt;&amp;nbsp;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;        &lt;span style="color:#0000ff"&gt;public&lt;/span&gt; EFCachingConnection(&lt;span style="color:#2b91af"&gt;DbConnection&lt;/span&gt; wrappedConnection, &lt;span style="color:#0000ff"&gt;string&lt;/span&gt; wrappedProviderInvariantName)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;        {&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;            &lt;span style="color:#0000ff"&gt;this&lt;/span&gt;.WrappedConnection = wrappedConnection;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            &lt;span style="color:#0000ff"&gt;this&lt;/span&gt;.CachingPolicy = &lt;span style="color:#2b91af"&gt;EFCachingProviderConfiguration&lt;/span&gt;.DefaultCachingPolicy;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;            &lt;span style="color:#0000ff"&gt;this&lt;/span&gt;.Cache = &lt;span style="color:#2b91af"&gt;EFCachingProviderConfiguration&lt;/span&gt;.DefaultCache;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            &lt;span style="color:#0000ff"&gt;base&lt;/span&gt;.wrappedProviderInvariantName = wrappedProviderInvariantName; &lt;span style="color:#008000"&gt;// make it possible to set the wrappedProviderInvariantName via this ctor&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;        }&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The I use the following helper function to create an instance of the EFCachingConnection that wraps a SqlConnection:&lt;br /&gt;&lt;br /&gt;&lt;div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"&gt;&lt;br /&gt;&lt;div style="background: #fff; max-height: 300px; overflow: auto"&gt;&lt;br /&gt;&lt;ol start="56" style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"&gt;&lt;br /&gt;&lt;li&gt;&amp;nbsp;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;        &lt;span style="color:#0000ff"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff"&gt;static&lt;/span&gt; &lt;span style="color:#2b91af"&gt;EFCachingConnection&lt;/span&gt; CreateEFCachingConnectionWrapper(&lt;span style="color:#0000ff"&gt;string&lt;/span&gt; nameOrConnectionString)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;        {&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;            &lt;span style="color:#0000ff"&gt;string&lt;/span&gt; connectionString;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            &lt;span style="color:#0000ff"&gt;if&lt;/span&gt; (nameOrConnectionString.Contains(&lt;span style="color:#a31515"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;))&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;                connectionString = nameOrConnectionString;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            &lt;span style="color:#0000ff"&gt;else&lt;/span&gt;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;                connectionString = &lt;span style="color:#2b91af"&gt;ConfigurationManager&lt;/span&gt;.ConnectionStrings[nameOrConnectionString].ConnectionString;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            &lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;            &lt;span style="color:#2b91af"&gt;DbConnection&lt;/span&gt; connection = &lt;span style="color:#0000ff"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af"&gt;SqlConnection&lt;/span&gt;(connectionString);&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;nbsp;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;            &lt;span style="color:#0000ff"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af"&gt;EFCachingConnection&lt;/span&gt;(connection, &lt;span style="color:#a31515"&gt;&amp;quot;System.Data.SqlClient&amp;quot;&lt;/span&gt;); &lt;/li&gt;&lt;br /&gt;&lt;li&gt;        }&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now you would simply pass the newly constucted EFCachingConnection instance to the ctor of DbContext:&lt;br /&gt;&lt;br /&gt;&lt;div style="border: #000080 1px solid; color: #000; font-family: 'Courier New', Courier, Monospace; font-size: 10pt"&gt;&lt;br /&gt;&lt;div style="background: #fff; max-height: 300px; overflow: auto"&gt;&lt;br /&gt;&lt;ol start="100" style="background: #ffffff; margin: 0; padding: 0 0 0 5px;"&gt;&lt;br /&gt;&lt;li&gt;&amp;nbsp;&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;        &lt;span style="color:#0000ff"&gt;public&lt;/span&gt; MyContext(&lt;span style="color:#2b91af"&gt;DbConnection&lt;/span&gt; connection)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;            : &lt;span style="color:#0000ff"&gt;base&lt;/span&gt;(connection, &lt;span style="color:#0000ff"&gt;true&lt;/span&gt;)&lt;/li&gt;&lt;br /&gt;&lt;li style="background: #f3f3f3"&gt;        {&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note that MyContext is the application's EF code first context, which derives from DbContext and has probably overriden the OnModelCreating() method.&lt;br /&gt;&lt;br /&gt;Last and not the least you would need to call EFCachingProviderConfiguration.RegisterProvider() first when you start your application.&lt;br /&gt;&lt;br /&gt;Happy holidays and happy EF coding!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-159651364685143466?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/159651364685143466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=159651364685143466' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/159651364685143466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/159651364685143466'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2011/12/how-to-make-tracing-and-caching.html' title='How to Make Tracing and Caching Providers Work for EF 4.1 Code First'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-5806229153335270601</id><published>2011-03-01T14:36:00.011-05:00</published><updated>2011-03-01T15:21:45.038-05:00</updated><title type='text'>Recording VS.NET Web Performance Test for Flex</title><content type='html'>We are building a web application that integrates with a third party software by embedding their Flex objects in our ASPX pages. When we started using VS.NET 2010 Web Performance Test, everything worked fine except for the weborb requests made by the Flex objects to the server. Basically, the requests recorded by the web test, when played back and sent to the server, were causing the server to respond with errors. From googling, it looks like that &lt;a href="http://tech.groups.yahoo.com/group/flashorb/message/7725"&gt;the same issue&lt;/a&gt; has been experienced by other folks as well. At this point, it would be easy to simply dismiss VS.NET 2010 Web Performance Test as a viable tool for Flex. What a costly mistake this would have been if we had stopped doing more analysis! &lt;br /&gt;&lt;br /&gt;Looking at the initially recorded tests, I found out that all the data posted by the Flex objects was recorded and played back as string data type. Examining the payload in Fiddler, however, showed that the data is obviously binary. So our recorded test was sending the data with lost fidelity and the server just choked. &lt;br /&gt;&lt;br /&gt;Thinking that there must be configuration to tweak to make our tests record binary data, I started searching MSDN for documentation. Sure enough, I found &lt;a href=http://msdn.microsoft.com/en-us/library/ff356200.aspx"&gt;this link&lt;/a&gt;. I went ahead and added "application/x-amf" as the content type. Then I recorded the test again and ran the scripts. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-JTFm8x69Gxw/TW1T8fvm6ZI/AAAAAAAAAQE/-1daLXQ1lTY/s1600/Webtest_amf_option.PNG"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 184px;" src="http://3.bp.blogspot.com/-JTFm8x69Gxw/TW1T8fvm6ZI/AAAAAAAAAQE/-1daLXQ1lTY/s320/Webtest_amf_option.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5579207812160350610" /&gt;&lt;/a&gt;Voila, everything worked like a charm!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-5806229153335270601?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/5806229153335270601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=5806229153335270601' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5806229153335270601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5806229153335270601'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2011/03/recording-vsnet-web-performance-test.html' title='Recording VS.NET Web Performance Test for Flex'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-JTFm8x69Gxw/TW1T8fvm6ZI/AAAAAAAAAQE/-1daLXQ1lTY/s72-c/Webtest_amf_option.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-1526572974068042339</id><published>2010-05-10T22:09:00.004-04:00</published><updated>2010-05-10T23:02:53.803-04:00</updated><title type='text'>Fixing My Custom Built PC After a Power Outage</title><content type='html'>I usually wouldn't blog about hardware but since this experience felt just like debugging a software problem, here it goes:&lt;br /&gt;&lt;br /&gt;The NJ area experienced a pretty bad wind storm this past weekend. Downed tree branches knocked out some power lines, which caused scattered power outages in the area. My house was one of the unlucky ones that were hit with the outage. After the power came back in the next morning, one of my desktop PCs that I built several years ago wouldn't start. This is the PC that I have just recently upgraded from Vista to Windows 7 and I also built inside the host PC a VPC with VS.NET 2010 and all the other latest cool stuff (Silverlight, etc.). So I was determined to figure out what went bad and hoped to salvage as much as possible. &lt;br /&gt;&lt;br /&gt;The symptom of the problem is that initially it wouldn't even turn on when I pressed the power button. After I switched to a different circuit in the house, it could start with fans and lights on. So it was evident that the PSU was still good. But there was no display on the monitor and no system start beep sound either. What was even worse was I could smell burning plastic. Some board was fried during the outage and now with the power on, sending the current through the board is still burning it. &lt;br /&gt;&lt;br /&gt;I turned off the power and began visually inspecting the mobo, hoping to find where the burn was but to no avail. I started disconnecting the IDE cable to the DVD rom, SATA cables to the HDD, unplugging RAM. I would make one change at a time while powering on to see if there is a system beep. Nothing so far. &lt;br /&gt;&lt;br /&gt;The last item was the video card with dual DVI interfaces for my two monitors. After I unplugged the video card, bingo! the system started making beeping sounds. And as I flipped the video card over, sure enough I found the burning spot, which I wouldn't have been able to see when it was installed closely to the bottom of the tower in the facing down position. Fortunately I had a spare video card. After plugging that in I had no problem booting into Windows 7. It did require resetting the resolution after automatically installing the driver for the card. Minutes later, I noticed that automatic Windows update was complaining about not able to complete the updates and a closer look revealed that the system clock was set to 1/1/2006. I suspect this was done as I was resetting the BIOS during the diagnosis process - while the power cord was unplugged, I pressed and held the power button for a few moments. &lt;br /&gt;&lt;br /&gt;So fortunately it was only a small loss instead of the MOBO/CPU that are commonly getting fried during power outages. One thing I will be doing for sure going forward is to use the battery backup surge protector as opposed to a low end one I was using :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-1526572974068042339?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/1526572974068042339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=1526572974068042339' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1526572974068042339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1526572974068042339'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2010/05/fixing-my-custom-built-pc-after-power.html' title='Fixing My Custom Built PC After a Power Outage'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-535982652129856670</id><published>2009-12-16T01:07:00.027-05:00</published><updated>2009-12-16T13:37:02.603-05:00</updated><title type='text'>Application Migration - Vista/Win7 Compatibility</title><content type='html'>It has been a while since the last time I blogged. The theme of my work for the last 4 months or so is really migration, migration, and migration! &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;First I helped our team with a VB6 to VB.NET migration project that ran into some sticky interop problems.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Secondly I worked as an advisor for a customer who was in the process of migrating their apps from Win2K to Vista. Please don't ask me why they chose to go to Vista while Win7 was coming out - it was a decision already rationalized by the management when I was brought in. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;And lastly, just a couple of weeks ago, I helped Microsoft deliver a Win7 training course for a customer who is looking to migrate to Win7 in the next 6 months. Although it is not unusual that I present in a conference room or mentor developers privately, this was actually my first time to do a formal training. The sessions were recorded and are being made available for later reuse by the customer. Speaking of the sessions on tape, I actually saw Oliver Stone and Michael Douglas when they were shooting Wall Street 2 on site at the Borders book store at the corner of Wall Street and Broadway. And that was when I was working on the Vista migration mentioned above.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Enough with the chronology and my celebrity sightings. As the title suggests, I'd like to cover the most common compatibility issues for Vista/Win7from a developer perspective. So here are the two top issues I have seen so far:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Writing to %ProgramFiles% (e.g. C:\Program Files) and %SystemRoot% (e.g. C:\Windows) locations&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Writing to registry hive: HKLM\Software&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;It is quite common that legacy apps write configuration data to the above locations. But with UAC enabled in Vista/Win7, an admin user will be running an app with standard user privileges unless the app has a manifest explicitly requesting admin privilege or the app is started with "Run as administrator" context menu; And since standard user will only have read/execute rights to those locations, the attempt made by those apps to write configuration data to those locations will fail. Using the icacls at the command prompt shows the ACL of %ProgramFiles% as in the following on my machine: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;C:\Program Files&gt;icacls .&lt;br /&gt;. NT SERVICE\TrustedInstaller:(F)&lt;br /&gt;  NT SERVICE\TrustedInstaller:(CI)(IO)(F)&lt;br /&gt;  NT AUTHORITY\SYSTEM:(M)&lt;br /&gt;  NT AUTHORITY\SYSTEM:(OI)(CI)(IO)(F)&lt;br /&gt;  BUILTIN\Administrators:(M)&lt;br /&gt;  BUILTIN\Administrators:(OI)(CI)(IO)(F)&lt;br /&gt;  BUILTIN\Users:(RX)&lt;br /&gt;  BUILTIN\Users:(OI)(CI)(IO)(GR,GE)&lt;br /&gt;  CREATOR OWNER:(OI)(CI)(IO)(F)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;There is an additional twist here. The app may not be failing but you will not see files or registry keys written to the intended location. This is the work of data redirection(or UAC virtualization). The details can be found &lt;a href="http://windowsteamblog.com/blogs/developers/archive/2009/08/04/user-account-control-data-redirection.aspx"&gt;here&lt;/a&gt;. But basically:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Writing to %ProgramFiles%\MyApp\myapp.ini gets redirected to C:\Users\Username\AppData\Local\VirtualStore\Program Files\MyApp\myapp.ini&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Writing to HKLM\Software\MyApp\ gets redirected to HKCU\Software\Classes\VirtualStore\MACHINE\Software\MyApp&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;When virtualization happens, you can fire up Process Monitor and notice a REPARSE event, followed by writing to those redirected locations. &lt;br /&gt;&lt;br /&gt;As the redirection is on per-user basis, this can mess up the intended behavior of the application. For example, the application may be intended to be used by multiple users on one machine and the configuration data should be shared. Microsoft is making no guarantee that the virtualization will be in future Windows. So what to do as a developer? The best practice for writing per machine configuration data is using %ProgramData% (e.g. C:\ProgramData). For per user configuration data, use %LocalAppData% (e.g. C:\Users\User\AppData\Local) for local or %AppData% for roaming user profile. &lt;br /&gt;&lt;br /&gt;Running icacls on %ProgramData% shows that a standard user would have additional AD(append data/add subdirectory), WD(write data/add file), WEA(write extended attributes) and WA(write attributes) privileges:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;C:\ProgramData&gt;icacls .&lt;br /&gt;. NT AUTHORITY\SYSTEM:(OI)(CI)(F)&lt;br /&gt;  BUILTIN\Administrators:(OI)(CI)(F)&lt;br /&gt;  CREATOR OWNER:(OI)(CI)(IO)(F)&lt;br /&gt;  BUILTIN\Users:(OI)(CI)(RX)&lt;br /&gt;  BUILTIN\Users:(CI)(WD,AD,WEA,WA)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And lastly, don't hard code any of the paths we have talked about. There are well-known APIs to get them. In .NET, follow this sample:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 string\cf0  path = \cf4 Environment\cf0 .GetFolderPath(\cf4 Environment\cf0 .\cf4 SpecialFolder\cf0 .CommonApplicationData);\par ??\par ??path = \cf4 Environment\cf0 .GetFolderPath(\cf4 Environment\cf0 .\cf4 SpecialFolder\cf0 .LocalApplicationData);\par ??\par ??path = \cf4 Environment\cf0 .GetFolderPath(\cf4 Environment\cf0 .\cf4 SpecialFolder\cf0 .ApplicationData);}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;string&lt;/span&gt; path = &lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.GetFolderPath(&lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.&lt;span style="color: #2b91af;"&gt;SpecialFolder&lt;/span&gt;.CommonApplicationData);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;path = &lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.GetFolderPath(&lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.&lt;span style="color: #2b91af;"&gt;SpecialFolder&lt;/span&gt;.LocalApplicationData);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;path = &lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.GetFolderPath(&lt;span style="color: #2b91af;"&gt;Environment&lt;/span&gt;.&lt;span style="color: #2b91af;"&gt;SpecialFolder&lt;/span&gt;.ApplicationData);&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And if you write C++ code, here is a sample:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red0\green128\blue0;}??\fs20 \cf1 void\cf0  ShowFolders(HWND hWnd)\par ??\{\tab \par ??\tab LPWSTR wszPath = NULL;\par ??\tab HRESULT hr = SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); \par ??\tab \cf1 if\cf0  ( SUCCEEDED(hr) )\par ??\tab \{\par ??\tab \tab \cf4 // work with wszPath\par ??\cf0 \tab \tab \par ??\tab \tab CoTaskMemFree(wszPath);\par ??\tab \}\par ??\par ??\tab hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); \par ??\tab \cf1 if\cf0  ( SUCCEEDED(hr) )\par ??\tab \{\par ??\tab \tab \cf4 // work with wszPath\tab \tab \par ??\cf0 \tab \tab \par ??\tab \tab CoTaskMemFree(wszPath);\par ??\tab \}\par ??\par ??\tab hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); \par ??\tab \cf1 if\cf0  ( SUCCEEDED(hr) )\par ??\tab \{\par ??\tab \tab \cf4 // work with wszPath\tab \par ??\cf0 \tab \tab \par ??\tab \tab CoTaskMemFree(wszPath);\par ??\tab \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;void&lt;/span&gt; ShowFolders(HWND hWnd)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;{&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LPWSTR wszPath = NULL;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; HRESULT hr = SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); &lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; ( SUCCEEDED(hr) )&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// work with wszPath&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CoTaskMemFree(wszPath);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); &lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; ( SUCCEEDED(hr) )&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// work with wszPath&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CoTaskMemFree(wszPath);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; hr = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY, NULL, &amp;amp;wszPath); &lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; ( SUCCEEDED(hr) )&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// work with wszPath&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CoTaskMemFree(wszPath);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-535982652129856670?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/535982652129856670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=535982652129856670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/535982652129856670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/535982652129856670'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2009/12/application-migration-vistawin7.html' title='Application Migration - Vista/Win7 Compatibility'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6030714575999750149</id><published>2009-09-02T16:58:00.004-04:00</published><updated>2009-09-02T17:32:37.406-04:00</updated><title type='text'>Hotfix KB971030 Released</title><content type='html'>You can finally download this hotfix from &lt;a href="http://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=21630"&gt;here&lt;/a&gt; and the detailed information is available &lt;a href="http://support.microsoft.com/kb/971030"&gt;here&lt;/a&gt;. According to the information posted there, it is a fix for an access violation problem when making virtual function calls to the IList&amp;lt;T&amp;gt;, IEnumerable&amp;lt;T&amp;gt;, or ICollection&amp;lt;T&amp;gt; interface. I am not sure yet if this is another manifestation of the same dispatch token problem I described in my &lt;a href="http://tigerang.blogspot.com/2008/09/follow-up-of-piab-and-wcf-article.html"&gt;previous blog&lt;/a&gt; or the CLR team simply bundled together several virtual dispatch bug fixes that just include &lt;a href="http://tigerang.blogspot.com/2008/09/follow-up-of-piab-and-wcf-article.html"&gt;what I found&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;I ran the same test harness that I used before and confirmed that the hotfix does indeed resolve the problem. &lt;br /&gt;&lt;br /&gt;I was having some trouble installing the hotfix today but eventually got it installed. It turned out that my OS was Vista SP1 and I had to upgrade it to SP2 in order to install the hotfix. If you have another OS and wondering about the same question as &lt;a href="https://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6641481464743152310"&gt;Chris Dion&lt;/a&gt; had, the hotfix should be applicable to Windows Server 2000, Windows Server 2003, Windows Server 2008 and Windows XP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6030714575999750149?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6030714575999750149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6030714575999750149' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6030714575999750149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6030714575999750149'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2009/09/hotfix-kb971030-released.html' title='Hotfix KB971030 Released'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6641481464743152310</id><published>2009-05-15T13:51:00.002-04:00</published><updated>2009-05-15T14:11:53.657-04:00</updated><title type='text'>CLR Virtual Call Stub Issue Resolved</title><content type='html'>&lt;strong&gt;Good news&lt;/strong&gt; - I have just received words from the Microsoft CLR team that the issue I  detailed in &lt;a href="http://tigerang.blogspot.com/2008/09/follow-up-of-piab-and-wcf-article.html"&gt;this blog&lt;/a&gt; has been fixed in an upcoming QFE, which will be available for download through the Support/KB site using KB971030 in about a week. This also means that the fix will be automatically included in any future 3.5 service pack release. In addition, this has been fixed in the upcoming 4.0 release. I will try the fix in a week and keep everyone posted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6641481464743152310?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6641481464743152310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6641481464743152310' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6641481464743152310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6641481464743152310'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2009/05/clr-virtual-call-stub-issue-resolved.html' title='CLR Virtual Call Stub Issue Resolved'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-2738680715644395903</id><published>2009-02-18T11:46:00.005-05:00</published><updated>2009-02-18T12:34:15.681-05:00</updated><title type='text'>Making Assumptions in Application Design</title><content type='html'>Back during the holidays, I wrote a small .NET program to manipulate my Canon XTi camera, which was connected to the PC via USB. Everything worked great when I was using my laptop that had Vista on it. But on my wife's laptop that had XP, the performance became unbearable. My utility program would wait for several minutes before I could start using it. The program's thread was pretty much idle during the waiting so I was asking myself: could this be the PC hardware? I tested this program on one of my desktops that also had XP. Nope, still the same poor performance. I then updated the camera's firmware and that didn't resolve the issue either. I began to suspect that this was OS related. Sure enough, when I plugged in the camera without my program running, XP took a much longer time than Vista to come up with the camera and scanners wizard. I noticed that while XP seemed to be cluelessly waiting, the CF card indicator light of the camera was flashing madly. I realized that XP was probably trying to download pictures from the camera, which was busy reading from the CF card. At the time, I had about 300 high resolution pictures on the 2GB CF card. After I switched it with an empty CF card, the performance problem just went away. &lt;br /&gt;&lt;br /&gt;The morale of the story is that we need to be extra careful when making assumptions for users when designing UI applications. In this case, XP made a not necessarily wise assumption about the intention of plugging a camera into the USB port. Even for users who do want to download pictures this way, there is no visual clue provided, leaving users wonder what is going on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-2738680715644395903?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/2738680715644395903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=2738680715644395903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2738680715644395903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2738680715644395903'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2009/02/making-assumptions-in-application.html' title='Making Assumptions in Application Design'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-4026213380706870838</id><published>2008-10-14T12:29:00.011-04:00</published><updated>2008-10-14T13:40:26.252-04:00</updated><title type='text'>Reverse P/Invoke - Part 2</title><content type='html'>In &lt;a href="http://tigerang.blogspot.com/2008/09/reverse-pinvoke.html"&gt;my last post&lt;/a&gt;, I described a loosely-coupled pattern for native code to call into managed code. That approach requires control of source code of the native library, although only minor change would be made. There are scenarios where native code is not available and we just can not make any changes to it. For example, I have a Canon Rebel XTi camera connected to my PC and I need to notify my Winforms application of a new picture just taken so that the application can download and display it. The Canon SDK is in native library and has exported functions for callback function pointers to be registered. So what do we do? Scenarios like this require us to call native API from managed code, passing delegates marshaled as function pointers. &lt;br /&gt;&lt;br /&gt;The solution is surprisingly straightforward. To demonstrate the technique, here is the native library code - note the definitions of data structure and callback function prototype:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 \cf1 #define\cf0  NATIVELIB_API \cf1 __declspec\cf0 (\cf1 dllexport\cf0 )\par ??\par ??\cf4 // data structure for the callback function\par ??\cf1 struct\cf0  EventData\par ??\{\par ??    \cf1 int\cf0  I;\par ??    TCHAR* Message; \par ??\};\par ??\par ??\cf4 // callback function prototype\par ??\cf1 typedef\cf0  \cf1 void\cf0  (*FPCallBack)(EventData data);\par ??\par ??\cf4 // exported API\par ??\cf0 NATIVELIB_API \cf1 void\cf0  fnNativeAPI(\cf1 int\cf0  i, FPCallBack callBack)\par ??\{\par ??\tab EventData data;\par ??\tab data.I = i;\par ??\tab data.Message = L\cf5 "Hello from native code!"\cf0 ;\par ??\par ??\tab \cf4 // invoke the callback function\par ??\cf0 \tab callBack(data);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;#define&lt;/span&gt; NATIVELIB_API &lt;span style="color: blue;"&gt;__declspec&lt;/span&gt;(&lt;span style="color: blue;"&gt;dllexport&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// data structure for the callback function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;struct&lt;/span&gt; EventData&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; I;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR* Message; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;};&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// callback function prototype&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;typedef&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; (*FPCallBack)(EventData data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// exported API&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;NATIVELIB_API &lt;span style="color: blue;"&gt;void&lt;/span&gt; fnNativeAPI(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i, FPCallBack callBack)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; EventData data;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; data.I = i;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; data.Message = L&lt;span style="color: #a31515;"&gt;"Hello from native code!"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// invoke the callback function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; callBack(data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And here is my corresponding interop code in C#. Notice that in the P/Invoke definition of the fnNativeAPI call, I added the MarshalAs(UnmanagedType.FunctionPtr) attribute in front of the CallBackDelegate parameter to instruct the runtime to marshal the delegate as a function pointer from managed code to native code.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 [\cf3 StructLayout\cf0 (\cf3 LayoutKind\cf0 .Sequential, CharSet = \cf3 CharSet\cf0 .Unicode)]\par ??\cf4 public\cf0  \cf4 struct\cf0  \cf3 EventData\par ??\cf0 \{\par ??    \cf4 public\cf0  \cf4 int\cf0  I;\par ??    \cf4 public\cf0  \cf4 string\cf0  Message;\par ??\}\par ??\par ??[\cf3 UnmanagedFunctionPointer\cf0 (\cf3 CallingConvention\cf0 .Cdecl)]\par ??\cf4 public\cf0  \cf4 delegate\cf0  \cf4 void\cf0  \cf3 CallBackDelegate\cf0 (\cf3 EventData\cf0  data);\par ??\par ??\cf4 public\cf0  \cf4 class\cf0  \cf3 Native\par ??\cf0 \{\par ??    [\cf3 DllImport\cf0 (\cf5 "NativeLib.dll"\cf0 )]\par ??    \cf4 public\cf0  \cf4 static\cf0  \cf4 extern\cf0  \cf4 void\cf0  fnNativeAPI(\cf4 int\cf0  i, [\cf3 MarshalAs\cf0 (\cf3 UnmanagedType\cf0 .FunctionPtr)] \cf3 CallBackDelegate\cf0  callBack);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;StructLayout&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;LayoutKind&lt;/span&gt;.Sequential, CharSet = &lt;span style="color: #2b91af;"&gt;CharSet&lt;/span&gt;.Unicode)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;struct&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;EventData&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; I;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Message;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;UnmanagedFunctionPointer&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;CallingConvention&lt;/span&gt;.Cdecl)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;delegate&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;CallBackDelegate&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;EventData&lt;/span&gt; data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Native&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;DllImport&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"NativeLib.dll"&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;extern&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; fnNativeAPI(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i, [&lt;span style="color: #2b91af;"&gt;MarshalAs&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;UnmanagedType&lt;/span&gt;.FunctionPtr)] &lt;span style="color: #2b91af;"&gt;CallBackDelegate&lt;/span&gt; callBack);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Here is the C# code of the application:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red0\green128\blue0;}??\fs20 \cf1 public\cf0  \cf1 partial\cf0  \cf1 class\cf0  \cf4 Form1\cf0  : \cf4 Form\par ??\cf0 \{\par ??    \cf1 private\cf0  CallBackDelegate _cb;\par ??\par ??    \cf1 public\cf0  Form1()\par ??    \{\par ??        InitializeComponent();\par ??        _cb = \cf1 new\cf0  CallBackDelegate(Foo);\par ??    \}\par ??\par ??    \cf1 private\cf0  \cf1 void\cf0  Form1_Load(\cf1 object\cf0  sender, \cf4 EventArgs\cf0  e)\par ??    \{\par ??        \cf5 // call the native API, passing our .NET delegate\par ??\cf0         \cf1 int\cf0  i = 200;\par ??        Native.fnNativeAPI(i, _cb);\par ??    \}\par ??\par ??    \cf5 // this is our callback function\par ??\cf0     \cf1 private\cf0  \cf1 void\cf0  Foo(EventData data)\par ??    \{\par ??        \cf4 Debug\cf0 .WriteLine(data.I);\par ??        \cf4 Debug\cf0 .WriteLine(data.Message);\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;partial&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Form1&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;Form&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; CallBackDelegate _cb;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; Form1()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; InitializeComponent();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _cb = &lt;span style="color: blue;"&gt;new&lt;/span&gt; CallBackDelegate(Foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Form1_Load(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af;"&gt;EventArgs&lt;/span&gt; e)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// call the native API, passing our .NET delegate&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; i = 200;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Native.fnNativeAPI(i, _cb);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// this is our callback function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Foo(EventData data)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(data.I);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(data.Message);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Careful readers may have noticed that I have kept the delegate as a class field. This is a best practice to prevent the delegate from being garbage-collected. It would be really bad if the native code holds an invalid function pointer and tries to invoke it. &lt;br /&gt;&lt;br /&gt;For VB programmers, here is the interop code in VB.NET:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 &amp;lt;StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)&amp;gt; _\par ??\cf3 Public\cf0  \cf3 Structure\cf0  EventData\par ??    \cf3 Public\cf0  I \cf3 As\cf0  \cf3 Integer\par ??\cf0     \cf3 Public\cf0  Message \cf3 As\cf0  \cf3 String\par ??End\cf0  \cf3 Structure\par ??\par ??\cf0 &amp;lt;UnmanagedFunctionPointer(CallingConvention.Cdecl)&amp;gt; _\par ??\cf3 Public\cf0  \cf3 Delegate\cf0  \cf3 Sub\cf0  CallBackDelegate(\cf3 ByVal\cf0  data \cf3 As\cf0  EventData)\par ??\par ??\cf3 Public\cf0  \cf3 Class\cf0  Native\par ??    &amp;lt;DllImport(\cf4 "NativeLib.dll"\cf0 )&amp;gt; _\par ??    \cf3 Public\cf0  \cf3 Shared\cf0  \cf3 Sub\cf0  fnNativeAPI(\cf3 ByVal\cf0  i \cf3 As\cf0  \cf3 Integer\cf0 , _\par ??                                  &amp;lt;MarshalAs(UnmanagedType.FunctionPtr)&amp;gt; \cf3 ByVal\cf0  callBack \cf3 As\cf0  CallBackDelegate)\par ??    \cf3 End\cf0  \cf3 Sub\par ??End\cf0  \cf3 Class}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;lt;StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)&amp;gt; _&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Structure&lt;/span&gt; EventData&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Public&lt;/span&gt; I &lt;span style="color: blue;"&gt;As&lt;/span&gt; &lt;span style="color: blue;"&gt;Integer&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Public&lt;/span&gt; Message &lt;span style="color: blue;"&gt;As&lt;/span&gt; &lt;span style="color: blue;"&gt;String&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Structure&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;lt;UnmanagedFunctionPointer(CallingConvention.Cdecl)&amp;gt; _&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Delegate&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; CallBackDelegate(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; data &lt;span style="color: blue;"&gt;As&lt;/span&gt; EventData)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt; Native&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;DllImport(&lt;span style="color: #a31515;"&gt;"NativeLib.dll"&lt;/span&gt;)&amp;gt; _&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Shared&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; fnNativeAPI(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; i &lt;span style="color: blue;"&gt;As&lt;/span&gt; &lt;span style="color: blue;"&gt;Integer&lt;/span&gt;, _&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;MarshalAs(UnmanagedType.FunctionPtr)&amp;gt; &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; callBack &lt;span style="color: blue;"&gt;As&lt;/span&gt; CallBackDelegate)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And the application code:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red0\green128\blue0;}??\fs20 \cf1 Public\cf0  \cf1 Class\cf0  Form1\par ??    \cf1 Dim\cf0  _cb \cf1 As\cf0  CallBackDelegate\par ??\par ??    \cf1 Public\cf0  \cf1 Sub\cf0  \cf1 New\cf0 ()\par ??\par ??        \cf4 ' This call is required by the Windows Form Designer.\par ??\cf0         InitializeComponent()\par ??\par ??        \cf4 ' Add any initialization after the InitializeComponent() call.\par ??\cf0         _cb = \cf1 New\cf0  CallBackDelegate(\cf1 AddressOf\cf0  \cf1 Me\cf0 .Foo)\par ??    \cf1 End\cf0  \cf1 Sub\par ??\par ??\cf0     \cf1 Private\cf0  \cf1 Sub\cf0  Form1_Load(\cf1 ByVal\cf0  sender \cf1 As\cf0  System.Object, \cf1 ByVal\cf0  e \cf1 As\cf0  System.EventArgs) \cf1 Handles\cf0  \cf1 MyBase\cf0 .Load\par ??        \cf1 Dim\cf0  i \cf1 As\cf0  \cf1 Integer\cf0  = 200\par ??        \cf4 'call the native API, passing our .NET delegate\par ??\cf0         Native.fnNativeAPI(i, _cb)\par ??    \cf1 End\cf0  \cf1 Sub\par ??\par ??\cf0     \cf4 ' this is our callback function\par ??\cf0     \cf1 Private\cf0  \cf1 Sub\cf0  Foo(\cf1 ByVal\cf0  data \cf1 As\cf0  EventData)\par ??        Debug.WriteLine(data.I)\par ??        Debug.WriteLine(data.Message)\par ??    \cf1 End\cf0  \cf1 Sub\par ??End\cf0  \cf1 Class}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt; Form1&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Dim&lt;/span&gt; _cb &lt;span style="color: blue;"&gt;As&lt;/span&gt; CallBackDelegate&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; &lt;span style="color: blue;"&gt;New&lt;/span&gt;()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;' This call is required by the Windows Form Designer.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; InitializeComponent()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;' Add any initialization after the InitializeComponent() call.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _cb = &lt;span style="color: blue;"&gt;New&lt;/span&gt; CallBackDelegate(&lt;span style="color: blue;"&gt;AddressOf&lt;/span&gt; &lt;span style="color: blue;"&gt;Me&lt;/span&gt;.Foo)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; Form1_Load(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color: blue;"&gt;Handles&lt;/span&gt; &lt;span style="color: blue;"&gt;MyBase&lt;/span&gt;.Load&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Dim&lt;/span&gt; i &lt;span style="color: blue;"&gt;As&lt;/span&gt; &lt;span style="color: blue;"&gt;Integer&lt;/span&gt; = 200&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;'call the native API, passing our .NET delegate&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Native.fnNativeAPI(i, _cb)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;' this is our callback function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; Foo(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; data &lt;span style="color: blue;"&gt;As&lt;/span&gt; EventData)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(data.I)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(data.Message)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-4026213380706870838?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/4026213380706870838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=4026213380706870838' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4026213380706870838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4026213380706870838'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/10/reverse-pinvoke-part-2.html' title='Reverse P/Invoke - Part 2'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-913827605849520990</id><published>2008-09-30T19:24:00.000-04:00</published><updated>2008-09-30T21:57:52.028-04:00</updated><title type='text'>Reverse P/Invoke</title><content type='html'>While researching for ongoing/upcoming projects that will need approaches for interop between .NET and native code, specifically, for native code to call into .NET code, &lt;a href="http://blogs.msdn.com/junfeng/archive/2008/01/28/reverse-p-invoke-and-exception.aspx"&gt;Reverse P/Invoke&lt;/a&gt; has come to my attention as a viable option. Of course there is the official Microsoft recommendation to expose .NET classes as COM components, which are then callable from native code that talks COM.&lt;br /&gt;&lt;br /&gt;The Reverse P/Invoke approach allows native code to call into .NET delegate using a function pointer. So it could work well for my requirement, for which I need a way to fire an event from the native app to the .NET app, for instance, an application context change on the native side must be reflected on the .NET side.&lt;br /&gt;&lt;br /&gt;The blog by Junfeng, however, does not give a concrete example of such Reverse P/Invoke approach. So I came up with a POC, where I had a VS.NET solution with three projects: (1) a native console application (C++ project) (2) a managed class library (C# project) and (3) a mixed mode dll library with exported C++ function (C++/CLI project). &lt;br /&gt;&lt;br /&gt;So this POC is trying to simulate a native application (#1) that needs to notify managed code (#2) of data changes. I came up with a dll library compiled with /clr switch to handle the interop details. Both the native app and the managed code requires very minimum changes. &lt;br /&gt;&lt;br /&gt;On the .NET side, we have a managed class that has a Foo() function and a GetDelegate() function that hands out a delegate to Foo to its caller.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 public\cf0  \cf1 class\cf0  \cf4 ManagedClass\par ??\cf0 \{\par ??    \cf1 private\cf0  CallBackDelegate _delegate;\par ??\par ??    \cf1 public\cf0  ManagedClass()\par ??    \{\par ??        _delegate = \cf1 new\cf0  CallBackDelegate(\cf1 this\cf0 .Foo);\par ??    \}\par ??\par ??    \cf1 public\cf0  CallBackDelegate GetDelegate()\par ??    \{\par ??        \cf1 return\cf0  _delegate;\par ??    \}\par ??\par ??    \cf1 public\cf0  \cf1 void\cf0  Foo(EventData data)\par ??    \{\par ??        \cf4 Debug\cf0 .WriteLine(data.I);\par ??        \cf4 Debug\cf0 .WriteLine(data.Message);\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ManagedClass&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; CallBackDelegate _delegate;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; ManagedClass()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _delegate = &lt;span style="color: blue;"&gt;new&lt;/span&gt; CallBackDelegate(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.Foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; CallBackDelegate GetDelegate()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; _delegate;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Foo(EventData data)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(data.I);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(data.Message);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The EventData is a data structure that shares the same binary layout as the one that will be created and marshaled from the native code.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 [\cf3 StructLayout\cf0 (\cf3 LayoutKind\cf0 .Sequential, CharSet = \cf3 CharSet\cf0 .Unicode)]\par ??\cf4 public\cf0  \cf4 struct\cf0  \cf3 EventData\par ??\cf0 \{\par ??    \cf4 public\cf0  \cf4 int\cf0  I;\par ??    \cf4 public\cf0  \cf4 string\cf0  Message;\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;StructLayout&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;LayoutKind&lt;/span&gt;.Sequential, CharSet = &lt;span style="color: #2b91af;"&gt;CharSet&lt;/span&gt;.Unicode)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;struct&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;EventData&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; I;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Message;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And here is the delegate definition. Note the attribute UnmanagedFunctionPointer with the calling convention.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 [\cf3 UnmanagedFunctionPointer\cf0 (\cf3 CallingConvention\cf0 .Cdecl)]\par ??\cf4 public\cf0  \cf4 delegate\cf0  \cf4 void\cf0  \cf3 CallBackDelegate\cf0 (EventData data);}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;UnmanagedFunctionPointer&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;CallingConvention&lt;/span&gt;.Cdecl)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;delegate&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;CallBackDelegate&lt;/span&gt;(EventData data);&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In the mixed mode dll, here is the definition of the EventData data structure and function pointer:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;\red0\green128\blue0;}??\fs20 \cf1 #pragma\cf0  \cf1 once\par ??\par ??#include\cf0  \cf4 &amp;lt;windows.h&amp;gt;\par ??\par ??\cf5 // data structure for the callback function\par ??\cf1 struct\cf0  EventData\par ??\{\par ??\tab \cf1 int\cf0  I;\par ??\tab TCHAR* Message; \par ??\};\par ??\par ??\cf5 // callback function prototype\par ??\cf1 typedef\cf0  \cf1 void\cf0  (*NativeToManaged)(EventData data);}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;#pragma&lt;/span&gt; &lt;span style="color: blue;"&gt;once&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;#include&lt;/span&gt; &lt;span style="color: #a31515;"&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// data structure for the callback function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;struct&lt;/span&gt; EventData&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; I;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TCHAR* Message; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;};&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// callback function prototype&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;typedef&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; (*NativeToManaged)(EventData data);&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And the exported function is defined as in the following. Note how the .NET delegate gets invoked through the function pointer. &lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red0\green128\blue0;}??\fs20 \cf1 #define\cf0  INTEROPBRIDGE_API \cf1 __declspec\cf0 (\cf1 dllexport\cf0 )\par ??\par ??INTEROPBRIDGE_API \cf1 void\cf0  fnInteropBridge(EventData data)\par ??\{\par ??\tab ManagedLib::ManagedClass^ c = \cf1 gcnew\cf0  ManagedLib::ManagedClass();\par ??\tab IntPtr p = Marshal::GetFunctionPointerForDelegate(c-&amp;gt;GetDelegate());\par ??\tab \par ??\tab NativeToManaged funcPointer = (NativeToManaged) p.ToPointer();\par ??\par ??\tab \cf4 // invoke the delegate\par ??\cf0 \tab funcPointer(data);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;#define&lt;/span&gt; INTEROPBRIDGE_API &lt;span style="color: blue;"&gt;__declspec&lt;/span&gt;(&lt;span style="color: blue;"&gt;dllexport&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;INTEROPBRIDGE_API &lt;span style="color: blue;"&gt;void&lt;/span&gt; fnInteropBridge(EventData data)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ManagedLib::ManagedClass^ c = &lt;span style="color: blue;"&gt;gcnew&lt;/span&gt; ManagedLib::ManagedClass();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IntPtr p = Marshal::GetFunctionPointerForDelegate(c-&amp;gt;GetDelegate());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NativeToManaged funcPointer = (NativeToManaged) p.ToPointer();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// invoke the delegate&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; funcPointer(data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now in the native app, I have code that creates a copy of EventData and invokes the .NET code through the exported dll function fnInteropBridge:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green128\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 // forward definition of the API function\par ??\cf3 void\cf0  fnInteropBridge(EventData data);\par ??\par ??\cf3 int\cf0  _tmain(\cf3 int\cf0  argc, _TCHAR* argv[])\par ??\{\par ??\tab EventData data;\par ??\tab data.I = 50;\par ??\tab data.Message = L\cf5 "Hello from native code!"\cf0 ;\par ??\par ??\tab fnInteropBridge(data);\par ??\tab \par ??\tab \cf3 return\cf0  0;\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// forward definition of the API function&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;void&lt;/span&gt; fnInteropBridge(EventData data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;int&lt;/span&gt; _tmain(&lt;span style="color: blue;"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; EventData data;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; data.I = 50;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; data.Message = L&lt;span style="color: #a31515;"&gt;"Hello from native code!"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; fnInteropBridge(data);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 0;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In summary, I like this approach it that it provides quite an easy and non-invasive way for native code to call into managed code. It should especially work well in my scenario, where application context changes initiated from the native app needs to be propagated to the managed code. Furthermore, besides polishing this up, I think I will add code to raise a .NET event from inside ManagedClass.Foo(). Then all interested .NET citizens on the managed app side can subscribe to it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-913827605849520990?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/913827605849520990/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=913827605849520990' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/913827605849520990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/913827605849520990'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/09/reverse-pinvoke.html' title='Reverse P/Invoke'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-7274533132261823914</id><published>2008-09-23T23:09:00.000-04:00</published><updated>2008-09-26T16:30:50.764-04:00</updated><title type='text'>Follow-up of PIAB and WCF Article</title><content type='html'>Since publishing &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc136759.aspx"&gt;the MSDN article&lt;/a&gt; on an approach to integrate PIAB into WCF, I have received quite a few feedback from folks using this approach in production. And I am glad to say it's working out successfully for those folks. &lt;br /&gt;&lt;br /&gt;As I &lt;a href="http://tigerang.blogspot.com/2008/01/piab-and-wcf-article-published-on-msdn.html"&gt;mentioned earlier&lt;/a&gt; in the comment, &lt;a href="http://blogs.msdn.com/tomholl/"&gt;Tom Hollander&lt;/a&gt; of p&amp;p group has found an issue with our approach when two PIAB-enabled WCF services are hosted in the same IIS worker process. He graciously shared his code with us and I was able to reproduce the problem when the two WCF services were hosted in two separate AppDomains of the same IIS worker process. Although in production deployment scenarios, different WCF services would likely be hosted in separate processes or on different machines, I have still been wanting to figure out the root cause of this particular issue. Unfortunately with work and other things in my life, I just haven't had time until last week when I was finally able to sit down and focused on this problem. &lt;br /&gt;&lt;br /&gt;I have to admit this has been the most tedious debugging I have ever done as I was deep in the guts of WCF and CLR, inspecting dynamic types, JIT compiler, call stubs, etc. without a whole lot of background in this area - I only wish I were working for the CLR team :-) After a few days, I finally found out the cause of the problem, which is pretty close to my initial hunch. A sense of elation at last! &lt;br /&gt;&lt;br /&gt;Here it goes. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;1. The setup to repro the problem&lt;/strong&gt;&lt;br /&gt;The setup is fairly straightforward. There are two WCF services, each implementing IService and IAnotherService respectively (the code is pretty much verbatim from Tom):&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 [\cf3 ServiceContract\cf0 ]\par ??\cf4 public\cf0 \cf4 interface\cf0 \cf3 IService\par ??\cf0 \{\par ?? [\cf3 OperationContract\cf0 ]\par ?? Foo GetFoo(\cf4 int\cf0 id);\par ??\par ?? [\cf3 OperationContract\cf0 ]\par ?? \cf4 void\cf0 AddFoo(\cf4 int\cf0 i, [\cf3 NotNullValidator\cf0 ] Foo foo);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;ServiceContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IService&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;OperationContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Foo GetFoo(&lt;span style="color: blue;"&gt;int&lt;/span&gt; id);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;OperationContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddFoo(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i, [&lt;span style="color: #2b91af;"&gt;NotNullValidator&lt;/span&gt;] Foo foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 [\cf3 ServiceContract\cf0 ]\par ??\cf4 public\cf0 \cf4 interface\cf0 \cf3 IAnotherService\par ??\cf0 \{\par ?? [\cf3 OperationContract\cf0 ]\par ?? \cf4 void\cf0 LogFoo(Foo foo);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;ServiceContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IAnotherService&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;OperationContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogFoo(Foo foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Both services would be enabled with PIAB of course: &lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 [PolicyInjectionBehaviors.\cf3 PolicyInjectionBehavior\cf0 ]\par ??[\cf3 ValidationCallHandler\cf0 ]\par ??[\cf3 LogCallHandler\cf0 ]\par ??\cf4 public\cf0 \cf4 class\cf0 \cf3 Service\cf0 : \cf3 IService\par ??\cf0 \{\par ?? \cf4 private\cf0 \cf4 static\cf0 \cf3 Dictionary\cf0 &amp;lt;\cf4 int\cf0 , \cf3 Foo\cf0 &amp;gt; store = \cf4 new\cf0 \cf3 Dictionary\cf0 &amp;lt;\cf4 int\cf0 , \cf3 Foo\cf0 &amp;gt;();\par ?? \cf3 IAnotherService\cf0 anotherService;\par ??\par ?? \cf4 public\cf0 Service()\par ?? \{\par ?? \cf3 BasicHttpBinding\cf0 binding = \cf4 new\cf0 \cf3 BasicHttpBinding\cf0 ();\par ?? binding.SendTimeout = \cf4 new\cf0 \cf3 TimeSpan\cf0 (4, 0, 0);\par ??\par ?? anotherService = \cf4 new\cf0 AnotherServiceClient(binding, \cf4 new\cf0 \cf3 EndpointAddress\cf0 (\cf5 "http://localhost/AnotherTestService/AnotherTestService.svc"\cf0 ));\par ?? \}\par ??\par ?? \cf4 public\cf0 \cf4 void\cf0 AddFoo(\cf4 int\cf0 id, \cf3 Foo\cf0 foo)\par ?? \{\par ?? store[id] = foo;\par ?? anotherService.LogFoo(foo);\par ?? \}\par ??\par ?? \cf4 public\cf0 \cf3 Foo\cf0 GetFoo(\cf4 int\cf0 id)\par ?? \{\par ?? \cf4 if\cf0 (store.ContainsKey(id))\par ?? \{\par ?? anotherService.LogFoo(store[id]);\par ?? \cf4 return\cf0 store[id];\par ?? \}\par ?? \cf4 else\par ??\cf0 \cf4 return\cf0 \cf4 null\cf0 ;\par ?? \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[PolicyInjectionBehaviors.&lt;span style="color: #2b91af;"&gt;PolicyInjectionBehavior&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;ValidationCallHandler&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;LogCallHandler&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Service&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IService&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;int&lt;/span&gt;, &lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt;&amp;gt; store = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Dictionary&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;int&lt;/span&gt;, &lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt;&amp;gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;IAnotherService&lt;/span&gt; anotherService;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; Service()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;BasicHttpBinding&lt;/span&gt; binding = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;BasicHttpBinding&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; binding.SendTimeout = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;TimeSpan&lt;/span&gt;(4, 0, 0);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; anotherService = &lt;span style="color: blue;"&gt;new&lt;/span&gt; AnotherServiceClient(binding, &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;EndpointAddress&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"http://localhost/AnotherTestService/AnotherTestService.svc"&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddFoo(&lt;span style="color: blue;"&gt;int&lt;/span&gt; id, &lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt; foo)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; store[id] = foo;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; anotherService.LogFoo(foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt; GetFoo(&lt;span style="color: blue;"&gt;int&lt;/span&gt; id)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (store.ContainsKey(id))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; anotherService.LogFoo(store[id]);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; store[id];&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 [PolicyInjectionBehaviors.\cf3 PolicyInjectionBehavior\cf0 ]\par ??[\cf3 ValidationCallHandler\cf0 ]\par ??[\cf3 LogCallHandler\cf0 ]\par ??\cf4 public\cf0  \cf4 class\cf0  \cf3 AnotherService\cf0  : IAnotherService\par ??\{\par ??    \cf4 public\cf0  \cf4 void\cf0  LogFoo(Foo foo)\par ??    \{\par ??        \cf3 Logger\cf0 .Write(\cf5 "LogFoo() called."\cf0 );\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[PolicyInjectionBehaviors.&lt;span style="color: #2b91af;"&gt;PolicyInjectionBehavior&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;ValidationCallHandler&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;LogCallHandler&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;AnotherService&lt;/span&gt; : IAnotherService&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogFoo(Foo foo)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;.Write(&lt;span style="color: #a31515;"&gt;"LogFoo() called."&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #2b91af;"&gt;Foo&lt;/span&gt; is simply a DataContract object that holds both an int and a string properties.&lt;br /&gt;&lt;br /&gt;Now the services would be hosted two AppDomains in the same IIS worker process. This is how it looks like on my Vista machine:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_UTl9xtmUmII/SNp9rM9w8iI/AAAAAAAAACE/sGUm7zxyMAE/s1600-h/WCF_PIAB_IIS.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_UTl9xtmUmII/SNp9rM9w8iI/AAAAAAAAACE/sGUm7zxyMAE/s400/WCF_PIAB_IIS.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5249646496821867042" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see both services are in the DefaultAppPool. With both services set up, we can run the test harness, which first calls Service.AddFoo() and then Service.GetFoo(). The Service.Foo() is completed fine but Service.GetFoo() call fails with a System.Reflection.TargetException: Object does not match target. The stack trace is as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;1017e344 79644832 System.Reflection.RuntimeMethodInfo.CheckConsistency(System.Object)&lt;br /&gt;1017e350 793a4124 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, Boolean)&lt;br /&gt;1017e39c 793a40a2 System.Reflection.RuntimeMethodInfo.Invoke(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)&lt;br /&gt;1017e3bc 0f96e699 Microsoft.Practices.EnterpriseLibrary.PolicyInjection.RemotingInterception.InterceptingRealProxy+&lt;&gt;c__DisplayClass1.&lt;Invoke&gt;b__0(Microsoft.Practices.EnterpriseLibrary.PolicyInjection.IMethodInvocation, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.GetNextHandlerDelegate)&lt;br /&gt;1017e3ec 0f968ed1 Microsoft.Practices.EnterpriseLibrary.PolicyInjection.HandlerPipeline.Invoke(Microsoft.Practices.EnterpriseLibrary.PolicyInjection.IMethodInvocation, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.InvokeHandlerDelegate)&lt;br /&gt;1017e404 0f968a2e Microsoft.Practices.EnterpriseLibrary.PolicyInjection.RemotingInterception.InterceptingRealProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)&lt;br /&gt;1017e418 79374dc3 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)&lt;br /&gt;1017e6b4 79f98b43 [TPMethodFrame: 1017e6b4] WcfPiabInstability.Services.&lt;font color="red"&gt;IAnotherService.LogFoo&lt;/font&gt;(WcfPiabInstability.Services.Foo)&lt;br /&gt;1017e6c4 0efd08dc DynamicClass.&lt;font color="red"&gt;SyncInvokeGetFoo&lt;/font&gt;(System.Object, System.Object[], System.Object[])&lt;br /&gt;1017e6d4 50b8d90b System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(System.Object, System.Object[], System.Object[] ByRef)&lt;br /&gt;1017e74c 50b6d245 System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e7a0 509137ad System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e7e0 509136a6 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e80c 50913613 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e81c 50913459 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e82c 50912257 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(System.ServiceModel.Dispatcher.MessageRpc ByRef)&lt;br /&gt;1017e844 50911f8f System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean)&lt;br /&gt;1017e888 509115ff System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(System.ServiceModel.Channels.RequestContext, Boolean, System.ServiceModel.OperationContext)&lt;br /&gt;1017ea34 5090f8c9 System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(System.ServiceModel.Channels.RequestContext, System.ServiceModel.OperationContext)&lt;br /&gt;1017ea78 5090f35e System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(System.IAsyncResult)&lt;br /&gt;1017ea8c 5090f2f1 System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(System.IAsyncResult)&lt;br /&gt;1017ea98 50232d68 System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult)&lt;br /&gt;1017eac4 50904501 System.ServiceModel.AsyncResult.Complete(Boolean)&lt;br /&gt;1017eb00 50992b36 System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader[[System.__Canon, mscorlib]].Set(Item&lt;System.__Canon&gt;)&lt;br /&gt;1017eb14 50992215 System.ServiceModel.Channels.InputQueue`1[[System.__Canon, mscorlib]].EnqueueAndDispatch(Item&lt;System.__Canon&gt;, Boolean)&lt;br /&gt;1017eb7c 50991ffb System.ServiceModel.Channels.InputQueue`1[[System.__Canon, mscorlib]].EnqueueAndDispatch(System.__Canon, System.ServiceModel.Channels.ItemDequeuedCallback, Boolean)&lt;br /&gt;1017eba4 5091d7e5 System.ServiceModel.Channels.SingletonChannelAcceptor`3[[System.__Canon, mscorlib],[System.__Canon, mscorlib],[System.__Canon, mscorlib]].Enqueue(System.__Canon, System.ServiceModel.Channels.ItemDequeuedCallback, Boolean)&lt;br /&gt;1017ebc8 50977b7e System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(System.ServiceModel.Channels.HttpRequestContext, System.ServiceModel.Channels.ItemDequeuedCallback)&lt;br /&gt;1017ec0c 5094f396 System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(System.ServiceModel.Activation.HostedHttpRequestAsyncResult)&lt;br /&gt;1017ec50 5094e4cf System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()&lt;br /&gt;1017ec68 5094defd System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()&lt;br /&gt;1017eca4 5094dea5 System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(System.Object)&lt;br /&gt;1017ecd0 50903c3c System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2()&lt;br /&gt;1017ed0c 50903b26 System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke()&lt;br /&gt;1017ed20 50903ab5 System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks()&lt;br /&gt;1017ed54 5090390f System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback(System.Object)&lt;br /&gt;1017ed80 5090388b System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)&lt;br /&gt;1017ed8c 50232e1f System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame(UInt32, UInt32, System.Threading.NativeOverlapped*)&lt;br /&gt;1017edc0 79405534 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)&lt;br /&gt;1017ef60 79e7c74b [GCFrame: 1017ef60] &lt;br /&gt;1017f0b8 79e7c74b [ContextTransitionFrame: 1017f0b8] &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;2. Culprit - a subtle bug in the CLR?&lt;/strong&gt;&lt;br /&gt;What is going on here? The exception is being thrown by System.Reflection.RuntimeMethodInfo.CheckConsistency() but the problem happened earlier. Notice the red in those two lines of the stack trace. DynamicClass.SyncInvokeGetFoo is the function generated by WCF using Lightweight Code Gen (LCG) to facilitate the GetFoo() call, which is in IService definition. But the next one on the call stack somehow becomes IAnotherService.LogFoo() - please be reminded that IAnotherService.LogFoo() call on the stack here is not to be confused with the one inside the Service.GetFoo() as the call hasn't reached to the actual object yet when exception happens. Using SOS command !clrstack -p and !dumpobject reveals that the object reference in the call context here is the PIAB proxy to the Service object (tp-&gt;rp-&gt;real object), which implements IService but not IAnotherService. The mismatch simply didn't manifest into an exception until later in System.Reflection.RuntimeMethodInfo.CheckConsistency(). So where the exception is thrown is not that important. We need to understand why IService.GetFoo() suddenly becomes IAnotherService.LogFoo().&lt;br /&gt;&lt;br /&gt;Let's review the high level picture of how the calls are being dispatched from the client site (we will only consider synchronous calls for now):&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Client makes a call by sending an XML message to the WCF service&lt;/li&gt;&lt;br /&gt;&lt;li&gt;WCF processes the message in the pipeline before it finally dispatches the call through System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() as shown on the stack trace. System.ServiceModel.Dispatcher.InvokerUtil uses LCG to generate a delegate SyncInvokeXXXX, where XXXX is the target method name and SyncInvoke stands for synchronous call. SyncMethodInvoker.Invoke() simply passes control to SyncInvokeXXXX(). This part is not that difficult to figure out by using Reflector. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;CLR takes the buck from here. Starting with 2.0, .NET uses dispatch stub to handle interface calls. The runtime figures out the method disptach token and sends it along with the target object reference to mscorwks!ResolveWorkerAsmStub, which calls mscorwks!VirtualCallStubManager::ResolveWorkerStatic and then the heavy lifting mscorwks!VirtualCallStubManager::ResolveWorker to figure out the stub that contains the assembly code to make the actual call. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;PIAB proxy gets called. This is where the injection magic happens and service method finally gets called.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;The dispatch token is a 32 bit integer with hi as the type id of the interface and lo as the slot number of the method as shown in the Rotor(SSCLI) source code:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20 \par ?? \cf3 static\cf0 \cf3 const\cf0 UINT_PTR MASK_TYPE_ID = 0x0000FFFF;\par ?? \cf3 static\cf0 \cf3 const\cf0 UINT_PTR MASK_SLOT_NUMBER = 0x0000FFFF;\par ??\par ?? \cf3 static\cf0 \cf3 const\cf0 UINT_PTR SHIFT_TYPE_ID = 0x10;\par ?? \cf3 static\cf0 \cf3 const\cf0 UINT_PTR SHIFT_SLOT_NUMBER = 0x0;\par ??\par ?? \cf4 //------------------------------------------------------------------------\par ??\cf0 \cf4 // Combines the two values into a single 32-bit number.\par ??\cf0 \cf3 static\cf0 UINT_PTR CreateToken(UINT32 typeID, UINT32 slotNumber)\par ?? \{\par ?? LEAF_CONTRACT;\par ?? CONSISTENCY_CHECK(((UINT_PTR)typeID &amp;amp; MASK_TYPE_ID) == (UINT_PTR)typeID);\par ?? CONSISTENCY_CHECK(((UINT_PTR)slotNumber &amp;amp; MASK_SLOT_NUMBER) == (UINT_PTR)slotNumber);\par ?? \cf3 return\cf0 ((((UINT_PTR)typeID &amp;amp; MASK_TYPE_ID) &amp;lt;&amp;lt; SHIFT_TYPE_ID) |\par ?? (((UINT_PTR)slotNumber &amp;amp; MASK_SLOT_NUMBER) &amp;lt;&amp;lt; SHIFT_SLOT_NUMBER));\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; UINT_PTR MASK_TYPE_ID&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; = 0x0000FFFF;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; UINT_PTR MASK_SLOT_NUMBER&amp;nbsp;&amp;nbsp; = 0x0000FFFF;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; UINT_PTR SHIFT_TYPE_ID&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; = 0x10;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; UINT_PTR SHIFT_SLOT_NUMBER&amp;nbsp; = 0x0;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;//------------------------------------------------------------------------&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: green;"&gt;// Combines the two values into a single 32-bit number.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; UINT_PTR CreateToken(UINT32 typeID, UINT32 slotNumber)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LEAF_CONTRACT;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONSISTENCY_CHECK(((UINT_PTR)typeID &amp;amp; MASK_TYPE_ID) == (UINT_PTR)typeID);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CONSISTENCY_CHECK(((UINT_PTR)slotNumber &amp;amp; MASK_SLOT_NUMBER) == (UINT_PTR)slotNumber);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; ((((UINT_PTR)typeID &amp;amp; MASK_TYPE_ID) &amp;lt;&amp;lt; SHIFT_TYPE_ID) |&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; (((UINT_PTR)slotNumber &amp;amp; MASK_SLOT_NUMBER) &amp;lt;&amp;lt; SHIFT_SLOT_NUMBER));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Type ids are integer identifiers to represent types in an AppDomain. Slot numbers are integer values representing entries of interface methods in the method table. In the example I am using, IService has a type id of 0x0003 and AddFoo has a slot number of 0x0001, therefore yielding a token of 0x00030001. IService.GetFoo has a dispatch token of 0x00030000. And IAnotherService.LogFoo also has a token of 0x0003000. You see that both IService and IAnotherService, living in two AppDomains, happen to have the same type id: 0x0003. It is a coincidence, but not to be ignored. &lt;br /&gt;&lt;br /&gt;The reason why the dispatch token is critical here is because of the following:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;all interface disptach stubs for our PIAB enabled services are handled by the VirtualCallStubManager in the shared domain of the process.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;the stub manager keeps a hash table to cache the stub code using those two keys: token and object type. In our example, the object type is always a transparent proxy for PIAB-enabled services. So effectively token becomes the only key that matters.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;the heavy lifting mscorwks!VirtualCallStubManager::ResolveWorker() is responsible for generating and caching the stub. Obviously it always first checks if there is a cached entry. If one is found using the keys, that entry will be returned. &lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;When our unit test harness calls Service.AddFoo, which internally calls AnotherService.LogFoo, two dispatch stubs are created and cached by the shared stub manager, with tokens 0x00030001 and 0x00030000 as the effective key respectively. Now the unit test makes a different call Service.GetFoo. Note that IService.GetFoo also has the dispatch token as 0x00030000, same as IAnotherSevice.LogFoo, despite the fact they are two types in different domains. The stub manager of the shared domain hands out the previously cached dispatch stub for IAnotherService.LogFoo. This is why we saw the strange call stack above and the call eventually fails.&lt;br /&gt;&lt;br /&gt;To further prove this, I changed the definition of IAnotherService to the following to include 5 additional functions as fillers to the method table slots:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red0\green128\blue0;}??\fs20 [\cf3 ServiceContract\cf0 ]\par ??\cf4 public\cf0 \cf4 interface\cf0 \cf3 IAnotherService\par ??\cf0 \{\par ?? \cf5 // fillers \par ??\cf0 \cf4 void\cf0 Filler1();\par ?? \cf4 void\cf0 Filler2();\par ?? \cf4 void\cf0 Filler3();\par ?? \cf4 void\cf0 Filler4();\par ?? \cf4 void\cf0 Filler5();\par ??\par ?? [\cf3 OperationContract\cf0 ]\par ?? \cf4 void\cf0 LogFoo(Foo foo);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;ServiceContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;IAnotherService&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// fillers &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Filler1();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Filler2();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Filler3();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Filler4();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Filler5();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;OperationContract&lt;/span&gt;]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogFoo(Foo foo);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The purpose is to alter the slot number of IAnotherService.LogFoo to avoid the token clash. As shown in the following Windbg snippet, I did indeed get a token of 0x00030005 as opposed to the 0x0003000 that I had earlier: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;eax=&lt;font color="red"&gt;00000003&lt;/font&gt; ebx=0e3f6228 ecx=79e89e87 edx=00000003 esi=&lt;font color="red"&gt;00000005&lt;/font&gt; edi=01c45b18&lt;br /&gt;eip=79eb45cf esp=1057dd4c ebp=1057dd80 iopl=0 nv up ei pl nz ac po cy&lt;br /&gt;cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213&lt;br /&gt;mscorwks!VirtualCallStubManager::GetCallStub+0x34:&lt;br /&gt;79eb45cf c1e010 &lt;font color="green"&gt;shl eax,10h&lt;/font&gt;&lt;br /&gt;0:025&gt; p&lt;br /&gt;eax=&lt;font color="red"&gt;00030000&lt;/font&gt; ebx=0e3f6228 ecx=79e89e87 edx=00000003 esi=&lt;font color="red"&gt;00000005&lt;/font&gt; edi=01c45b18&lt;br /&gt;eip=79eb45d2 esp=1057dd4c ebp=1057dd80 iopl=0 nv up ei pl nz ac pe nc&lt;br /&gt;cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216&lt;br /&gt;mscorwks!VirtualCallStubManager::GetCallStub+0x37:&lt;br /&gt;79eb45d2 0bf0 &lt;font color="green"&gt;or esi,eax&lt;/font&gt;&lt;br /&gt;0:025&gt; p&lt;br /&gt;eax=00030000 ebx=0e3f6228 ecx=79e89e87 edx=00000003 esi=&lt;font color="red"&gt;00030005&lt;/font&gt; edi=01c45b18&lt;br /&gt;eip=79eb45d4 esp=1057dd4c ebp=1057dd80 iopl=0 nv up ei pl nz na pe nc&lt;br /&gt;cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the CLR happily makes all the calls without the dreadful exception! &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. Summary&lt;/strong&gt;&lt;br /&gt;It is interesting to see how the CLR team may have tried to safeguard the clashing of the keys by using both token and the object type. In our case, the object type, being the transparent proxy for PIAB-enabled services, takes that key out of the equation. The token, although having HI corresponding to the interface type and LO to the slot number, is scoped within the AppDomain where the type is loaded. The fewer the number of types and the fewer the methods of the operation contracts are defined for the WCF service in each AppDomain, the bigger the odds key clashing like this will happen. &lt;br /&gt;&lt;br /&gt;So what is the solution? Could other interface method related values such as MethodDesc, which seems to be unique across app domains, be a better candidate? That is the question for the CLR team.&lt;br /&gt;&lt;br /&gt;As for us who want to integrate PIAB into WCF while minimizing development team efforts, we should be fine by hosting WCF services in separate processes. If you really, really want to host everything in one IIS worker process like our contrived example, you can get around this issue by not using the default PIAB interception mechanism. Suppose you can come up with a LCG mechanism to generate one dynamic proxy (instead of System.Runtime.Remoting.Proxies.__TransparentProxy) for each target. Having a different object type as each service's PIAB intercepting proxy will therefore avoid the key clashing. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4. Tools etc.&lt;/strong&gt;&lt;br /&gt;Debugging is always an enlightening experience. And I can't imagine what life is going to be without Windbg and Reflector. Visual Studio 2008 is cool since you can configure it to debug into .NET framework code. But if the symbols are not available for the module you want to investigate or you need to dig deeper below the FCL layer, Reflector and Windbg are just indispensable. &lt;br /&gt;&lt;br /&gt;Also, having SSCLI source code is absolutely wonderful. Without it, debugging through machine code in windbg would be a lot harder. &lt;br /&gt;&lt;br /&gt;Most of the SSCLI code for this exercise is located inside &lt;a href="http://www.koders.com/cpp/fidD25A3F8FFAB28F672B5E53EE4A4BF6D1C174E149.aspx"&gt;virtualcallstub.cpp&lt;/a&gt; file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-7274533132261823914?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/7274533132261823914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=7274533132261823914' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7274533132261823914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7274533132261823914'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/09/follow-up-of-piab-and-wcf-article.html' title='Follow-up of PIAB and WCF Article'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_UTl9xtmUmII/SNp9rM9w8iI/AAAAAAAAACE/sGUm7zxyMAE/s72-c/WCF_PIAB_IIS.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-5777217099660690108</id><published>2008-09-09T09:46:00.000-04:00</published><updated>2008-09-22T18:21:02.305-04:00</updated><title type='text'>Interview Questions</title><content type='html'>Having a list of questions with standard answers to score candidates during technical screenings certainly has its benefits, especially maintaining consistencies across different interviewers. However if the interviewer simply compares the candidate's answers to the official ones, then she is not doing her job. Interview is an interactive process and should be leveraged as such. Many seemingly easy questions can be extended to discussions at both broader and deeper levels. You will get a better picture of candidate's overall skills and experiences this way. For example, there is usually a basic question on the differences between value and reference types. This question can be extended to boxing/unboxing, and the scenarios where boxing/unboxing can occur and the performance implications, which can be a good starting point to test candidate's knowledge on generics. There are semantic implications of boxing and unboxing as well. A boxed integer, e.g. is a brand new object with a copy of the initial integer value. The following is not allowed by the C# compiler:&lt;br /&gt;&lt;br /&gt;int i = 1; // class instance field&lt;br /&gt;&lt;br /&gt;lock(i)&lt;br /&gt;{&lt;br /&gt;//...&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;You could hack it with:&lt;br /&gt;&lt;br /&gt;lock ((object)i)&lt;br /&gt;{&lt;br /&gt;//...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;But you will not get the intended lock semantics. I will leave it to you to answer why that is the case. If you know the answer, you will see that you can evaluate the candidate's knowledge of threading and synchronization, besides boxing/unboxing.&lt;br /&gt;&lt;br /&gt;And there is more! A related topic is passing by reference vs. passing by value in function calls (I had a &lt;a href="http://tigerang.blogspot.com/2007/01/byref-snafu.html"&gt;previous blog&lt;/a&gt; in this area). And you can take the initial question and extend it to a discussion on heap vs. stack and further on GC. &lt;br /&gt;&lt;br /&gt;So you see how one easy question can be extended quite a bit and become the vehicle for you to test candidate's overall knowledge. Of course you need to be sensitive to time and not go off to all directions. You usually will get a sense of the candidate's knowledge half way through and can decide whether to go further or not from that point.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-5777217099660690108?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/5777217099660690108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=5777217099660690108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5777217099660690108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5777217099660690108'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/09/interview-questions.html' title='Interview Questions'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-2873249182478104336</id><published>2008-06-20T15:46:00.000-04:00</published><updated>2008-06-20T16:28:41.873-04:00</updated><title type='text'>I Am Back</title><content type='html'>For the last three months, I was working for a client on envisioning the next generation architecture of a highly impactful desktop application. Despite the short 3 months time, it was nevertheless a winding journey. Because of the impact of the application, business and politics drove a lot of the architecture decisions, and a lot of long nights too. Now that the project is on hold until the next phase, I can get back inside Visual Studio and be really technical for a short while.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-2873249182478104336?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/2873249182478104336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=2873249182478104336' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2873249182478104336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2873249182478104336'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/06/i-am-back.html' title='I Am Back'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-7436489467865582612</id><published>2008-03-14T16:31:00.000-04:00</published><updated>2008-03-14T17:26:52.929-04:00</updated><title type='text'>Debug.Assert in ASP.NET Application</title><content type='html'>My most recent project was an ASP.NET 2.0 application developed in Visual Studio 2005. During the first build and deployment into dev integration environment, everything went pretty well except for one page. Request for this page was just hanging. I started to investigate and I captured a hang dump using adplus. In windbg, I found out the longest running thread. Suspecting that is the thread that was hanging, I looked at its CLR stack:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:001&gt; !clrstack&lt;br /&gt;*********************************************************************&lt;br /&gt;* Symbols can not be loaded because symbol path is not initialized. *&lt;br /&gt;* *&lt;br /&gt;* The Symbol Path can be set by: *&lt;br /&gt;* using the _NT_SYMBOL_PATH environment variable. *&lt;br /&gt;* using the -y &lt;symbol_path&gt; argument when starting the debugger. *&lt;br /&gt;* using .sympath and .sympath+ *&lt;br /&gt;*********************************************************************&lt;br /&gt;PDB symbol for mscorwks.dll not loaded&lt;br /&gt;OS Thread Id: 0x2fac (1)&lt;br /&gt;ESP EIP &lt;br /&gt;006bf414 77f88a77 [NDirectMethodFrameStandalone: 006bf414] Microsoft.Win32.SafeNativeMethods.MessageBox(System.Runtime.InteropServices.HandleRef, System.String, System.String, Int32)&lt;br /&gt;006bf430 7a4f839a System.Diagnostics.AssertWrapper.ShowMessageBoxAssert(System.String, System.String, System.String)&lt;br /&gt;006bf460 7a4fabb2 System.Diagnostics.DefaultTraceListener.Fail(System.String, System.String)&lt;br /&gt;006bf4a0 7a4faad7 System.Diagnostics.DefaultTraceListener.Fail(System.String)&lt;br /&gt;006bf4a4 7a500a22 System.Diagnostics.TraceInternal.Fail(System.String)&lt;br /&gt;006bf4e0 7a6e2523 System.Diagnostics.TraceInternal.Assert(Boolean, System.String)&lt;br /&gt;006bf4e4 7a4fa6cb System.Diagnostics.Debug.Assert(Boolean, System.String)&lt;br /&gt;006bf4e8 1ae8b7c9 CondosPaymentPageBase.GetResidentData()&lt;br /&gt;006bf528 1ae8b567 CondosPaymentPageBase.OnLoad(System.EventArgs)&lt;br /&gt;006bf534 66143ad0 System.Web.UI.Control.LoadRecursive()&lt;br /&gt;006bf548 66155106 System.Web.UI.Page.ProcessRequestMain(Boolean, Boolean)&lt;br /&gt;006bf700 66154a1b System.Web.UI.Page.ProcessRequest(Boolean, Boolean)&lt;br /&gt;006bf738 66154967 System.Web.UI.Page.ProcessRequest()&lt;br /&gt;006bf770 66154887 System.Web.UI.Page.ProcessRequestWithNoAssert(System.Web.HttpContext)&lt;br /&gt;006bf778 6615481a System.Web.UI.Page.ProcessRequest(System.Web.HttpContext)&lt;br /&gt;006bf78c 1bb8ccae ASP.payment_3_history_aspx.ProcessRequest(System.Web.HttpContext)&lt;br /&gt;006bf798 65ff27d4 System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()&lt;br /&gt;006bf7cc 65fc15b5 System.Web.HttpApplication.ExecuteStep(IExecutionStep, Boolean ByRef)&lt;br /&gt;006bf80c 65fd32e0 System.Web.HttpApplication+ApplicationStepManager.ResumeSteps(System.Exception)&lt;br /&gt;006bf85c 65fc0225 System.Web.HttpApplication.System.Web.IHttpAsyncHandler.BeginProcessRequest(System.Web.HttpContext, System.AsyncCallback, System.Object)&lt;br /&gt;006bf878 65fc550b System.Web.HttpRuntime.ProcessRequestInternal(System.Web.HttpWorkerRequest)&lt;br /&gt;006bf8ac 65fc5212 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)&lt;br /&gt;006bf8b8 65fc3587 System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)&lt;br /&gt;006bfa68 79f35ee8 [ContextTransitionFrame: 006bfa68] &lt;br /&gt;006bfab8 79f35ee8 [GCFrame: 006bfab8] &lt;br /&gt;006bfc10 79f35ee8 [ComMethodFrame: 006bfc10] &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the native stack looked like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:001&gt; kb&lt;br /&gt;ChildEBP RetAddr Args to Child &lt;br /&gt;006bf1b0 77e4f9f0 50000018 00000003 00000003 NTDLL!ZwRaiseHardError+0xb&lt;br /&gt;006bf20c 77e34398 00d3b684 00d3c298 00040212 USER32!ServiceMessageBox+0x16b&lt;br /&gt;006bf35c 77e339cb 006bf36c 006bfa68 00000028 USER32!MessageBoxWorker+0x10a&lt;br /&gt;006bf3b4 77e4fa54 00000000 00d3b684 00d3c298 USER32!MessageBoxExW+0x77&lt;br /&gt;*** WARNING: Unable to verify checksum for System.ni.dll&lt;br /&gt;006bf43c 7a4fad1d 00000000 00d1c4fc 00d28944 USER32!MessageBoxW+0x49&lt;br /&gt;006bf454 7a4fabb2 00000000 00d24bf8 04cfda28 System_ni+0xbad1d&lt;br /&gt;006bf494 7a4faad7 00000000 7a500a22 00000000 System_ni+0xbabb2&lt;br /&gt;006bf4d8 7a6e2523 7a4fa6cb 1ae8b7c9 00d113c0 System_ni+0xbaad7&lt;br /&gt;00000000 00000000 00000000 00000000 00000000 System_ni+0x2a2523&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;At this point, it was clear to me that some data condition in dev int environment had caused Debug.Assert to fail. The assert failure message box was waiting to be closed. But on an IIS box with the ASP worker process running in the context of a service account, this UI interaction is simply not going to work. &lt;br /&gt;&lt;br /&gt;As you may know, Debug.Assert will be left out of the IL code by compilers for release build. Our MSBuild script that produced the deployment package did have the "release" switch turned on. So what went wrong? It turned out that &lt;a href="http://msdn2.microsoft.com/en-us/asp.net/aa336619.aspx"&gt;the web deployment &lt;/a&gt; project we had, "Generate debug information" option was checked. I initially thought this would give me pdb files. But obviously this meant a debug build, irrespective of the "Configuration=Release" setting for the MSBuild script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-7436489467865582612?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/7436489467865582612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=7436489467865582612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7436489467865582612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7436489467865582612'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/03/debugassert-in-aspnet-application.html' title='Debug.Assert in ASP.NET Application'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6149880158106382176</id><published>2008-01-13T11:27:00.000-05:00</published><updated>2008-06-18T22:55:19.883-04:00</updated><title type='text'>PIAB and WCF Article Published on MSDN Magazine</title><content type='html'>The article that I have coauthored with my Avanade colleague &lt;a href="http://www.mtelligent.com/"&gt;David San Filippo&lt;/a&gt; is now published in the February issue of MSDN magazine. If you have subscribed to MSDN, you should have received it in your mail box by now. The online link is &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc136759.aspx"&gt;here&lt;/a&gt;. Basically the article details how to integrate PIAB into WCF via .NET configuration or attribute so developers would not have to write code to apply the goodness of PIAB to WCF. &lt;br /&gt;&lt;br /&gt;It's been an absolutely wonderful experience working with MSDN editors, Howard Dierking, Nancy Michell and Debra Kelly so I'd like to extend a big "thank you" to them from here. My colleague David is one of the smartest developers I have worked with; it only took a few weekends for us to come up with a draft of this article after the brainstorming back in last August.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6149880158106382176?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6149880158106382176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6149880158106382176' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6149880158106382176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6149880158106382176'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/01/piab-and-wcf-article-published-on-msdn.html' title='PIAB and WCF Article Published on MSDN Magazine'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-3899053698559360617</id><published>2008-01-09T15:17:00.000-05:00</published><updated>2008-01-09T15:37:11.156-05:00</updated><title type='text'>A Good Book on Windbg</title><content type='html'>Since I have never worked for any Microsoft product team, a good way for me to get internal system knowledge is through debugging, using tools like Windbg (Visual Studio as an IDE can be good for debugging too, but is limited in functionalities compared with Windbg). &lt;br /&gt;&lt;br /&gt;Over the years, I have gained my Windbg skills by reading blogs (thanks to those who post them) and just practicing it on my own whenever I have a chance. Most of the debugging books don't have enough coverage in this area. So I was really excited after I found out that Addison Wesley has published this &lt;a href="http://www.bookpool.com/sm/0321374460"&gt;Advanced Windows Debugging&lt;/a&gt; book. You should read this book if you are seriously thinking about learning Windbg.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-3899053698559360617?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/3899053698559360617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=3899053698559360617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3899053698559360617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3899053698559360617'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2008/01/good-book-on-windbg.html' title='A Good Book on Windbg'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-1911246413741712784</id><published>2007-12-18T14:36:00.000-05:00</published><updated>2007-12-18T16:15:47.693-05:00</updated><title type='text'>Debugging MAPI Problems</title><content type='html'>I have been quiet here for the last month or so, one of the reasons being that I have been bogged down by a lot of application issues in production. The most recent one had to do with 4 Windows services on the production database server. Those services, developed in VB long time ago, run as work flow engines, polling/querying the database on a timer, changing the state of work flow items according to business rules and emailing the next person in the queue using MAPI function. Those services were developed at different times but they have very similar functionalities. Most of the source code was just copied from the very first one unfortunately. &lt;br /&gt;&lt;br /&gt;About a week ago, those services started to hang - users are usually first to tell because the work flow items don't get routed after a couple of minutes as it is supposed to. I have been doing analysis with the hang dumps created by ADPLUS, arriving at the conclusion that MAPI call was the culprit. However, I haven't figured out exactly what in the MAPI call caused the problem due to lack of MAPI debug symbols. I am going to blog the debugging result anyway - hopefully someone with similar experiences with MAPI can point out the issue. &lt;br /&gt;&lt;br /&gt;The following shows the stack of the main thread of the services that are hanging:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;0:000&gt; kb&lt;br /&gt;ChildEBP RetAddr  Args to Child              &lt;br /&gt;0012e64c 7c59a072 000005a4 00000000 00000000 NTDLL!ZwWaitForSingleObject+0xb&lt;br /&gt;0012e674 7c57b3e9 000005a4 ffffffff 00000000 KERNEL32!WaitForSingleObjectEx+0x71&lt;br /&gt;*** ERROR: Symbol file could not be found.  Defaulted to export symbols for MSMAPI32.DLL - &lt;br /&gt;0012e684 35ffbee7 000005a4 ffffffff 0de623a0 KERNEL32!WaitForSingleObject+0xf&lt;br /&gt;WARNING: Stack unwind information not available. Following frames may be wrong.&lt;br /&gt;0012e6fc 35f789e7 00000000 02dad738 02da27d8 MSMAPI32!FPropContainsProp+0x2612&lt;br /&gt;*** ERROR: Symbol file could not be found.  Defaulted to export symbols for MAPI32.DLL - &lt;br /&gt;0012e744 61dd2d09 00000000 02da33f8 02da2228 MSMAPI32!MAPILogonEx+0xa7&lt;br /&gt;*** ERROR: Symbol file could not be found.  Defaulted to export symbols for CDO.DLL - &lt;br /&gt;0012e76c 0dd025ea 00000000 02da33f8 02da2228 MAPI32!MAPILogonEx+0x79&lt;br /&gt;00000000 00000000 00000000 00000000 00000000 CDO!DllUnregisterServer+0x10eea&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To see what WaitForSingleObject() is waiting on:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;0:000&gt; !handle 5a4 f&lt;br /&gt;Handle 000005a4&lt;br /&gt;  Type          Mutant&lt;br /&gt;  Attributes    0&lt;br /&gt;  GrantedAccess 0x120001:&lt;br /&gt;         ReadControl,Synch&lt;br /&gt;         QueryState&lt;br /&gt;  HandleCount   6&lt;br /&gt;  PointerCount  12&lt;br /&gt;  Name          \BaseNamedObjects\4D4150494C6F676F6E0070B872C47FD7101B8BEA00AA0038C699_S-1-5-21-1346851753-1016681682-1202159320-1002&lt;br /&gt;  Object specific information&lt;br /&gt;    Mutex is Owned&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If the export symbols are close enough, the MAPILogonEx() is waiting on this mutex, which has a name suffixed with a SID, which belongs to the service account the services are running as. The SID suffix seems to reenforce the conjecture that MAPILogonEx() is being called.&lt;br /&gt;&lt;br /&gt;While 3 out of the 4 services have their main threads like that, the forth one is different:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;0:000&gt; kb&lt;br /&gt;ChildEBP RetAddr  Args to Child              &lt;br /&gt;0012de34 7c59a072 00000664 00000000 00000000 NTDLL!ZwWaitForSingleObject+0xb&lt;br /&gt;0012de5c 7c57b3e9 00000664 ffffffff 00000000 KERNEL32!WaitForSingleObjectEx+0x71&lt;br /&gt;*** ERROR: Symbol file could not be found.  Defaulted to export symbols for MSMAPI32.DLL - &lt;br /&gt;0012de6c 35f98779 00000664 ffffffff 00000000 KERNEL32!WaitForSingleObject+0xf&lt;br /&gt;WARNING: Stack unwind information not available. Following frames may be wrong.&lt;br /&gt;0012de94 35f98691 00000201 0012deec 0012decc MSMAPI32!DDLUnwrapObjectEx+0xc65&lt;br /&gt;*** ERROR: Symbol file could not be found.  Defaulted to export symbols for EMSABP32.DLL - &lt;br /&gt;0012dec4 35ae3c6e 00000004 00000201 00000000 MSMAPI32!DDLUnwrapObjectEx+0xb7d&lt;br /&gt;0012df10 35ae3bbd 023e2144 00000001 023e2170 EMSABP32!ABProviderInit+0x2611&lt;br /&gt;0012e028 35f72512 35f72570 360b6700 35f755d0 EMSABP32!ABProviderInit+0x2560&lt;br /&gt;00000000 00000000 00000000 00000000 00000000 MSMAPI32!DDCS_Enter+0x16&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This one is waiting on an event object:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;0:000&gt; !handle 664 f&lt;br /&gt;Handle 00000664&lt;br /&gt;  Type          Event&lt;br /&gt;  Attributes    0&lt;br /&gt;  GrantedAccess 0x1f0003:&lt;br /&gt;         Delete,ReadControl,WriteDac,WriteOwner,Synch&lt;br /&gt;         QueryState,ModifyState&lt;br /&gt;  HandleCount   2&lt;br /&gt;  PointerCount  4&lt;br /&gt;  Name          &lt;none&gt;&lt;br /&gt;  No object specific information available&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I suspect this process is the owner of the mutex, although I didn't have a chance to create a kernel dump to verify. &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;0:000&gt; !handle 370 f&lt;br /&gt;Handle 00000370&lt;br /&gt;  Type          Mutant&lt;br /&gt;  Attributes    0&lt;br /&gt;  GrantedAccess 0x1f0001:&lt;br /&gt;         Delete,ReadControl,WriteDac,WriteOwner,Synch&lt;br /&gt;         QueryState&lt;br /&gt;  HandleCount   6&lt;br /&gt;  PointerCount  12&lt;br /&gt;  Name          \BaseNamedObjects\4D4150494C6F676F6E0070B872C47FD7101B8BEA00AA0038C699_S-1-5-21-1346851753-1016681682-1202159320-1002&lt;br /&gt;  Object specific information&lt;br /&gt;    Mutex is Owned&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;We have moved the 4 services from the database server (Win2K) to a different box (Win2K3) and there hasn't been any hang problems so far, which suggests that the MAPI problem is probably local to that machine, rather than having to do with the exchange server. Here is the detail of MAPI32.dll on the database server:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;61dd0000 61df1000   MAPI32     (export symbols)       MAPI32.DLL&lt;br /&gt;    Loaded symbol image file: MAPI32.DLL&lt;br /&gt;    Image path: C:\Program Files\Common Files\System\MSMAPI\1033\MAPI32.DLL&lt;br /&gt;    Image name: MAPI32.DLL&lt;br /&gt;    Timestamp:        Wed Jan 13 11:08:14 1999 (369CC4EE)&lt;br /&gt;    CheckSum:         0002A798&lt;br /&gt;    ImageSize:        00021000&lt;br /&gt;    File version:     1.0.2536.0&lt;br /&gt;    Product version:  1.0.2536.0&lt;br /&gt;    File flags:       2 (Mask 3F) Pre-release&lt;br /&gt;    File OS:          40004 NT Win32&lt;br /&gt;    File type:        2.0 Dll&lt;br /&gt;    File date:        00000000.00000000&lt;br /&gt;    Translations:     0409.04e4&lt;br /&gt;    CompanyName:      Microsoft Corporation&lt;br /&gt;    ProductName:      Microsoft Exchange&lt;br /&gt;    InternalName:     MAPI32&lt;br /&gt;    OriginalFilename: MAPI32.DLL&lt;br /&gt;    ProductVersion:   1.0&lt;br /&gt;    FileVersion:      1.0.2536.0&lt;br /&gt;    FileDescription:  Extended MAPI 1.0 for Windows NT&lt;br /&gt;    LegalCopyright:   Copyright © 1986-1999 Microsoft Corp. All rights reserved.&lt;br /&gt;    LegalTrademarks:  Microsoft® and Windows® are registered trademarks of Microsoft Corporation.&lt;br /&gt;    Comments:         Service Pack 3&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now back to investigating ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-1911246413741712784?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/1911246413741712784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=1911246413741712784' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1911246413741712784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1911246413741712784'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/12/debugging-mapi-problems.html' title='Debugging MAPI Problems'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-3401110524127346700</id><published>2007-10-31T17:14:00.000-04:00</published><updated>2007-11-03T21:42:36.544-04:00</updated><title type='text'>Thread Pool</title><content type='html'>I mentioned in &lt;a href="http://tigerang.blogspot.com/2007/10/net-code-instrumentation-independent-of.html"&gt;my last post&lt;/a&gt; that I would cover some interesting topics that all relate to thread. Now here is the second one, on thread pool.&lt;br /&gt;&lt;br /&gt;Thread pool is an efficient way to achieve concurrency since it saves the cost of creating new threads all the time by reusing threads in a pool. To get a good understanding of how to leverage ThreadPool class in the .NET framework, you can start by reading Jeffery Richter's good &lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/06/NET/"&gt;article on MSDN&lt;/a&gt;. However that was .NET 1.1. In .NET 2.0, the ThreadPool class supports a total of 4 types of uses as opposed to 3, which can be seen clearly from the enumeration in SSCLI2: &lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 enum\cf0 ThreadpoolThreadType\par ??\{\par ?? WorkerThread,\par ?? CompletionPortThread,\par ?? WaitThread,\par ?? TimerMgrThread\par ??\};}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;enum&lt;/span&gt; ThreadpoolThreadType&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WorkerThread,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CompletionPortThread,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WaitThread,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TimerMgrThread&lt;/p&gt;&lt;p style="margin: 0px;"&gt;};&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;With the new ThreadPool class, we can&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;1) call a method on a worker thread by QueueUserWorkItem&lt;/li&gt;&lt;br /&gt;&lt;li&gt;2) call a method on an IO Completion port thread by UnsafeQueueNativeOverlapped&lt;/li&gt;&lt;br /&gt;&lt;li&gt;3) call a method on an IO Completion port thread when a kernel object is signaled by RegisterWaitForSingleObject&lt;/li&gt; &lt;br /&gt;&lt;li&gt;4) call a method on a worker thread by using System.Threading.Timer - note this is the API seemingly irrelevant to ThreadPool&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;While IO Completion Port (IOCP) is not new to native Windows, the inclusion of its API in thread pool is the latest feature added to .NET 2.0. IOCP is a mechanism on Windows to allow asynchronous IO. The IOCP threads will be woken up and start code execution if IO operation is complete. The Win32 API for this is GetQueuedCompletionStatus, which essentially doesn't return (thread back to the pool) until IO operation is done. And more interestingly, IOCP isn't just limited to being used for IO - ThreadPool.UnsafeQueueNativeOverlapped can be used just like ThreadPool.QueueUserWorkItem. Here is a code snippet for queueing a delegate to the IOCP threads via Overlapped data structure:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 unsafe\par ??\cf0 \{\par ??    \cf4 Overlapped\cf0  overlapped = \cf1 new\cf0  \cf4 Overlapped\cf0 (0, 0, \cf4 IntPtr\cf0 .Zero, \cf1 null\cf0 );\par ??    \cf4 NativeOverlapped\cf0 * pOverlapped = overlapped.Pack(IocpThreadProc, \cf1 null\cf0 );\par ??    \cf4 ThreadPool\cf0 .UnsafeQueueNativeOverlapped(pOverlapped);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;unsafe&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Overlapped&lt;/span&gt; overlapped = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Overlapped&lt;/span&gt;(0, 0, &lt;span style="color: #2b91af;"&gt;IntPtr&lt;/span&gt;.Zero, &lt;span style="color: blue;"&gt;null&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;NativeOverlapped&lt;/span&gt;* pOverlapped = overlapped.Pack(IocpThreadProc, &lt;span style="color: blue;"&gt;null&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ThreadPool&lt;/span&gt;.UnsafeQueueNativeOverlapped(pOverlapped);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note that unsafe keyword is used as native pointer is created. And here is the delegate:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 unsafe\cf0  \cf1 static\cf0  \cf1 void\cf0  IocpThreadProc(\cf1 uint\cf0  x, \cf1 uint\cf0  y, \cf4 NativeOverlapped\cf0 * p)\par ??\{   \par ??    \cf1 try\par ??\cf0     \{\par ??        Sort();\par ??    \}\par ??    \cf1 finally\par ??\cf0     \{\par ??        \cf4 Overlapped\cf0 .Free(p);\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;unsafe&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; IocpThreadProc(&lt;span style="color: blue;"&gt;uint&lt;/span&gt; x, &lt;span style="color: blue;"&gt;uint&lt;/span&gt; y, &lt;span style="color: #2b91af;"&gt;NativeOverlapped&lt;/span&gt;* p)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Sort();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;finally&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Overlapped&lt;/span&gt;.Free(p);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note that Free must be called in the finally block to ensure that memory is not leaked.&lt;br /&gt;&lt;br /&gt;The philosophy of IOCP is that the optimal number of concurrent running threads should be equal to the number of processors, because anything more would introduce the overhead of context switches between different threads. Peeking into the &lt;a href="http://www.koders.com/cpp/fid7316886C8F2DB23F271506CC01D8F0D3ABB008F4.aspx"&gt;win32threadpool.cpp&lt;/a&gt; file of SSCLI2, one can find that while both the number of worker threads and the number of IOCP threads can grow under the ceiling of upper limits set by ThreadPool.SetMaxThreads, IOCP has constraints from CPU utilization also. In other words, even if you set the max of IOCP threads to a number much higher than the number of processros, there won't be more concurrent threads than the number of processors if there is very high CPU utilization. On the other hand, the number of worker threads, under the situation of high CPU utilitzation, will likely grow under the ceiling with requests queued up. &lt;a href="http://blogs.thinktecture.com/buddhike/archive/2007/08/05/414907.aspx"&gt;This blog&lt;/a&gt; has shown empirical results proving this. The example is a bit of extreme in that a large number of highly computation-intensive requests are being queued to the thread pool. However it shouldn't be viewed that IOCP is always the better one to use. Remember now you can still call ThreadPool.SetMaxThreads to throttle the number of concurrent worker threads to achieve good results too. Measuring and tuning would be required in real world situations. While it's great that we have an additional option to be able to queue any requests to IOCP through UnsafeQueueNativeOverlapped, keep in mind that IOCP was designed to be a great mechanism to handle IO asynchronously. Examples, such as System.IO.FileStream, System.Net.Sockets.Socket, System.ServiceModel.Channels.MsmqQueue, etc. can be found in the FCL. So I'd conjecture that while using a custom IO device, if asynchronous IO is desired, the same pattern can be followed by passing the handle of the IO object to ThreadPool.BindHandle to associate the IO device to the IOCP of the ThreadPool. &lt;br /&gt;&lt;br /&gt;As to using System.Threading.Timer, &lt;a href="http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET/default.aspx"&gt;this great MSDN Article&lt;/a&gt; discusses it pretty well in comparison with System.Timers.Timer and System.Windows.Forms.Timer. It's important to remember that System.Timers.Timer is a wrapper of System.Threading.Timer. System.Windows.Forms.Timer uses a completely different mechanism, which is SetTimer Win32 API, posting WM_TIMER message to the application queue. This means that your delegate added to the Tick event will be running on the same UI thread that created the main application windows forms. As the UI thread processes a lot of messages, including mouse and keyboard messages, this mechanism will surely not get you a lot of mileage for concurrency if that's what you're looking for. &lt;br /&gt;&lt;br /&gt;As server apps like ASP.NET, WCF already have concurrency built in, ThreadPool should not be overly used in there. ThreadPool can be ideal in UI applications, Windows service, and batch applications, etc, if they need a lot of concurrency.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-3401110524127346700?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/3401110524127346700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=3401110524127346700' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3401110524127346700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3401110524127346700'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/10/thread-pool.html' title='Thread Pool'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-2050139715676539899</id><published>2007-10-31T15:24:00.000-04:00</published><updated>2008-12-08T15:58:52.159-05:00</updated><title type='text'>.NET Code Instrumentation That Is More Accurate?</title><content type='html'>I recently ran into a few interesting topics that all relate to Thread and I will share them with you here.&lt;br /&gt;&lt;br /&gt;Someone asked an interesting question to our company's community on how to instrument for just the time spent only in the thread when it is executing the code. Thread switching, thread idling/sleeping while waiting for IO, etc should not be counted.&lt;br /&gt;&lt;br /&gt;This is indeed pretty interesting as on a machine where a lot of threads are running concurrently, using the elapsed time (e.g. the Tracer in EntLib) approach, may give you inaccurate results if you just want to focus on measuring algorithm of your code. It will be further skewed if the thread running your code is given lower priorities than the other ones as thread scheduling on Windows is priority-driven and preemptive. &lt;br /&gt;&lt;br /&gt;After digging around a bit, I found a reasonable good approach to this problem, with the help of BCL of .NET framework. The Process type in System.Diagnostics namespace has a Threads property, which is a collection that corresponds to the Win32 threads in the process. The .NET type that represents the underlying Win32 thread is ProcessThread. It turns out that ProcessThread has properties for processor time, which is key to the solution. Specifically, the property I want to use is UserProcessorTime. Here is a simple wrapper class that I wrote, following the Tracer class pattern from EntLib. I have only kept necessary code to show the point – email me (hugh dot ang at gmail dot com) if you want to have my Visual Studio project that has the complete source code.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \cf1 public\cf0  \cf1 class\cf0  \cf4 ThreadTimer\cf0  : \cf4 IDisposable\par ??\cf0 \{\par ??    \cf1 private\cf0  \cf1 const\cf0  \cf1 string\cf0  LOG_CATEGORY = \cf5 "General"\cf0 ;\par ??\par ??    [\cf4 ThreadStatic\cf0 ()]\par ??    \cf1 private\cf0  \cf4 ProcessThread\cf0  _processThread;\par ??\par ??    \cf1 private\cf0  \cf1 int\cf0  _threadId;\par ??    \cf1 private\cf0  \cf4 TimeSpan\cf0  _start;\par ??\par ??    [\cf4 DllImport\cf0 (\cf5 "Kernel32"\cf0 , EntryPoint = \cf5 "GetCurrentThreadId"\cf0 , ExactSpelling = \cf1 true\cf0 )]\par ??    \cf1 private\cf0  \cf1 static\cf0  \cf1 extern\cf0  \cf4 Int32\cf0  GetCurrentWin32ThreadId();\par ??\par ??    \cf1 public\cf0  ThreadTimer()\par ??    \{\par ??        _threadId = ProcessThread.Id;\par ??        _start = ProcessThread.UserProcessorTime;\par ??\par ??        \cf4 Logger\cf0 .Write(\cf5 "ThreadTimer started"\cf0 , LOG_CATEGORY);\par ??    \}\par ??\par ??    \cf1 public\cf0  \cf1 void\cf0  Dispose()\par ??    \{\par ??        \cf1 double\cf0  duration = ProcessThread.UserProcessorTime.Subtract(_start).TotalSeconds;\par ??        \cf4 Logger\cf0 .Write(\par ??            \cf4 String\cf0 .Format(\cf5 "ThreadTimer ended with elapsed time of \{0\} seconds processor user time."\cf0 ,\par ??            duration),\par ??            LOG_CATEGORY);\par ??    \}\par ??    \par ??    \cf1 private\cf0  \cf4 ProcessThread\cf0  ProcessThread\par ??    \{\par ??        \cf1 get\par ??\cf0         \{\par ??            \cf1 if\cf0  (_processThread == \cf1 null\cf0 )\par ??            \{\par ??                \cf1 int\cf0  id = GetCurrentWin32ThreadId();\par ??                \cf1 foreach\cf0  (\cf4 ProcessThread\cf0  thread \cf1 in\cf0  \cf4 Process\cf0 .GetCurrentProcess().Threads)\par ??                \{\par ??                    \cf1 if\cf0  (thread.Id == id)\par ??                    \{\par ??                        _processThread = thread;\par ??                        \cf1 return\cf0  _processThread;\par ??                    \}\par ??                \}\par ??            \}\par ??\par ??            \cf1 return\cf0  _processThread;\par ??        \}\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ThreadTimer&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IDisposable&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; LOG_CATEGORY = &lt;span style="color: #a31515;"&gt;"General"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ThreadStatic&lt;/span&gt;()]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ProcessThread&lt;/span&gt; _processThread;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; _threadId;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;TimeSpan&lt;/span&gt; _start;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;DllImport&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Kernel32"&lt;/span&gt;, EntryPoint = &lt;span style="color: #a31515;"&gt;"GetCurrentThreadId"&lt;/span&gt;, ExactSpelling = &lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;extern&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Int32&lt;/span&gt; GetCurrentWin32ThreadId();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; ThreadTimer()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _threadId = ProcessThread.Id;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _start = ProcessThread.UserProcessorTime;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;.Write(&lt;span style="color: #a31515;"&gt;"ThreadTimer started"&lt;/span&gt;, LOG_CATEGORY);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Dispose()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;double&lt;/span&gt; duration = ProcessThread.UserProcessorTime.Subtract(_start).TotalSeconds;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Logger&lt;/span&gt;.Write(&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;String&lt;/span&gt;.Format(&lt;span style="color: #a31515;"&gt;"ThreadTimer ended with elapsed time of {0} seconds processor user time."&lt;/span&gt;,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; duration),&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; LOG_CATEGORY);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ProcessThread&lt;/span&gt; ProcessThread&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (_processThread == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; id = GetCurrentWin32ThreadId();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;ProcessThread&lt;/span&gt; thread &lt;span style="color: blue;"&gt;in&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Process&lt;/span&gt;.GetCurrentProcess().Threads)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (thread.Id == id)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _processThread = thread;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; _processThread;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; _processThread;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Here is how we can instrument a method called SortOperation:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red0\green128\blue0;}??\fs20 \cf1 using\cf0  (ThreadTimer threadTimer = \cf1 new\cf0  ThreadTimer())\par ??\{\par ??    \cf4 // simulate an operation that needs to be instrumented\par ??\cf0     SortOperation(i);\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; (ThreadTimer threadTimer = &lt;span style="color: blue;"&gt;new&lt;/span&gt; ThreadTimer())&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// simulate an operation that needs to be instrumented&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SortOperation(i);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To see how this works out in comparison to instrumentation of EntLib, I implemented the SortOperation() as in the following:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 static\cf0  \cf1 void\cf0  SortOperation(\cf1 int\cf0  x)\par ??\{\par ??    SortedList&amp;lt;\cf1 int\cf0 , \cf1 int\cf0 &amp;gt; slist = \cf1 new\cf0  SortedList&amp;lt;\cf1 int\cf0 , \cf1 int\cf0 &amp;gt;();\par ??    \cf1 for\cf0  (\cf1 int\cf0  i = x * 10000; i &amp;gt;= 0; i--)\par ??    \{\par ??        slist.Add(i, i);\par ??    \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; SortOperation(&lt;span style="color: blue;"&gt;int&lt;/span&gt; x)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SortedList&amp;lt;&lt;span style="color: blue;"&gt;int&lt;/span&gt;, &lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;gt; slist = &lt;span style="color: blue;"&gt;new&lt;/span&gt; SortedList&amp;lt;&lt;span style="color: blue;"&gt;int&lt;/span&gt;, &lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;for&lt;/span&gt; (&lt;span style="color: blue;"&gt;int&lt;/span&gt; i = x * 10000; i &amp;gt;= 0; i--)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; slist.Add(i, i);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To make it interesting, I first instrumented this method using both Tracer and my ThreadTimer and then instrumented the same method plus another method that does just IO, e.g. read from a file on disk. The IO method takes about 200 milliseconds. The following table summarizes the results:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_UTl9xtmUmII/RyjnN3WXWNI/AAAAAAAAABE/DQ0KyLomvog/s1600-h/results.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_UTl9xtmUmII/RyjnN3WXWNI/AAAAAAAAABE/DQ0KyLomvog/s320/results.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5127602401143380178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Without the IO method, both Tracer and ThreadTimer produce almost identical results. Based on the empirical results, it’s not hard to figure out that the algorithm of looping with SortedList &lt;&gt; is O(N&lt;sup&gt;2&lt;/sup&gt;). When the IO method is included, EntLib reports the extra 200 milliseconds while ThreadTimer reports pretty much unchanged results. &lt;br /&gt;&lt;br /&gt;So you see this ThreadTimer can be a reasonable solution for instrumentation in the scenario where you want to just focus on measuring your algorithm. However, as EntLib captures the start to end performance, which is what end user will experience, this solution shouldn’t replace that. Another caveat is that since there is no fixed relationship between a Win32 native thread and a managed thread, there is no guarantee that this solution will work for any CLR host.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-2050139715676539899?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/2050139715676539899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=2050139715676539899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2050139715676539899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2050139715676539899'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/10/net-code-instrumentation-independent-of.html' title='.NET Code Instrumentation That Is More Accurate?'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_UTl9xtmUmII/RyjnN3WXWNI/AAAAAAAAABE/DQ0KyLomvog/s72-c/results.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-960906841113328978</id><published>2007-10-26T21:11:00.000-04:00</published><updated>2007-10-26T23:41:07.296-04:00</updated><title type='text'>Debugging Without Source Code Using the Right Tools</title><content type='html'>When it comes to debugging without source code, there are two categories of debugging tools for this purpose:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;strong&gt;deassemblers/debuggers&lt;/strong&gt; such as IDA Pro, windbg, etc. If the running application is written in .NET, using windbg with SOS is really handy. This kind of tools are helpful if you need to track and understand program flow and execution state, such as stack and memory for subtle issues. These tools also tend to be favorites of crackers who want to crack/bypass license schemes.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; &lt;strong&gt;tracing tools&lt;/strong&gt;. There are those that trace network traffic such as &lt;a href="http://www.pocketsoap.com/tcpTrace/"&gt;tcpTrace&lt;/a&gt;, &lt;a href="http://www.ethereal.com/download.html"&gt;ethereal&lt;/a&gt;, &lt;a href="http://www.fiddlertool.com/fiddler/"&gt;Fiddler&lt;/a&gt; and of course &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=18b1d59d-f4d8-4213-8d17-2f6dde7d7aac&amp;displaylang=en"&gt;netmon&lt;/a&gt;. For monitoring process, file and registry activities on the OS itself, nothing beats the tools from Sysinternals, now Microsoft. The top two I recommend are &lt;a href="http://www.microsoft.com/technet/sysinternals/utilities/processmonitor.mspx"&gt;Process Monitor&lt;/a&gt; and &lt;a href="http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/ProcessExplorer.mspx"&gt;Process Explorer&lt;/a&gt;. The tools in this category are your friends in many debugging scenarios, especially during the initial stage of understanding the issues at hand. &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Here I will go over the debugging experience I just had this week with a legacy financial software, with a file-based database (no it's not Access or any of the Microsoft products). For anonymity reasons I will just not name this software.&lt;br /&gt;&lt;br /&gt;Anyway, the database file used by this software is installed on a network share so that the client on users desktops can all use it. You'd probably guess by now that locking has been a common issue but that's not what I plan to cover here. &lt;br /&gt;&lt;br /&gt;There is a custom built web application (classic ASP app hosted on IIS 5) in house that has to look up data from this database, which are files on the network share as I have mentioned. I was told that when the web app was being designed, the developer had found that although a VB Winform application could access the database through ODBC just fine, ASP application couldn't. Without investigating and further pursuit, a separate ETL program was developed to transfer the needed data to the SQL database used by the ASP application. The data fortunately doesn't change that much so this ETL program is run once every night. Suffice to say that such a moving piece has had its moments with IT operations although it is not the worst pet peeve.&lt;br /&gt;&lt;br /&gt;I came to know this application and the ETL program recently and when I asked why we can't query and cache the data from the file based database in the ASP app, the answer was that the ODBC connection didn't work in ASP although it worked in the ETL program written in VB. I was told that the developer hadn't really debugged the application but rather called the help desk of the software vendor, which was not at all helpful like most of the tier 1 support of those vendors. Intuition was telling me that this problem had to do with the security context, such as impersonation and logon sessions. Question I would ask right away when facing this type of issue: does the context in ASP have permission or other issue accessing this share? &lt;br /&gt;&lt;br /&gt;Determined to fix this problem and get rid of the ETL program, I started on the developer machine by configuring the IIS application with high isolation process model. This would cause a server COM+ application to be created - remember I had to deal with IIS 5! :-) Then I set the identity of the COM+ application to a domain service account that would have proper permission to the share, where the database files are located. With IIS directory security configured to do integrated windows authentication, the ASP app worked! But the production server has basic auth to allow users access this app from the Internet. Alas when basic auth was configured, it stopped working even when I typed in the same domain user name and password as the developer logged onto the desktop. As IIS 5 impersonates when either windows auth or basic auth is turned on, there must be a difference between the logged on session associated with the impersonation token in the two authentication types. Using a tool called TokenDump from Keith Brown, that I downloaded long time ago, I was able to confirm that 1) with windows auth, the ASP impersonation token is using the same logon session as the interactive user 2) with basic auth, the impersonation token, however, uses a different logon session than the desktop's although they are both for the same domain user account. This is probably by design as I conjecture that IIS may have done a LogonUser() call using the passed in user name and password, which would result in a different logon session. &lt;br /&gt;&lt;br /&gt;But why was a different logon session encountering the problem? I used the Process Monitor for two captures, one for each auth type. When I compared the two, I noticed that the basic auth one didn't even have any trace showing attempts to access the network share. Going further, I found out from the developer that during ODBC and client setup, the legacy financial software used a mapped drive to point to the network share, where the database files reside. This is where the answer to the puzzle lies. As you may know, mapped drive is tied to the logon session and therefore not global. Here is the &lt;a href="http://msdn2.microsoft.com/en-us/library/ms685143.aspx"&gt;official documentation&lt;/a&gt; on MSDN. We should avoid using it, especially for enterprise server applications.&lt;br /&gt;&lt;br /&gt;Finally I would need to change the drive letter to UNC. Alas the legacy software UI explicitly disallows it. Not wanting to give up at this point, I asked the developer to use Process Monitor to find out where (registry or configuration files) the software is keeping the data that contains the drive letter. Sure enough, we found a handful in the registry under the hives created by the software installation. I went ahead and manually changed all relevant registry settings. I then ran the ASP application with basic auth. Voila it worked! So the software must already be using the Win32 IO API that supports UNC, when its UI still disallows it. &lt;br /&gt;&lt;br /&gt;This experience shows you how handy the right tools can be in hairy situations such as this. I do caution you though that you need to be extra careful when changing registry settings like this as it may cause unexpected behavior and/or breach license agreement.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-960906841113328978?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/960906841113328978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=960906841113328978' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/960906841113328978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/960906841113328978'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/10/debugging-without-source-code-using.html' title='Debugging Without Source Code Using the Right Tools'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-794049094421218396</id><published>2007-10-05T23:13:00.000-04:00</published><updated>2008-12-08T15:58:52.426-05:00</updated><title type='text'>EntLib 3.1 Configuration - Part II</title><content type='html'>All EntLib versions come with source code, which is a great place to start digging around and understanding the framework. For configuration, since we are planning to write a custom configuration section, we will need to look at the Configuration and Configuration.Design sub namespaces as each block has them. For example, look for &lt;i&gt;Microsoft.Practices.EnterpriseLibrary.Logging.Configuration&lt;/i&gt; and &lt;i&gt;Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.Design&lt;/i&gt; in the Logging block. Given all the overwhelming number of types defined in those namespaces, it can seem daunting first to tackle this. &lt;br /&gt;&lt;br /&gt;It's actually not too difficult. I will illustrate the approach by just doing a custom configuration section with simple attributes, instead of a complicated configuration schema with nested hierarchies. &lt;br /&gt;&lt;br /&gt;Consider an example where we need to connect to an external web service, which needs a configuration section with URL, User ID and Password. &lt;br /&gt;&lt;br /&gt;1) First of all we will need to create a type that corresponds to the section in the configuration XML file. Note that this type extends the EntLib's SerializableConfigurationSection. All we need to do in this type is defining the section name and attribute names. And of course we need to define read/write properties for those attributes to read/persist from the configuration file.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 \par ?? \cf3 public\cf0 \cf3 class\cf0 \cf4 FooSettings\cf0 : \cf4 SerializableConfigurationSection\par ??\cf0 \{\par ?? \cf5 // Defines the section name \par ??\cf0 \cf3 public\cf0 \cf3 const\cf0 \cf3 string\cf0 SectionName = \cf6 "FooConfiguration"\cf0 ;\par ??\par ?? \cf5 // Defines attributes for the section\par ??\cf0 \cf3 private\cf0 \cf3 const\cf0 \cf3 string\cf0 URL_ATTR = \cf6 "url"\cf0 ;\par ?? \cf3 private\cf0 \cf3 const\cf0 \cf3 string\cf0 UID_ATTR = \cf6 "userID"\cf0 ;\par ?? \cf3 private\cf0 \cf3 const\cf0 \cf3 string\cf0 PASSWORD_ATTR = \cf6 "password"\cf0 ;\par ??\par ?? [\cf4 ConfigurationProperty\cf0 (URL_ATTR, IsRequired = \cf3 true\cf0 )]\par ?? \cf3 public\cf0 \cf3 string\cf0 Url\par ?? \{\par ?? \cf3 get\cf0 \{ \cf3 return\cf0 (\cf3 string\cf0 )\cf3 base\cf0 [URL_ATTR]; \}\par ?? \cf3 set\cf0 \{ \cf3 base\cf0 [URL_ATTR] = \cf3 value\cf0 ; \}\par ?? \}\par ??\par ?? [\cf4 ConfigurationProperty\cf0 (UID_ATTR, IsRequired = \cf3 true\cf0 )]\par ?? \cf3 public\cf0 \cf3 string\cf0 UID\par ?? \{\par ?? \cf3 get\cf0 \{ \cf3 return\cf0 (\cf3 string\cf0 )\cf3 base\cf0 [UID_ATTR]; \}\par ?? \cf3 set\cf0 \{ \cf3 base\cf0 [UID_ATTR] = \cf3 value\cf0 ; \}\par ?? \}\par ??\par ?? [\cf4 ConfigurationProperty\cf0 (PASSWORD_ATTR, IsRequired = \cf3 true\cf0 )]\par ?? \cf3 public\cf0 \cf3 string\cf0 Password\par ?? \{\par ?? \cf3 get\cf0 \{ \cf3 return\cf0 (\cf3 string\cf0 )\cf3 base\cf0 [PASSWORD_ATTR]; \}\par ?? \cf3 set\cf0 \{ \cf3 base\cf0 [PASSWORD_ATTR] = \cf3 value\cf0 ; \}\par ?? \}\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;SerializableConfigurationSection&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// Defines the section name &lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; SectionName = &lt;span style="color: #a31515;"&gt;"FooConfiguration"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// Defines attributes for the section&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; URL_ATTR = &lt;span style="color: #a31515;"&gt;"url"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; UID_ATTR = &lt;span style="color: #a31515;"&gt;"userID"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;const&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; PASSWORD_ATTR = &lt;span style="color: #a31515;"&gt;"password"&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ConfigurationProperty&lt;/span&gt;(URL_ATTR, IsRequired = &lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Url&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt;)&lt;span style="color: blue;"&gt;base&lt;/span&gt;[URL_ATTR]; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { &lt;span style="color: blue;"&gt;base&lt;/span&gt;[URL_ATTR] = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ConfigurationProperty&lt;/span&gt;(UID_ATTR, IsRequired = &lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; UID&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt;)&lt;span style="color: blue;"&gt;base&lt;/span&gt;[UID_ATTR]; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { &lt;span style="color: blue;"&gt;base&lt;/span&gt;[UID_ATTR] = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ConfigurationProperty&lt;/span&gt;(PASSWORD_ATTR, IsRequired = &lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Password&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: blue;"&gt;string&lt;/span&gt;)&lt;span style="color: blue;"&gt;base&lt;/span&gt;[PASSWORD_ATTR]; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { &lt;span style="color: blue;"&gt;base&lt;/span&gt;[PASSWORD_ATTR] = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;2) Secondly, we will need to create a type that represents the node on the EntLib console. This type extends the EntLib's ConfigurationSectionNode. Note that It's very similar to the FooSettings type defined above, in that there are three read/write properties that correspond to the Url, UID and Password. &lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 \par ?? [\cf3 Image\cf0 (\cf4 typeof\cf0 (\cf3 FooNode\cf0 ), \cf5 "ConfigNode_d.bmp"\cf0 )]\par ?? [\cf3 SelectedImage\cf0 (\cf4 typeof\cf0 (\cf3 FooNode\cf0 ), \cf5 "ConfigNode_h.bmp"\cf0 )]\par ?? \cf4 public\cf0 \cf4 class\cf0 \cf3 FooNode\cf0 : \cf3 ConfigurationSectionNode\par ??\cf0 \{\par ?? \cf4 private\cf0 \cf4 string\cf0 _url;\par ?? \cf4 private\cf0 \cf4 string\cf0 _uid;\par ?? \cf4 private\cf0 \cf4 string\cf0 _password;\par ??\par ?? \cf4 public\cf0 FooNode()\par ?? : \cf4 base\cf0 (\cf5 "Foo Configuration"\cf0 )\par ?? \{\}\par ??\par ?? [\cf3 ReadOnly\cf0 (\cf4 true\cf0 )]\par ?? \cf4 public\cf0 \cf4 override\cf0 \cf4 string\cf0 Name\par ?? \{\par ?? \cf4 get\cf0 \{ \cf4 return\cf0 \cf4 base\cf0 .Name; \}\par ?? \}\par ??\par ?? [\cf3 Required\cf0 ()]\par ?? [\cf3 Browsable\cf0 (\cf4 true\cf0 )]\par ?? \cf4 public\cf0 \cf4 string\cf0 Url\par ?? \{\par ?? \cf4 get\cf0 \{ \cf4 return\cf0 _url; \}\par ?? \cf4 set\cf0 \{ _url = \cf4 value\cf0 ; \}\par ?? \}\par ??\par ?? [\cf3 Required\cf0 ()]\par ?? [\cf3 Browsable\cf0 (\cf4 true\cf0 )]\par ?? \cf4 public\cf0 \cf4 string\cf0 UID\par ?? \{\par ?? \cf4 get\cf0 \{ \cf4 return\cf0 _uid; \}\par ?? \cf4 set\cf0 \{ _uid = \cf4 value\cf0 ; \}\par ?? \}\par ??\par ?? [\cf3 Required\cf0 ()]\par ?? [\cf3 Browsable\cf0 (\cf4 true\cf0 )]\par ?? \cf4 public\cf0 \cf4 string\cf0 Password\par ?? \{\par ?? \cf4 get\cf0 \{ \cf4 return\cf0 _password; \}\par ?? \cf4 set\cf0 \{ _password = \cf4 value\cf0 ; \}\par ?? \}\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Image&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;), &lt;span style="color: #a31515;"&gt;"ConfigNode_d.bmp"&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;SelectedImage&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;), &lt;span style="color: #a31515;"&gt;"ConfigNode_h.bmp"&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;ConfigurationSectionNode&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; _url;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; _uid;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; _password;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; FooNode()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Foo Configuration"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {}&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ReadOnly&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Name&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;base&lt;/span&gt;.Name; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Required&lt;/span&gt;()]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Url&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _url; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { _url = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Required&lt;/span&gt;()]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; UID&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _uid; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { _uid = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Required&lt;/span&gt;()]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;Browsable&lt;/span&gt;(&lt;span style="color: blue;"&gt;true&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; Password&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt; { &lt;span style="color: blue;"&gt;return&lt;/span&gt; _password; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;set&lt;/span&gt; { _password = &lt;span style="color: blue;"&gt;value&lt;/span&gt;; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;What is interesting here is that this class as well as its propeties have some attributes attached to them. The SelectedImage() and Image() attributes simply define the bitmap images shown when the node is in selected or deselected state. The two bitmap images are embedded resources within the same VS.NET project. The Required() and Browsable() attributes at the properties are telling the EntLib UI that those properties are required and browsable(visible) on the UI. If you don't put a value for the property, a UI validation error will occur when you try to save the configuration. &lt;br /&gt;&lt;br /&gt;3) So far so good. Now we need to have a way to let EntLib UI become aware of our custom configuration node. Here is where we need to extend EntLib's ConfigurationDesignManager to have our FooConifgurationDesignManager. &lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;\red0\green128\blue0;}??\fs20 \par ?? \cf3 public\cf0 \cf3 class\cf0 \cf4 FooConfigurationDesignManager\cf0 : \cf4 ConfigurationDesignManager\par ??\cf0 \{\par ?? \cf3 public\cf0 \cf3 override\cf0 \cf3 void\cf0 Register(\cf4 IServiceProvider\cf0 serviceProvider)\par ?? \{\par ?? (\cf3 new\cf0 \cf4 FooCommandRegistrar\cf0 (serviceProvider)).Register();\par ?? \}\par ??\par ?? \cf3 protected\cf0 \cf3 override\cf0 \cf3 void\cf0 OpenCore(\cf4 IServiceProvider\cf0 serviceProvider, \par ?? \cf4 ConfigurationApplicationNode\cf0 rootNode, \par ?? \cf4 ConfigurationSection\cf0 section)\par ?? \{\par ?? \cf3 if\cf0 (section != \cf3 null\cf0 )\par ?? \{\par ?? \cf4 FooSettings\cf0 settings = section \cf3 as\cf0 \cf4 FooSettings\cf0 ;\par ?? \cf4 Debug\cf0 .Assert(settings != \cf3 null\cf0 , \par ?? \cf5 "Check config section - not of the FooSettings type"\cf0 );\par ??\par ?? \cf4 FooNode\cf0 node = \cf3 new\cf0 \cf4 FooNode\cf0 ();\par ?? \cf6 // sync data on UI and in config file\par ??\cf0 node.Url = settings.Url;\par ?? node.UID = settings.UID;\par ?? node.Password = settings.Password;\par ??\par ?? SetProtectionProvider(section, node);\par ??\par ?? rootNode.AddNode(node);\par ?? \}\par ?? \}\par ??\par ?? \cf3 protected\cf0 \cf3 override\cf0 \cf4 ConfigurationSectionInfo\cf0 GetConfigurationSectionInfo(\par ?? \cf4 IServiceProvider\cf0 serviceProvider)\par ?? \{\par ?? \cf4 ConfigurationNode\cf0 rootNode = \cf4 ServiceHelper\cf0 .GetCurrentRootNode(serviceProvider);\par ?? \cf4 FooNode\cf0 node = \cf3 null\cf0 ;\par ?? \cf3 if\cf0 (rootNode != \cf3 null\cf0 )\par ?? node = (\cf4 FooNode\cf0 )rootNode.Hierarchy.FindNodeByType(rootNode, \cf3 typeof\cf0 (\cf4 FooNode\cf0 ));\par ??\par ?? \cf4 FooSettings\cf0 settings = \cf3 null\cf0 ;\par ?? \cf3 if\cf0 (node == \cf3 null\cf0 )\par ?? \{\par ?? settings = \cf3 null\cf0 ;\par ?? \}\par ?? \cf3 else\par ??\cf0 \{\par ?? settings = \cf3 new\cf0 \cf4 FooSettings\cf0 ();\par ??\par ?? \cf6 // sync data on UI and in config file\par ??\cf0 settings.Url = node.Url;\par ?? settings.UID = node.UID;\par ?? settings.Password = node.Password;\par ?? \}\par ?? \cf3 string\cf0 protectionProviderName = GetProtectionProviderName(node);\par ??\par ?? \cf3 return\cf0 \cf3 new\cf0 \cf4 ConfigurationSectionInfo\cf0 (node, \par ?? settings, \cf4 FooSettings\cf0 .SectionName, protectionProviderName);\par ?? \}\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooConfigurationDesignManager&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;ConfigurationDesignManager&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Register(&lt;span style="color: #2b91af;"&gt;IServiceProvider&lt;/span&gt; serviceProvider)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; (&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooCommandRegistrar&lt;/span&gt;(serviceProvider)).Register();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; OpenCore(&lt;span style="color: #2b91af;"&gt;IServiceProvider&lt;/span&gt; serviceProvider, &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ConfigurationApplicationNode&lt;/span&gt; rootNode, &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ConfigurationSection&lt;/span&gt; section)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (section != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt; settings = section &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.Assert(settings != &lt;span style="color: blue;"&gt;null&lt;/span&gt;, &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #a31515;"&gt;"Check config section - not of the FooSettings type"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt; node = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// sync data on UI and in config file&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; node.Url = settings.Url;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; node.UID = settings.UID;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; node.Password = settings.Password;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; SetProtectionProvider(section, node);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; rootNode.AddNode(node);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ConfigurationSectionInfo&lt;/span&gt; GetConfigurationSectionInfo(&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;IServiceProvider&lt;/span&gt; serviceProvider)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ConfigurationNode&lt;/span&gt; rootNode = &lt;span style="color: #2b91af;"&gt;ServiceHelper&lt;/span&gt;.GetCurrentRootNode(serviceProvider);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt; node = &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (rootNode != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; node = (&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;)rootNode.Hierarchy.FindNodeByType(rootNode, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt; settings = &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (node == &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings = &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// sync data on UI and in config file&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings.Url = node.Url;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings.UID = node.UID;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings.Password = node.Password;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; protectionProviderName = GetProtectionProviderName(node);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ConfigurationSectionInfo&lt;/span&gt;(node, &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; settings, &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt;.SectionName, protectionProviderName);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;The two overridden methods OpenCore() and GetConfigurationSectionInfo() are the hooks for EntLib UI to load and save from/to configuration file. You will notice the code in the two methods to sync up data held by FooNode and FooSettings - just remember that FooNode represents the UI view and FooSettings represents the configuration file. The remaining function, Register(), is the hook for us to provide the command in the EntLib context menu. Here we will use the following CommandRegistrar class to add the command "Foo Configuration":&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \par ?? \cf3 public\cf0 \cf3 class\cf0 \cf4 FooCommandRegistrar\cf0 : \cf4 CommandRegistrar\par ??\cf0 \{\par ?? \cf3 public\cf0 FooCommandRegistrar(\cf4 IServiceProvider\cf0 serviceProvider)\par ?? : \cf3 base\cf0 (serviceProvider)\par ?? \{\par ?? \}\par ??\par ?? \cf3 public\cf0 \cf3 override\cf0 \cf3 void\cf0 Register()\par ?? \{\par ?? \cf4 ConfigurationUICommand\cf0 cmd = \cf4 ConfigurationUICommand\cf0 .CreateSingleUICommand(ServiceProvider,\par ?? \cf5 "Foo Configuration"\cf0 ,\par ?? \cf5 "Foo Configuration"\cf0 ,\par ?? \cf3 new\cf0 \cf4 AddChildNodeCommand\cf0 (ServiceProvider, \cf3 typeof\cf0 (\cf4 FooNode\cf0 )),\par ?? \cf3 typeof\cf0 (\cf4 FooNode\cf0 ));\par ?? AddUICommand(cmd, \cf3 typeof\cf0 (\cf4 ConfigurationApplicationNode\cf0 ));\par ?? \}\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooCommandRegistrar&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;CommandRegistrar&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; FooCommandRegistrar(&lt;span style="color: #2b91af;"&gt;IServiceProvider&lt;/span&gt; serviceProvider)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(serviceProvider)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Register()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ConfigurationUICommand&lt;/span&gt; cmd = &lt;span style="color: #2b91af;"&gt;ConfigurationUICommand&lt;/span&gt;.CreateSingleUICommand(ServiceProvider,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #a31515;"&gt;"Foo Configuration"&lt;/span&gt;,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #a31515;"&gt;"Foo Configuration"&lt;/span&gt;,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;AddChildNodeCommand&lt;/span&gt;(ServiceProvider, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;)),&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooNode&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; AddUICommand(cmd, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;ConfigurationApplicationNode&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;With all these in place, we need to add the following to the AssemblyInfo.cs file:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 [assembly: \cf3 ConfigurationDesignManager\cf0 (\cf4 typeof\cf0 (\cf3 FooConfigurationDesignManager\cf0 ))]}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;[assembly: &lt;span style="color: #2b91af;"&gt;ConfigurationDesignManager&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FooConfigurationDesignManager&lt;/span&gt;))]&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;EntLib UI, when being loaded, will use reflection API to query the assemblies in its folder ("c:\Program Files\Microsoft Enterprise Library 3.1 - May 2007\Bin\" in my case) and find out all the ConfigurationDesignManager types through this assembly attribute. So after the project is compiled, we need to drop the dll into the same folder as the EntLibConfig.exe file.&lt;br /&gt;&lt;br /&gt;Whew, now we can see how this works in the EntLib UI. The following figure shows that the "Foo Configuration" command is in the context menu.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_UTl9xtmUmII/RwcQwHkDWZI/AAAAAAAAAA0/5hbAuJumQSs/s1600-h/FooCommand.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_UTl9xtmUmII/RwcQwHkDWZI/AAAAAAAAAA0/5hbAuJumQSs/s320/FooCommand.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5118077920379885970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One cool feature of EntLib 3.1 configuration is that it works integrated with VS.NET 2005 IDE. The following figure shows just that. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_UTl9xtmUmII/RwcRS3kDWaI/AAAAAAAAAA8/egrpskFlxIE/s1600-h/override.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_UTl9xtmUmII/RwcRS3kDWaI/AAAAAAAAAA8/egrpskFlxIE/s320/override.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5118078517380340130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You see that a Foo Configuration is created besides the standard logging application block. In the properties window on the lower-right corner, the values for Url, UID and Password are set. I have also defined two environments, QA and Prod. For QA, override is chosen for the foo configuration and you can also see that it's a different set of values. Note that you can encrypt this section with the standard providers. If you have gone through the code I listed above, you will realize that these two functions are provided by EntLib without us writing any code!&lt;br /&gt;&lt;br /&gt;Here is what the app.config file looks like (I have ommitted the logging section for clarity):&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red163\green21\blue21;\red255\green0\blue0;\red0\green0\blue0;}??\fs20 \cf1 &amp;lt;?\cf3 xml\cf1 \cf4 version\cf1 =\cf0 "\cf1 1.0\cf0 "\cf1 \cf4 encoding\cf1 =\cf0 "\cf1 utf-8\cf0 "\cf1 ?&amp;gt;\par ??&amp;lt;\cf3 configuration\cf1 &amp;gt;\par ?? &amp;lt;\cf3 configSections\cf1 &amp;gt;\par ?? &amp;lt;\cf3 section\cf1 \cf4 name\cf1 =\cf0 "\cf1 FooConfiguration\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 CustomEntLibConfig.FooSettings, CustomEntLibConfig, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;/\cf3 configSections\cf1 &amp;gt;\par ?? &amp;lt;\cf3 FooConfiguration\cf1 \cf4 url\cf1 =\cf0 "\cf1 http://foo.com/test.asmx\cf0 "\cf1 \cf4 userID\cf1 =\cf0 "\cf1 test\cf0 "\par ??\cf1 \cf4 password\cf1 =\cf0 "\cf1 test123\cf0 "\cf1 /&amp;gt;\par ??&amp;lt;/\cf3 configuration\cf1 &amp;gt;}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515;"&gt;xml&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;version&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;1.0&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;encoding&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;utf-8&lt;/span&gt;"&lt;span style="color: blue;"&gt;?&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configuration&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configSections&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;section&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;FooConfiguration&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;CustomEntLibConfig.FooSettings, CustomEntLibConfig, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configSections&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;FooConfiguration&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;url&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;http://foo.com/test.asmx&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;userID&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;test&lt;/span&gt;"&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span style="color: red;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;test123&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configuration&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In case you're curious, here is what the QA delta file looks like.&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red163\green21\blue21;\red255\green0\blue0;\red0\green0\blue0;}??\fs20 \cf1 &amp;lt;\cf3 configuration\cf1 &amp;gt;\par ?? &amp;lt;\cf3 configSections\cf1 &amp;gt;\par ?? &amp;lt;\cf3 section\cf1 \cf4 name\cf1 =\cf0 "\cf1 EnvironmentMergeData\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides.Configuration.EnvironmentMergeSection, Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;/\cf3 configSections\cf1 &amp;gt;\par ?? &amp;lt;\cf3 EnvironmentMergeData\cf1 \cf4 environmentName\cf1 =\cf0 "\cf1 QA\cf0 "\cf1 \cf4 environmentDeltaFile\cf1 =\cf0 "\cf1 app.qa\cf0 "\cf1 &amp;gt;\par ?? &amp;lt;\cf3 mergeElements\cf1 &amp;gt;\par ?? &amp;lt;\cf3 override\cf1 \cf4 nodePath\cf1 =\cf0 "\cf1 /Foo Configuration\cf0 "\cf1 \cf4 overrideProperties\cf1 =\cf0 "\cf1 true\cf0 "\cf1 &amp;gt;\par ?? &amp;lt;\cf3 overridddenProperties\cf1 &amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 Password\cf0 "\cf1 \cf4 value\cf1 =\cf0 "\cf1 qa123\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 UID\cf0 "\cf1 \cf4 value\cf1 =\cf0 "\cf1 qa\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 Url\cf0 "\cf1 \cf4 value\cf1 =\cf0 "\cf1 http://qa.foo.com/test.asmx\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;/\cf3 overridddenProperties\cf1 &amp;gt;\par ?? &amp;lt;/\cf3 override\cf1 &amp;gt;\par ?? &amp;lt;/\cf3 mergeElements\cf1 &amp;gt;\par ?? &amp;lt;/\cf3 EnvironmentMergeData\cf1 &amp;gt;\par ??&amp;lt;/\cf3 configuration\cf1 &amp;gt;}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configuration&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configSections&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;section&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;EnvironmentMergeData&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides.Configuration.EnvironmentMergeSection, Microsoft.Practices.EnterpriseLibrary.Configuration.EnvironmentalOverrides, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configSections&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;EnvironmentMergeData&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;environmentName&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;QA&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;environmentDeltaFile&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;app.qa&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;mergeElements&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;override&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;nodePath&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;/Foo Configuration&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;overrideProperties&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;true&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;overridddenProperties&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Password&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;qa123&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;UID&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;qa&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Url&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;value&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;http://qa.foo.com/test.asmx&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;overridddenProperties&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;override&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;mergeElements&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;EnvironmentMergeData&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;configuration&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;4) To use the configuration programmatically, here is a code snippet:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 \par ?? \cf3 FooSettings\cf0 node = \cf3 ConfigurationManager\cf0 .GetSection(\cf3 FooSettings\cf0 .SectionName) \cf4 as\cf0 \cf3 FooSettings\cf0 ;\par ??\par ?? \cf4 if\cf0 (node != \cf4 null\cf0 )\par ?? \cf3 Console\cf0 .WriteLine(\cf5 "Url: \{0\}, UID: \{1\}, Password: \{2\}"\cf0 , \par ?? node.Url, node.UID, node.Password);\par ?? \cf4 else\par ??\cf0 \cf3 Console\cf0 .WriteLine(\cf5 "Custom section not found"\cf0 );\par ??\par ?? \cf3 Console\cf0 .ReadLine();}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt; node = &lt;span style="color: #2b91af;"&gt;ConfigurationManager&lt;/span&gt;.GetSection(&lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt;.SectionName) &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FooSettings&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (node != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Url: {0}, UID: {1}, Password: {2}"&lt;/span&gt;, &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; node.Url, node.UID, node.Password);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Custom section not found"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.ReadLine();&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I hope you find this helpful. Email me at hugh dot ang @ gmail dot com if you need the source code for the sample I have used here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-794049094421218396?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/794049094421218396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=794049094421218396' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/794049094421218396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/794049094421218396'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/10/entlib-31-configuration-part-ii.html' title='EntLib 3.1 Configuration - Part II'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_UTl9xtmUmII/RwcQwHkDWZI/AAAAAAAAAA0/5hbAuJumQSs/s72-c/FooCommand.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-5588902975452784931</id><published>2007-09-23T21:36:00.000-04:00</published><updated>2007-09-23T22:51:37.762-04:00</updated><title type='text'>EntLib 3.1 Configuration - Part I</title><content type='html'>Recently, when an application that my team had built was deployed to production, an external web service's URL was forgotten to have been set from its test site's to the production site's. So the transactions thought to have completed actually never happened. This caused some interruptions to the business.&lt;br /&gt;&lt;br /&gt;We had to rush this deployment one month ahead of schedule because of a business issue. While the rush was partly to blame, I think since the application uses Enterprise Library 3.1 for quite a few of its blocks, one feature could have helped us avoid this hiccup. &lt;br /&gt;&lt;br /&gt;Since 3.0, Enterprise Library introduced the environment overrides for configuration. &lt;a href="http://bloggingabout.net/blogs/olaf/archive/2007/02/18/environmental-overrides-made-it-into-entlib-v3.aspx"&gt;This blog&lt;/a&gt; had a good overview of this feature. In a nutshell, the configuration files for the most part are the same between different environments, DEV, Staging, QA and Prod, etc. There are only a few minor things that might be different, such as database connection string, logging threshold, etc. This new Enterprise Library configuration feature saves the differentials in delta config files. And the merge function overrides the original (usually DEV) application config file with the delta to produce the config file for the target environment. &lt;br /&gt;&lt;br /&gt;Of course, this feature works out of box for any configuration setting if it can be done through the Enterprise Library configuration console tool, which is also available from Visual Studio .NET 2005 IDE. The list includes the "Application Settings", "Caching", "Logging", etc. "Application Settings" is great for independent name/value pairs but for a set of values and more complicated configuration data schema, a separate configuration section is required. In the next blog, I will show how to create custom EntLib 3.1 configuration sections so that not only can we leverage the environment overrides, but also we can easily use the EntLib config UI to protect sensitive config data with cryptography.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-5588902975452784931?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/5588902975452784931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=5588902975452784931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5588902975452784931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/5588902975452784931'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/09/entlib-31-configuration-part-i.html' title='EntLib 3.1 Configuration - Part I'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6119883797296212813</id><published>2007-08-21T22:22:00.000-04:00</published><updated>2007-08-21T22:44:59.435-04:00</updated><title type='text'>Sync Active Item in VS.NET Solution Explorer</title><content type='html'>Opening a big VS.NET solution and having a lot of source files can be very disorienting. I've found it especially so when I am tracking deep in the types that are referred by other types, which are referred by others, and so on. And it's pretty difficult to find out which Visual Studio project the type is defined in. I was so desperate that I almost wrote an addin to help me synchronizing the active source file in the solution explorer window. Alas when I was almost done, I found that Visual Studio 2005 already offers such function. To use it, just follow these steps:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Go to "Tools" menu, click "Options"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Under "Projects and Solutions", click "General"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Check the "Track Active Item in Solution Explorer" checkbox on the right side&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;That is it! Now no matter which source file you end up burying your head into, the solution explorer window always selects and scrolls to that file for you. I guess my lesson learned is that I should always look hard first because Visual Studio may just have that built in already. And it was also interesting to learn the VS.NET automation APIs that have to do with finding the solution item and manipulating the solution explorer window.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6119883797296212813?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6119883797296212813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6119883797296212813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6119883797296212813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6119883797296212813'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/08/sync-active-item-in-vsnet-solution.html' title='Sync Active Item in VS.NET Solution Explorer'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-4762772941500134859</id><published>2007-08-09T12:19:00.000-04:00</published><updated>2007-08-20T13:18:12.165-04:00</updated><title type='text'>Commoditization of Business Applications</title><content type='html'>I have been quiet here for the last couple of months. The main reason is that I stepped into the position of vice president of app dev department and became heavily involved in organization management as well as project management at a client. I am also busy collaborating with a colleague on a WCF article that we hope to publish soon.&lt;br /&gt;&lt;br /&gt;Being in this particular management position has given me a different perspective on application development. I have been involved in a couple of projects where "buy vs. build" decision was made. Dollars and benefits (ROI) always took precedence over anything else. And it seems obvious that the industry trend is going towards the direction where building everything from scratch is less favored and we see needs for product knowledge and configuration management skills. You can see that with the slew of products like BizTalk, MOSS, Commerce Server 2007, Dynamics, etc. coming out of Microsoft assembly line in a pace like never before. &lt;br /&gt;&lt;br /&gt;The trade-off for the product knowledge will be fundamentals and technical skills. An unfortunate effect of this will be that for certain technical issues, the root problems don't get resolved but rather awkward workarounds are contrived at the product level, which could result in convoluted business processes for end users.&lt;br /&gt;&lt;br /&gt;For developers, this may not be good news as the creativity aspect (the fun part) of application development is being gradually taken away and it is a big challenge to keep on top of the ever growing list of products.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-4762772941500134859?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/4762772941500134859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=4762772941500134859' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4762772941500134859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4762772941500134859'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/08/commoditization-of-business.html' title='Commoditization of Business Applications'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6640013347691234046</id><published>2007-05-25T14:08:00.000-04:00</published><updated>2007-05-25T14:14:06.024-04:00</updated><title type='text'>EntLib 3.1 Is Coming</title><content type='html'>It looks like that p&amp;p is addressing the &lt;a href="http://tigerang.blogspot.com/2007/02/policy-injection-app-block-of-entlib-30.html"&gt;implementation issue of interception for Policy Injection&lt;/a&gt; by making the interception mechanism configurable. Here is the &lt;a href="http://blogs.msdn.com/tomholl/archive/2007/05/21/enterprise-library-3-1-is-coming.aspx"&gt;blog&lt;/a&gt; that talks about this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6640013347691234046?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6640013347691234046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6640013347691234046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6640013347691234046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6640013347691234046'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/05/entlib-31-is-coming.html' title='EntLib 3.1 Is Coming'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-7958375204227359744</id><published>2007-05-15T12:50:00.000-04:00</published><updated>2007-05-15T13:54:49.824-04:00</updated><title type='text'>A Simple Design Pattern for Extensible Enumeration Types</title><content type='html'>In .NET, custom enum types are of value type so they cannot be extended. This can create an issue if you want to include an enum in your framework API, where you wish that the enum could be extended by the applications that are using the framework. After examining the implementation of System.Enum, I came up with the following implementation. I haven't googled thoroughly yet so please no flames if someone has done something similar :-) Also note the code posted is POC quality and I am looking to improve it. &lt;br /&gt;&lt;br /&gt;First I will start off with a base class EnumEx&lt;T&gt;. I am using generics to allow different underlying enum types:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green0\blue255;\red0\green128\blue0;}??\fs20 \par ?? [\cf3 Serializable\cf0 ()]\par ?? \cf4 public\cf0 \cf4 abstract\cf0 \cf4 class\cf0 \cf3 EnumEx\cf0 &amp;lt;T&amp;gt; \par ?? \cf4 where\cf0 T : \cf4 struct\par ??\cf0 \{\par ?? \cf5 // holds the actual value\par ??\cf0 \cf4 protected\cf0 T _t;\par ??\par ?? \cf5 // default constructor\par ??\cf0 \cf4 protected\cf0 EnumEx()\par ?? \{\par ?? _t = \cf4 default\cf0 (T);\par ?? \}\par ??\par ?? \cf5 // constructor that takes the enum value\par ??\cf0 \cf4 protected\cf0 EnumEx(T t)\par ?? \{\par ?? _t = t;\par ?? \}\par ??\par ?? \cf5 // performs an implicit conversion to the underlying value\par ??\cf0 \cf4 public\cf0 \cf4 static\cf0 \cf4 implicit\cf0 \cf4 operator\cf0 T(\cf3 EnumEx\cf0 &amp;lt;T&amp;gt; obj)\par ?? \{\par ?? \cf4 return\cf0 obj._t;\par ?? \}\par ??\par ?? \cf5 // parses a string to the specified type, returns null if no string match is defined\par ??\cf0 \cf5 // this is a case-sensitive version\par ??\cf0 \cf4 public\cf0 \cf4 static\cf0 \cf4 object\cf0 Parse(\cf4 string\cf0 s, \cf3 Type\cf0 type)\par ?? \{\par ?? \cf3 FieldInfo\cf0 [] fis = type.GetFields(\cf3 BindingFlags\cf0 .Static | \cf3 BindingFlags\cf0 .Public);\par ?? \cf4 foreach\cf0 (\cf3 FieldInfo\cf0 fi \cf4 in\cf0 fis)\par ?? \{\par ?? \cf4 if\cf0 (s.Equals(fi.Name))\par ?? \{\par ?? \cf4 object\cf0 obj = fi.GetValue(\cf4 null\cf0 );\par ?? \cf4 return\cf0 obj;\par ?? \}\par ?? \}\par ??\par ?? \cf4 return\cf0 \cf4 null\cf0 ;\par ?? \}\par ??\par ?? \cf5 // System.Object overrides\par ??\cf0 \cf4 public\cf0 \cf4 override\cf0 \cf4 int\cf0 GetHashCode()\par ?? \{\par ?? \cf4 return\cf0 _t.GetHashCode();\par ?? \}\par ??\par ?? \cf4 public\cf0 \cf4 override\cf0 \cf4 string\cf0 ToString()\par ?? \{\par ?? \cf3 FieldInfo\cf0 [] fis = \cf4 this\cf0 .GetType().GetFields(\cf3 BindingFlags\cf0 .Static | \cf3 BindingFlags\cf0 .Public);\par ?? \cf4 foreach\cf0 (\cf3 FieldInfo\cf0 fi \cf4 in\cf0 fis)\par ?? \{\par ?? \cf4 object\cf0 obj = fi.GetValue(\cf4 this\cf0 );\par ?? T t = ((\cf3 EnumEx\cf0 &amp;lt;T&amp;gt;)obj)._t;\par ?? \cf4 if\cf0 (_t.Equals(t))\par ?? \cf4 return\cf0 fi.Name;\par ?? \}\par ??\par ?? \cf4 return\cf0 \cf4 string\cf0 .Empty;\par ?? \}\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Serializable&lt;/span&gt;()]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;abstract&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;EnumEx&lt;/span&gt;&amp;lt;T&amp;gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;where&lt;/span&gt; T : &lt;span style="color: blue;"&gt;struct&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// holds the actual value&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; T _t;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// default constructor&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; EnumEx()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _t = &lt;span style="color: blue;"&gt;default&lt;/span&gt;(T);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// constructor that takes the enum value&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; EnumEx(T t)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _t = t;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// performs an implicit conversion to the underlying value&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;implicit&lt;/span&gt; &lt;span style="color: blue;"&gt;operator&lt;/span&gt; T(&lt;span style="color: #2b91af;"&gt;EnumEx&lt;/span&gt;&amp;lt;T&amp;gt; obj)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; obj._t;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// parses a string to the specified type, returns null if no string match is defined&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// this is a case-sensitive version&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; Parse(&lt;span style="color: blue;"&gt;string&lt;/span&gt; s, &lt;span style="color: #2b91af;"&gt;Type&lt;/span&gt; type)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FieldInfo&lt;/span&gt;[] fis = type.GetFields(&lt;span style="color: #2b91af;"&gt;BindingFlags&lt;/span&gt;.Static | &lt;span style="color: #2b91af;"&gt;BindingFlags&lt;/span&gt;.Public);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;FieldInfo&lt;/span&gt; fi &lt;span style="color: blue;"&gt;in&lt;/span&gt; fis)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (s.Equals(fi.Name))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;object&lt;/span&gt; obj = fi.GetValue(&lt;span style="color: blue;"&gt;null&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; obj;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// System.Object overrides&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; GetHashCode()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; _t.GetHashCode();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; ToString()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FieldInfo&lt;/span&gt;[] fis = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.GetType().GetFields(&lt;span style="color: #2b91af;"&gt;BindingFlags&lt;/span&gt;.Static | &lt;span style="color: #2b91af;"&gt;BindingFlags&lt;/span&gt;.Public);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;FieldInfo&lt;/span&gt; fi &lt;span style="color: blue;"&gt;in&lt;/span&gt; fis)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;object&lt;/span&gt; obj = fi.GetValue(&lt;span style="color: blue;"&gt;this&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; T t = ((&lt;span style="color: #2b91af;"&gt;EnumEx&lt;/span&gt;&amp;lt;T&amp;gt;)obj)._t;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (_t.Equals(t))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; fi.Name;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;.Empty;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;This can be how a framework enum is defined:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \par ?? \cf3 public\cf0 \cf3 class\cf0 \cf4 LogType\cf0 : \cf4 EnumEx\cf0 &amp;lt;\cf3 int\cf0 &amp;gt;\par ?? \{\par ?? \cf3 protected\cf0 LogType() \par ?? : \cf3 base\cf0 ()\par ?? \{\par ?? \}\par ??\par ?? \cf3 protected\cf0 LogType(\cf3 int\cf0 value)\par ?? : \cf3 base\cf0 (value)\par ?? \{\par ?? \}\par ??\par ?? \cf3 public\cf0 \cf3 static\cf0 \cf3 implicit\cf0 \cf3 operator\cf0 \cf4 LogType\cf0 (\cf3 int\cf0 i)\par ?? \{\par ?? \cf3 return\cf0 \cf3 new\cf0 \cf4 LogType\cf0 (i);\par ?? \}\par ??\par ?? \cf3 public\cf0 \cf3 static\cf0 \cf4 LogType\cf0 Info = 1;\par ?? \cf3 public\cf0 \cf3 static\cf0 \cf4 LogType\cf0 Warning = 2;\par ?? \cf3 public\cf0 \cf3 static\cf0 \cf4 LogType\cf0 Error = 3;\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;EnumEx&lt;/span&gt;&amp;lt;&lt;span style="color: blue;"&gt;int&lt;/span&gt;&amp;gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; LogType() &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; LogType(&lt;span style="color: blue;"&gt;int&lt;/span&gt; value)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(value)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;implicit&lt;/span&gt; &lt;span style="color: blue;"&gt;operator&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;(&lt;span style="color: blue;"&gt;int&lt;/span&gt; i)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;(i);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; Info = 1;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; Warning = 2;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; Error = 3;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And if the application wishes to extend the enum:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \par ?? \cf3 public\cf0 \cf3 class\cf0 \cf4 LogTypeEx\cf0 : \cf4 LogType\par ??\cf0 \{\par ?? \cf3 public\cf0 \cf3 static\cf0 \cf4 LogType\cf0 Verbose = 4;\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogTypeEx&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; Verbose = 4;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If I write the following test code:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red163\green21\blue21;\red0\green0\blue255;}??\fs20 \par ?? \cf3 LogType\cf0 logType = \cf3 LogType\cf0 .Error;\par ?? \cf3 Console\cf0 .WriteLine(logType.ToString());\par ??\par ?? \cf3 LogType\cf0 logType2 = \cf3 LogType\cf0 .Parse(\cf4 "Warning"\cf0 , \cf5 typeof\cf0 (\cf3 LogType\cf0 )) \cf5 as\cf0 \cf3 LogType\cf0 ;\par ?? \cf5 if\cf0 (logType2.Equals(\cf3 LogType\cf0 .Warning))\par ?? \cf3 Console\cf0 .WriteLine(\cf4 "Parsing succeeds"\cf0 );\par ??\par ?? \cf5 int\cf0 i = logType2;\par ?? \cf5 if\cf0 (i == 2)\par ?? \cf3 Console\cf0 .WriteLine(\cf4 "Implicit conversion to underlying type succeeds"\cf0 );}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; logType = &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;.Error;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(logType.ToString());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt; logType2 = &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;.Parse(&lt;span style="color: #a31515;"&gt;"Warning"&lt;/span&gt;, &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;)) &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (logType2.Equals(&lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;.Warning))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Parsing succeeds"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;int&lt;/span&gt; i = logType2;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (i == 2)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Implicit conversion to underlying type succeeds"&lt;/span&gt;);&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I will get the following result in the console:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;Error&lt;br /&gt;Parsing succeeds&lt;br /&gt;Implicit conversion to underlying type succeeds&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;So you see that this extensible enum type is pretty straightforward to use, extending the enum is very easy and it achieves pretty much what the native enum type has to offer. One thing left to be desired though is an issue using switch statement with C# compiler. Only the following works:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \par ?? \cf3 switch\cf0 (logType2)\par ?? \{\par ?? \cf3 case\cf0 2:\par ?? \cf4 Console\cf0 .WriteLine(\cf5 "Do logic based on LogType.Info"\cf0 );\par ?? \cf3 break\cf0 ;\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;switch&lt;/span&gt; (logType2)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; 2:&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Do logic based on LogType.Info"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;while this doesn't compile (it fails at the case statement):&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \par ?? \cf3 switch\cf0 (logType2)\par ?? \{\par ?? \cf3 case\cf0 \cf4 LogType\cf0 .Info:\par ?? \cf4 Console\cf0 .WriteLine(\cf5 "Do logic based on LogType.Info"\cf0 );\par ?? \cf3 break\cf0 ;\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;switch&lt;/span&gt; (logType2)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LogType&lt;/span&gt;.Info:&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Do logic based on LogType.Info"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;break&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The C# compiler requires a constant in the case statement. It's also picky about what's in the switch statement. Without the implicit operator, the first switch code snippet wouldn't even have compiled either.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-7958375204227359744?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/7958375204227359744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=7958375204227359744' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7958375204227359744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7958375204227359744'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/05/simple-design-pattern-for-extensible.html' title='A Simple Design Pattern for Extensible Enumeration Types'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-9138260956869842372</id><published>2007-04-24T14:37:00.000-04:00</published><updated>2007-04-24T15:53:57.312-04:00</updated><title type='text'>Share Application-Scoped Data in Web Farm or Web Garden</title><content type='html'>I was asked recently on how to share application-scoped data in a web farm or web garden. The answer would have been easy if the question had been on session data as ASP.NET offers a couple of different ways for sharing session out-of-proc based on configuration, namely, by setting mode attribute to "StateServer", "SQLServer" or "Custom" in the sessionState element of the web.config file.&lt;br /&gt;&lt;br /&gt;For sharing application-scoped data arocess processes, though, there is no such feature provided out of box by ASP.NET. Back when EntLib wasn’t available, I implemented a custom caching framework to share application-scoped data in the web farm. Now with EntLib, you can use the caching block to achieve this quite easily. You just need to choose the database cache storage or a custom storage for the caching block. The custom storage, if you choose to do so, will have to be written and plugged into the EntLib framework of course. As the objects put in the cache will be serialized across processes and may be saved in the database, the objects will need to be serializable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-9138260956869842372?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/9138260956869842372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=9138260956869842372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/9138260956869842372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/9138260956869842372'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/04/share-application-scoped-data-in-web.html' title='Share Application-Scoped Data in Web Farm or Web Garden'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-8199486692060700745</id><published>2007-02-25T20:03:00.000-05:00</published><updated>2007-02-25T20:32:26.748-05:00</updated><title type='text'>Policy Injection App Block of EntLib 3.0 - An implementation of AOP</title><content type='html'>Details have finally emerged about Policy Injection App Block (PIAB) in the upcoming EntLib 3.0 - see &lt;a href="http://blogs.msdn.com/tomholl/archive/2007/02/23/announcing-the-policy-injection-application-block.aspx"&gt;here&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/edjez/archive/2007/02/23/policy-injection-app-block-behind-the-scenes.aspx"&gt;here&lt;/a&gt;. I have been curious and wanting to see this as this is a form of Aspect-Oriented Programming (AOP). I have worked quite a bit on my company's framework, which has a different variation of AOP. What I like about PIAB from p&amp;p is that it doesn't impose restriction of AOP at physical boundaries, as opposed to, say, binding AOP to the service boundary. The arguments for binding AOP to only the service boundary are basically concerning about the undisciplined use of AOP, thus causing aspect "meatballs" throughout the application. I think the decoupling of AOP from physical application boundaries bring more benefits and goodness to the application architecture. Remember that we could configure attributes, such as transaction, security for components in MTS and later COM+. If a framework makes the aspect feature highly configurable, I wouldn't agree to the "meatballs" argument. Besides, any language or framework in existence today, while making developers lives easier, still can't be savior of all problems without disciplines from developers - This is where good development process comes in. So I think most of the developers would appreciate the freedom that PIAB offers.&lt;br /&gt;&lt;br /&gt;The PIAB implementation, though, seems to be somewhat controversial. Instead of a few sound alternatives, they picked remoting. p&amp;p didn't want to mess around the runtime by using CLR profiler APIs or JIT Debugger callbacks to rewrite IL at runtime. However, the reason for not using IL rewriting, should not be they are obscure or not supported by PSS. Instead, The CLR already has ContextBoundObject, which is designed for this very purpose of interception. Don Box's Essential .NET book has a good coverage of this topic in chapter 7. As a matter of fact, I have seen a lot of AOP implementations using ContextBoundObject in the field. So I really don't understand the argument "&lt;i&gt;not recommended for customer code&lt;/i&gt;" in Edjez's blog. Maybe the CLR team can shed some light on this. Honestly I don't see why remoting is a better choice and wouldn't be replaced in future releases of EntLib. We know that remoting was not designed to BE an interception mechanism, although with an interception mechanism.&lt;br /&gt;&lt;br /&gt;Although not stated by the blogs, I suspect that the lack of "new" interception in the object builder framework may have been a driver to using remoting instead of ContextBoundObject. But based on my experience so far, besides being internally used by the other blocks, object builder hasn't got wide adoption, due to lack of documentation and API complexities. An important success factor for a framework, no matter how good the framework is, is the ease of use of its APIs. I am waiting to get my hands on the February CTP of EntLin 3.0 to see how easy the PIAB can be used in conjunction with object builder. I am hoping that tying PIAB to object builder doesn’t make it more cumbersome to use as opposed to intercepting “new” with ContextBoundObject and making it completely transparent for the client code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-8199486692060700745?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/8199486692060700745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=8199486692060700745' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/8199486692060700745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/8199486692060700745'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/02/policy-injection-app-block-of-entlib-30.html' title='Policy Injection App Block of EntLib 3.0 - An implementation of AOP'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-2899654601928695336</id><published>2007-02-10T14:07:00.000-05:00</published><updated>2007-02-10T15:09:52.776-05:00</updated><title type='text'>Win32++</title><content type='html'>The MSDN feed &lt;a href="http://msdn.microsoft.com/rss.xml/"&gt;MSDN Just Published&lt;/a&gt; interestingly has posted a &lt;a href="http://go.microsoft.com/?linkid=6162057"/&gt;link pointing to a code project article&lt;/a&gt;, which covers a simple C++ framework as an alternative to MFC. I have downloaded the core and sample source files and played with a few samples. Just as the author claims, this framework doesn't use macros, templates, MI as in MFC and WTL so it's much easier to comprehend. It bears a resemblance to the approach that .NET WinForm has taken when wrapping Win32 underneath. So kudos to the author for an exellent job!&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.codeproject.com/win32/framework.asp"&gt;code project site&lt;/a&gt; has some reader feedback regarding the choice of using TLS to store the association of a HWND and its corresponding WndProc. Being always conscious about performance, my only concern, though, is related to the implementation of StaticWindowProc:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 \par ??\tab LRESULT CALLBACK CWnd::StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\par ??\tab \{\par ??\tab \tab \cf3 try\par ??\cf0 \tab \tab \{\par ??\tab \tab \tab \{\par ??\tab \tab \tab \cf4 // Allocate an iterator for our HWND map\par ??\cf0 \tab \tab \tab std::map&amp;lt;HWND, CWnd*, CompareHWND&amp;gt;::iterator m;\par ??\par ??\tab \tab \tab GetApp()-&amp;gt;m_MapLock.Lock();\par ??\tab \tab \tab m = GetApp()-&amp;gt;GetHWNDMap().find(hWnd);\par ??\tab \tab \tab GetApp()-&amp;gt;m_MapLock.Release();\par ??\tab \tab \tab \cf3 if\cf0  (m != GetApp()-&amp;gt;GetHWNDMap().end())\par ??\tab \tab \tab \tab \cf3 return\cf0  m-&amp;gt;second-&amp;gt;WndProc(hWnd, uMsg, wParam, lParam);\par ??\par ??\tab \tab \tab \}\par ??\tab \tab \tab \cf3 throw\cf0  CWinException(TEXT(\cf5 "CWnd::StaticWindowProc .. Failed to route message"\cf0 ));\par ??\tab \tab \}\par ??\par ??\tab \tab \cf3 catch\cf0  (\cf3 const\cf0  CWinException &amp;amp;e)\par ??\tab \tab \{\par ??\tab \tab \tab e.MessageBox();\par ??\tab \tab \}\par ??\par ??\tab \tab \cf3 catch\cf0  (...)\par ??\tab \tab \{\par ??\tab \tab \tab DebugErrMsg(TEXT(\cf5 "Exception in CWnd::StaticWindowProc"\cf0 ));\par ??\tab \tab \}\par ??\par ??\tab \tab \cf3 return\cf0  ::DefWindowProc(hWnd, uMsg, wParam, lParam);;\par ??\par ??\tab \} \cf4 // LRESULT CALLBACK StaticWindowProc(...)}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; LRESULT CALLBACK CWnd::StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// Allocate an iterator for our HWND map&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; std::map&amp;lt;HWND, CWnd*, CompareHWND&amp;gt;::iterator m;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; GetApp()-&amp;gt;m_MapLock.Lock();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; m = GetApp()-&amp;gt;GetHWNDMap().find(hWnd);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; GetApp()-&amp;gt;m_MapLock.Release();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (m != GetApp()-&amp;gt;GetHWNDMap().end())&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; m-&amp;gt;second-&amp;gt;WndProc(hWnd, uMsg, wParam, lParam);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; CWinException(TEXT(&lt;span style="color: #a31515;"&gt;"CWnd::StaticWindowProc .. Failed to route message"&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: blue;"&gt;const&lt;/span&gt; CWinException &amp;amp;e)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; e.MessageBox();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (...)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; DebugErrMsg(TEXT(&lt;span style="color: #a31515;"&gt;"Exception in CWnd::StaticWindowProc"&lt;/span&gt;));&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; ::DefWindowProc(hWnd, uMsg, wParam, lParam);;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span style="color: green;"&gt;// LRESULT CALLBACK StaticWindowProc(...)&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Finding the WndProc corresponding to a HWND in the STL map will go through a critial section via m_MapLock.Lock() and m_MapLock.Release(). Albeit the light nature of crtitical sections, I'd always be wary of using it in this scenario, where all the windows messages (keyboard, mouse, etc.) of all the CWnd subclasses in the application get funneled through this function. &lt;br /&gt;&lt;br /&gt;Your thoughts? Please post comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-2899654601928695336?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/2899654601928695336/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=2899654601928695336' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2899654601928695336'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/2899654601928695336'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/02/win32.html' title='Win32++'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-3820025248341379332</id><published>2007-02-01T12:10:00.002-05:00</published><updated>2007-02-02T11:52:26.671-05:00</updated><title type='text'>Why Isn't Form Created on Stack GC'ed?</title><content type='html'>Have you run into situations where something is really simple and intuitive so you take it for granted? But if you think harder it makes little sense. Here is an example. In a WinForm application, a form (Form1) creates and opens another form (Form2) on stack (inside a button click handler) non-modally: &lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \par ??        \cf3 private\cf0  \cf3 void\cf0  btnNewForm_Click(\cf3 object\cf0  sender, \cf4 EventArgs\cf0  e)\par ??        \{\par ??            \cf4 Form2\cf0  frm = \cf3 new\cf0  \cf4 Form2\cf0 ();\par ??            frm.Show();\par ??        \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; btnNewForm_Click(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af;"&gt;EventArgs&lt;/span&gt; e)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Form2&lt;/span&gt; frm = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Form2&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; frm.Show();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We'd expect Form2 to stay on the screen after the call finishes. After all, the user of the software should be the one to decide when to end the life of Form2 by closing it. But wait, isn't the reference to Form2 created on the stack gone after the function call finishes? So why are we still seeing Form2? (Note that If the form is opened as modal, this question is irrelevant as the ShowDialog() call doesn't return until the modal form is closed)&lt;br /&gt;&lt;br /&gt;GC shouldn't bend the rules just for form objects. There must be hidden references that are not seen at programming level. A few SOS commands in the debugger indeed yield the truth for us. I have used .NET 2.0, WinDbg 6.6.0007.5 for this exercise.&lt;br /&gt;&lt;br /&gt;After the btnNewForm_Click() function that creates the form returns, we find the Form2 instance on the managed heap:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !dumpheap -type Form2&lt;br /&gt; Address       MT     Size&lt;br /&gt;013bd650 00a26d5c      324     &lt;br /&gt;total 1 objects&lt;br /&gt;Statistics:&lt;br /&gt;      MT    Count    TotalSize Class Name&lt;br /&gt;00a26d5c        1          324 Forms.Form2&lt;br /&gt;Total 1 objects&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now let's find out what are keeping references of it:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !gcroot 013bd650&lt;br /&gt;Note: Roots found on stacks may be false positives. Run "!help gcroot" for&lt;br /&gt;more info.&lt;br /&gt;Scan Thread 0 OSTHread 1f4&lt;br /&gt;Scan Thread 2 OSTHread c3c&lt;br /&gt;&lt;br /&gt;DOMAIN(001545F0):HANDLE(WeakLn):a010d0:Root:013bda70(System.Windows.Forms.NativeMethods+WndProc)-&gt;&lt;br /&gt;013bd7a4(System.Windows.Forms.Control+ControlNativeWindow)-&gt;&lt;br /&gt;013bd650(Forms.Form2)&lt;br /&gt;&lt;br /&gt;&lt;font color="red"/&gt;&lt;br /&gt;DOMAIN(001545F0):HANDLE(Strong):a01160:Root:013bd650(Forms.Form2)&lt;br /&gt;&lt;br /&gt;DOMAIN(001545F0):HANDLE(Pinned):a013ec:Root:02384b68(System.Object[])-&gt;&lt;br /&gt;0139c948(System.Collections.Generic.Dictionary`2[[System.Object, mscorlib],[System.Collections.Generic.List`1[[Microsoft.Win32.SystemEvents+SystemEventInvokeInfo, System]], mscorlib]])-&gt;&lt;br /&gt;0139d100(System.Collections.Generic.Dictionary`2+Entry[[System.Object, mscorlib],[System.Collections.Generic.List`1[[Microsoft.Win32.SystemEvents+SystemEventInvokeInfo, System]], mscorlib]][])-&gt;&lt;br /&gt;0139e27c(System.Collections.Generic.List`1[[Microsoft.Win32.SystemEvents+SystemEventInvokeInfo, System]])-&gt;&lt;br /&gt;0139e2a4(System.Object[])-&gt;&lt;br /&gt;013bdb30(Microsoft.Win32.SystemEvents+SystemEventInvokeInfo)-&gt;&lt;br /&gt;013bdb10(Microsoft.Win32.UserPreferenceChangedEventHandler)-&gt;&lt;br /&gt;013bd650(Forms.Form2)&lt;br /&gt;&lt;br /&gt;DOMAIN(001545F0):HANDLE(Pinned):a013f0:Root:02383030(System.Object[])-&gt;&lt;br /&gt;013a10e0(System.Windows.Forms.FormCollection)-&gt;&lt;br /&gt;013a10f8(System.Collections.ArrayList)-&gt;&lt;br /&gt;013a1110(System.Object[])-&gt;&lt;br /&gt;013bd650(Forms.Form2)&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;DOMAIN(001545F0):HANDLE(WeakSh):a01808:Root:013bd7a4(System.Windows.Forms.Control+ControlNativeWindow)&lt;br /&gt;DOMAIN(001545F0):HANDLE(WeakSh):a0180c:Root:013bd7a4(System.Windows.Forms.Control+ControlNativeWindow)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can ignore the weak references (WeakSh and WeakLn) and concentrate on the Strong and Pinned(indirectly) ones as they are the reasons that Form2 instance will not be GC'ed. The strong reference is actually a GCHandle (a01160) tied to the Form2 instance. Before the Form2 instance was created I added a breakpoint at call to System.Runtime.InteropServices.GCHandle.Alloc using !SOS.bpmd command. When the breakpoint was hit, I examined the CLR stack:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !clrstack -p&lt;br /&gt;OS Thread Id: 0x1f4 (0)&lt;br /&gt;ESP       EIP     &lt;br /&gt;0012ef28 79361fc4 System.Runtime.InteropServices.GCHandle.Alloc(System.Object, System.Runtime.InteropServices.GCHandleType)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        value = 0x013bd650&lt;br /&gt;        type = 0x00000002&lt;br /&gt;&lt;br /&gt;0012ef2c 7b0783cd System.Windows.Forms.Control+ControlNativeWindow.LockReference(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013bd7a4&lt;br /&gt;        locked = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012ef38 7b06ca41 System.Windows.Forms.Control.UpdateRoot()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012ef40 7b073366 System.Windows.Forms.Control.SetVisibleCore(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        value = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012efe8 7b06382b System.Windows.Forms.Form.SetVisibleCore(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013bd650&lt;br /&gt;        value = 0x00000001&lt;br /&gt;&lt;br /&gt;0012f028 7b0cf369 System.Windows.Forms.Control.Show()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012f02c 00f50423 Forms.Form1.btnNewForm_Click(System.Object, System.EventArgs)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01382ce4&lt;br /&gt;        sender = 0x0139c18c&lt;br /&gt;        e = 0x013bb798&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I have omitted the bottom frames for brevity. Showing the form eventually calls Control.SetVisibleCore(), which then calls ControlNativeWindow.LockReference(), which simply allocates a GC handle for the form instance as shown in the source code via reflector:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20 \par ??        \cf3 internal\cf0  \cf3 void\cf0  LockReference(\cf3 bool\cf0  locked)\par ??        \{\par ??            \cf3 if\cf0  (locked)\par ??            \{\par ??                \cf3 if\cf0  (!\cf3 this\cf0 .rootRef.IsAllocated)\par ??                \{\par ??                    \cf3 this\cf0 .rootRef = GCHandle.Alloc(\cf3 this\cf0 .GetControl(), GCHandleType.Normal);\par ??                \}\par ??            \}\par ??            \cf3 else\cf0  \cf3 if\cf0  (\cf3 this\cf0 .rootRef.IsAllocated)\par ??            \{\par ??                \cf3 this\cf0 .rootRef.Free();\par ??            \}\par ??        \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;internal&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LockReference(&lt;span style="color: blue;"&gt;bool&lt;/span&gt; locked)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (locked)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!&lt;span style="color: blue;"&gt;this&lt;/span&gt;.rootRef.IsAllocated)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.rootRef = GCHandle.Alloc(&lt;span style="color: blue;"&gt;this&lt;/span&gt;.GetControl(), GCHandleType.Normal);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (&lt;span style="color: blue;"&gt;this&lt;/span&gt;.rootRef.IsAllocated)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.rootRef.Free();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;According to the framework documentation, GCHandle is created corresponding to a managed object and can be used to prevent GC of the object when it's used by unmanaged client. In this case though, ControlNativeWindow's private variable rootRef, which holds the handle, does nothing but holding on tight to the form object! That's probably the name LockReference :-) To confirm that this is indeed the handle that SOS reports to us in the debugger, I stepped into the code that creates the GC handle. First I set a breakpoint at GCHandle.Alloc. When it's hit, I disassembled the instruction pointer:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !u eip&lt;br /&gt;preJIT generated code&lt;br /&gt;System.Runtime.InteropServices.GCHandle.Alloc(System.Object, System.Runtime.InteropServices.GCHandleType)&lt;br /&gt;Begin 79361fc4, size 39&lt;br /&gt;&gt;&gt;&gt; 79361fc4 57              push    edi&lt;br /&gt;79361fc5 56              push    esi&lt;br /&gt;79361fc6 53              push    ebx&lt;br /&gt;79361fc7 50              push    eax&lt;br /&gt;79361fc8 8bd9            mov     ebx,ecx&lt;br /&gt;79361fca 8bfa            mov     edi,edx&lt;br /&gt;79361fcc bae4040000      mov     edx,4E4h&lt;br /&gt;79361fd1 b901000000      mov     ecx,1&lt;br /&gt;79361fd6 e8f51ab100      call    mscorwks!JIT_Writeable_Thunks_Buf+0x1a0 (79e73ad0) (JitHelp: CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE)&lt;br /&gt;79361fdb 8d3424          lea     esi,[esp]&lt;br /&gt;79361fde 8bd7            mov     edx,edi&lt;br /&gt;79361fe0 8bcb            mov     ecx,ebx&lt;br /&gt;79361fe2 e80da4b800      call    mscorwks!MarshalNative::GCHandleInternalAlloc (79eec3f4)&lt;br /&gt;&lt;font color="red"&gt;79361fe7 8906            mov     dword ptr [esi],eax&lt;/font&gt;&lt;br /&gt;79361fe9 83ff03          cmp     edi,3&lt;br /&gt;79361fec 7507            jne     mscorlib_ni+0x2a1ff5 (79361ff5)&lt;br /&gt;79361fee 8bce            mov     ecx,esi&lt;br /&gt;79361ff0 e80f380100      call    mscorlib_ni+0x2b5804 (79375804) (System.Runtime.InteropServices.GCHandle.SetIsPinned(), mdToken: 06002ff9)&lt;br /&gt;79361ff5 8b0424          mov     eax,dword ptr [esp]&lt;br /&gt;79361ff8 59              pop     ecx&lt;br /&gt;79361ff9 5b              pop     ebx&lt;br /&gt;79361ffa 5e              pop     esi&lt;br /&gt;79361ffb 5f              pop     edi&lt;br /&gt;79361ffc c3              ret&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that I have highlighted the assembly code following the call to GCHandleInternalAlloc(). So then I stepped to that instruction 79361fe7:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; pa 79361fe7&lt;br /&gt;79361fe2 e80da4b800      call    mscorwks!MarshalNative::GCHandleInternalAlloc (79eec3f4)&lt;br /&gt;eax=00a01160 ebx=013bd650 ecx=79eec4fe edx=013bd650 esi=0012ef18 edi=00000002&lt;br /&gt;eip=79361fe7 esp=0012ef18 ebp=0012efe0 iopl=0         nv up ei pl zr na pe nc&lt;br /&gt;cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246&lt;br /&gt;mscorlib_ni+0x2a1fe7:&lt;br /&gt;79361fe7 8906            mov     dword ptr [esi],eax  ds:0023:0012ef18=00000000&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For brevity I have omitted instructions up to the point where GCHandleInternalAlloc() is called. The instruction is now at 79361fe7. The return value, which is the GC handle, should be in the EAX register:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; ?eax&lt;br /&gt;Evaluate expression: 10490208 = 00a01160&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the hex value a01160 matches exactly what SOS says. &lt;br /&gt;&lt;br /&gt;The other two references to the form instance are 1) a delegate (UserPreferenceChangedEventHandler) for system wide event notification - the name is obvious and 2) a collection FormCollection kept by System.Windows.Forms.Application.Application, exposed through a static property called OpenForms.&lt;br /&gt;&lt;br /&gt;When the form is being closed, the UserPreferenceChangedEventHandler is removed (via Control.OnHandleDestroyed), Form is removed from the Application.OpenFormsInternal (via Form.OnHandleDestroyed). As to the GCHandle, ControlNativeWindow.rootRef, is freed by LockReference again, with locked=false as seen in the following call stack:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !clrstack -p&lt;br /&gt;OS Thread Id: 0x2bc (0)&lt;br /&gt;ESP       EIP     &lt;br /&gt;0012e43c 7b078390 System.Windows.Forms.Control+ControlNativeWindow.LockReference(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01388a14&lt;br /&gt;        &lt;font color="red"&gt;locked = 0x00000000&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;0012e440 7b06ca41 System.Windows.Forms.Control.UpdateRoot()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e448 7b06d6ea System.Windows.Forms.Control.SetHandle(IntPtr)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        value = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e454 7b07a484 System.Windows.Forms.Control+ControlNativeWindow.OnHandleChange(IntPtr)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        newHandle = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e458 7b07a46e System.Windows.Forms.Control+ControlNativeWindow.OnHandleChange()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e45c 7b0897df System.Windows.Forms.NativeWindow.ReleaseHandle(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01388a14&lt;br /&gt;        handleValid = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e490 7b07a55a System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01388a14&lt;br /&gt;        hWnd = &lt;no data&gt;&lt;br /&gt;        msg = 0x00000082&lt;br /&gt;        wparam = &lt;no data&gt;&lt;br /&gt;        lparam = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e664 003420d4 [NDirectMethodFrameStandalone: 0012e664] System.Windows.Forms.UnsafeNativeMethods.IntDestroyWindow(System.Runtime.InteropServices.HandleRef)&lt;br /&gt;0012e67c 7b0892ee System.Windows.Forms.UnsafeNativeMethods.DestroyWindow(System.Runtime.InteropServices.HandleRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        hWnd = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e688 7b0891f8 System.Windows.Forms.NativeWindow.DestroyHandle()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01388a14&lt;br /&gt;&lt;br /&gt;0012e6cc 7b05f010 System.Windows.Forms.Control.DestroyHandle()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013888c0&lt;br /&gt;&lt;br /&gt;0012e6d0 7b08901e [InlinedCallFrame: 0012e6d0] &lt;br /&gt;0012e7a0 7b05c583 System.Windows.Forms.Form.Dispose(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013888c0&lt;br /&gt;        disposing = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e7b4 00f505ac Forms.Form2.Dispose(Boolean)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013888c0&lt;br /&gt;        disposing = 0x00000001&lt;br /&gt;&lt;br /&gt;0012e7c8 7a4a6633 System.ComponentModel.Component.Dispose()&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x013888c0&lt;br /&gt;&lt;br /&gt;0012e7d0 7b224d92 System.Windows.Forms.Form.WmClose(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e7fc 7b063e7d System.Windows.Forms.Form.WndProc(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e80c 7b07a72d System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e810 7b07a706 System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012e824 7b07a515 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = 0x01388a14&lt;br /&gt;        hWnd = &lt;no data&gt;&lt;br /&gt;        msg = 0x00000010&lt;br /&gt;        wparam = &lt;no data&gt;&lt;br /&gt;        lparam = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012ec04 003420d4 [InlinedCallFrame: 0012ec04] System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr)&lt;br /&gt;0012ec00 7b07a7d4 System.Windows.Forms.NativeWindow.DefWndProc(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = 0x0012ed3c&lt;br /&gt;&lt;br /&gt;0012ec44 7b05ed83 System.Windows.Forms.Form.DefWndProc(System.Windows.Forms.Message ByRef)&lt;br /&gt;    PARAMETERS:&lt;br /&gt;        this = &lt;no data&gt;&lt;br /&gt;        m = &lt;no data&gt;&lt;br /&gt;&lt;br /&gt;0012ec48 7b072abc [InlinedCallFrame: 0012ec48] &lt;br /&gt;0012ec90 7b07f795 [InlinedCallFrame: 0012ec90] &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-3820025248341379332?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/3820025248341379332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=3820025248341379332' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3820025248341379332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/3820025248341379332'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/02/why-isnt-form-created-on-stack-gced.html' title='Why Isn&apos;t Form Created on Stack GC&apos;ed?'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-7259930933094659420</id><published>2007-01-23T14:20:00.000-05:00</published><updated>2008-12-08T15:58:52.667-05:00</updated><title type='text'>How To Create Custom Database With Enterprise Library 2.0 Data Access Block - Part 2</title><content type='html'>As promised in &lt;a href="http://tigerang.blogspot.com/2007/01/how-to-create-custom-database-with.html"/&gt;this previous blog&lt;/a&gt;, I have created a custom Database implementation for Firebird in the EntLib 2.0 framework. &lt;br /&gt;&lt;br /&gt;First I implemented this interface: Microsoft.Practices.EnterpriseLibrary.Data.Configuration.IDatabaseAssembler&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 using\cf0 System;\par ??\cf1 using\cf0 System.Configuration;\par ??\cf1 using\cf0 Microsoft.Practices.EnterpriseLibrary.Common.Configuration;\par ??\cf1 using\cf0 Microsoft.Practices.EnterpriseLibrary.Data.Configuration;\par ??\par ??\cf1 namespace\cf0 FirebirdSql.Data.EntLib\par ??\{\par ?? \cf1 public\cf0 \cf1 class\cf0 \cf4 FbDatabaseAssembler\cf0 : \cf4 IDatabaseAssembler\par ??\cf0 \{\par ?? \cf1 public\cf0 Microsoft.Practices.EnterpriseLibrary.Data.\cf4 Database\cf0 Assemble(\cf1 string\cf0 name, \cf4 ConnectionStringSettings\cf0 connectionStringSettings, \cf4 IConfigurationSource\cf0 configurationSource)\par ?? \{\par ?? \cf1 return\cf0 \cf1 new\cf0 \cf4 FbDatabase\cf0 (connectionStringSettings.ConnectionString);\par ?? \}\par ?? \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Configuration;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Common.Configuration;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Data.Configuration;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; FirebirdSql.Data.EntLib&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FbDatabaseAssembler&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IDatabaseAssembler&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Data.&lt;span style="color: #2b91af;"&gt;Database&lt;/span&gt; Assemble(&lt;span style="color: blue;"&gt;string&lt;/span&gt; name, &lt;span style="color: #2b91af;"&gt;ConnectionStringSettings&lt;/span&gt; connectionStringSettings, &lt;span style="color: #2b91af;"&gt;IConfigurationSource&lt;/span&gt; configurationSource)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FbDatabase&lt;/span&gt;(connectionStringSettings.ConnectionString);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Then I derived from Microsoft.Practices.EnterpriseLibrary.Data.Database (we should do more deligence here to ensure we take care of FbClient's idiosyncracies by implementing appropriate overrides or provide additional functions, as in SqlDatabase and OracleDatabase):&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;}??\fs20 \cf1 using\cf0 System;\par ??\cf1 using\cf0 System.Data.Common;\par ??\cf1 using\cf0 System.Security.Permissions;\par ??\par ??\cf1 using\cf0 Microsoft.Practices.EnterpriseLibrary.Data;\par ??\cf1 using\cf0 Microsoft.Practices.EnterpriseLibrary.Data.Configuration;\par ??\par ??\cf1 using\cf0 FirebirdSql.Data.FirebirdClient;\par ??\par ??\cf1 namespace\cf0 FirebirdSql.Data.EntLib\par ??\{\par ?? [\cf4 FirebirdClientPermission\cf0 (\cf4 SecurityAction\cf0 .Demand)]\par ?? [\cf4 DatabaseAssembler\cf0 (\cf1 typeof\cf0 (\cf4 FbDatabaseAssembler\cf0 ))]\par ?? \cf1 public\cf0 \cf1 class\cf0 \cf4 FbDatabase\cf0 : \cf4 Database\par ??\cf0 \{\par ?? \cf1 public\cf0 FbDatabase(\cf1 string\cf0 connectionString)\par ?? : \cf1 base\cf0 (connectionString, \cf4 FirebirdClientFactory\cf0 .Instance)\par ?? \{\par ?? \}\par ??\par ?? \cf1 protected\cf0 \cf1 override\cf0 \cf1 void\cf0 DeriveParameters(System.Data.Common.\cf4 DbCommand\cf0 discoveryCommand)\par ?? \{\par ?? \cf4 FbCommandBuilder\cf0 .DeriveParameters((\cf4 FbCommand\cf0 )discoveryCommand);\par ?? \}\par ?? \}\par ??\}\par ??}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Data.Common;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Security.Permissions;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Data;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Data.Configuration;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; FirebirdSql.Data.FirebirdClient;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; FirebirdSql.Data.EntLib&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;FirebirdClientPermission&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;SecurityAction&lt;/span&gt;.Demand)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;DatabaseAssembler&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;FbDatabaseAssembler&lt;/span&gt;))]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FbDatabase&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;Database&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; FbDatabase(&lt;span style="color: blue;"&gt;string&lt;/span&gt; connectionString)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(connectionString, &lt;span style="color: #2b91af;"&gt;FirebirdClientFactory&lt;/span&gt;.Instance)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DeriveParameters(System.Data.Common.&lt;span style="color: #2b91af;"&gt;DbCommand&lt;/span&gt; discoveryCommand)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FbCommandBuilder&lt;/span&gt;.DeriveParameters((&lt;span style="color: #2b91af;"&gt;FbCommand&lt;/span&gt;)discoveryCommand);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And now I set up a winform test application:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \cf1 using\cf0 System;\par ??\cf1 using\cf0 System.Collections.Generic;\par ??\cf1 using\cf0 System.ComponentModel;\par ??\cf1 using\cf0 System.Data;\par ??\cf1 using\cf0 System.Drawing;\par ??\cf1 using\cf0 System.Text;\par ??\cf1 using\cf0 System.Windows.Forms;\par ??\cf1 using\cf0 System.Data.Common;\par ??\par ??\cf1 using\cf0 Microsoft.Practices.EnterpriseLibrary.Data;\par ??\par ??\cf1 namespace\cf0 FirebirdSql.Data.EntLib.Test\par ??\{\par ?? \cf1 public\cf0 \cf1 partial\cf0 \cf1 class\cf0 \cf4 MainForm\cf0 : \cf4 Form\par ??\cf0 \{\par ?? \cf1 public\cf0 MainForm()\par ?? \{\par ?? InitializeComponent();\par ?? \}\par ??\par ?? \cf1 private\cf0 \cf1 void\cf0 btnDataset_Click(\cf1 object\cf0 sender, \cf4 EventArgs\cf0 e)\par ?? \{\par ?? \cf4 Database\cf0 db = \cf4 DatabaseFactory\cf0 .CreateDatabase();\par ?? \cf4 DbCommand\cf0 comm = db.GetSqlStringCommand(\cf5 "SELECT JOB_CODE, JOB_REQUIREMENT FROM JOB"\cf0 );\par ??\par ?? \cf4 DataSet\cf0 ds = db.ExecuteDataSet(comm);\par ?? \cf1 this\cf0 .dgv.DataSource = ds.Tables[0];\par ?? \}\par ?? \}\par ??\}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.ComponentModel;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Data;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Drawing;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Text;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Data.Common;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Data;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; FirebirdSql.Data.EntLib.Test&lt;/p&gt;&lt;p style="margin: 0px;"&gt;{&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;partial&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MainForm&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;Form&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; MainForm()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; InitializeComponent();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; btnDataset_Click(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af;"&gt;EventArgs&lt;/span&gt; e)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Database&lt;/span&gt; db = &lt;span style="color: #2b91af;"&gt;DatabaseFactory&lt;/span&gt;.CreateDatabase();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DbCommand&lt;/span&gt; comm = db.GetSqlStringCommand(&lt;span style="color: #a31515;"&gt;"SELECT JOB_CODE, JOB_REQUIREMENT FROM JOB"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DataSet&lt;/span&gt; ds = db.ExecuteDataSet(comm);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.dgv.DataSource = ds.Tables[0];&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Note that I can now execute SQL and bind to the control in only 4 lines of code. The connection string and the mapping between provider and FbDatabase is taken care of by the EntLib configuration console:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_UTl9xtmUmII/RbZjwU0tgAI/AAAAAAAAAAk/t6PNxYJZsLg/s1600-h/EntLib_FbDatabase_DAAB_Config.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_UTl9xtmUmII/RbZjwU0tgAI/AAAAAAAAAAk/t6PNxYJZsLg/s320/EntLib_FbDatabase_DAAB_Config.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5023312116253032450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So you see it's really easy to implement a custom Database object for EntLib DAAB if its ADO.NET native providers exist. With this, developers can use consistent API to access the databases in an elegant way. It's especially useful when you need to access multiple databases (from different database types) in the same application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-7259930933094659420?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/7259930933094659420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=7259930933094659420' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7259930933094659420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7259930933094659420'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/how-to-create-custom-database-with_23.html' title='How To Create Custom Database With Enterprise Library 2.0 Data Access Block - Part 2'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_UTl9xtmUmII/RbZjwU0tgAI/AAAAAAAAAAk/t6PNxYJZsLg/s72-c/EntLib_FbDatabase_DAAB_Config.jpg' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-7297665780152660347</id><published>2007-01-23T10:54:00.000-05:00</published><updated>2007-01-23T12:03:08.422-05:00</updated><title type='text'>Memory Leaks in .NET Applications</title><content type='html'>When I tell people that their .NET applications are leaking memory, I sometimes get frowned upon as if memory leaking is moot in CLR. After all, garbage collection is there so why would we have to worry about this?&lt;br /&gt;&lt;br /&gt;MSDN has published &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/01/ManagedLeaks/default.aspx"&gt;an excellent article&lt;/a&gt; on this topic. While it covers many memory leaking scenarios to watch out for, I have seen a couple of quite common ones at various customers due to coding practice issues:&lt;br /&gt;&lt;br /&gt;1) Custom-rolled caching that has no expiration and throttling mechanisms. The cache eventually will be filled up with references to objects that are not intended to be kept. A common pattern is a singleton wrapping a hashtable.&lt;br /&gt;&lt;br /&gt;2) Event handlers (delegates) added to application level events but forgotten to be removed. I have seen this in both Winform and ASP.NET apps, where a form or an ASP.NET page has hooked its instance function to an application event through a delegate. Forgetting to remove such handlers when the form or page is unloaded will simply keep the instance of the form or page in memory, keeping it from garbage collected.&lt;br /&gt;&lt;br /&gt;As you can see, just like you need to "free" after "malloc", "delete" after "new", "CloseHandle" after "CreateFile" etc. in C++/Win32 API, discipline is still needed in .NET coding just as well. So don't let your guard down.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-7297665780152660347?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/7297665780152660347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=7297665780152660347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7297665780152660347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/7297665780152660347'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/memory-leaks-in-net-applications.html' title='Memory Leaks in .NET Applications'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-1503421848728957272</id><published>2007-01-22T09:26:00.000-05:00</published><updated>2008-12-08T15:58:52.804-05:00</updated><title type='text'>ByRef Snafu</title><content type='html'>At a client I worked some time ago, a consultant who had worked there prior to me had told the client developers (mostly from VB 6 background) a "best practice": &lt;i&gt;use ByRef when passing reference type parameters and ByVal for value type ones&lt;/i&gt;. Besides the obvious confusion of the concepts, this practice and a particular VB.NET compiler design had caused a subtle bug in the application that was difficult to track down. That application was written for .NET framework 1.1 with VS.NET 2003. Now the VB.NET compiler for VS.NET 2005 still does the same so I am able to contrive a simple example to demo this bug in VS.NET 2005.&lt;br /&gt;&lt;br /&gt;To get started, I have created a simple form with a textbox "txtName" and a button "btnCallByRef" as in the following:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_UTl9xtmUmII/RbTgyiH_-HI/AAAAAAAAAAY/93heSLgOiA8/s1600-h/VB_ByRef.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_UTl9xtmUmII/RbTgyiH_-HI/AAAAAAAAAAY/93heSLgOiA8/s320/VB_ByRef.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5022886643183384690" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And here is the code:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;\red0\green128\blue0;}??\fs20 \cf1 Public\cf0 \cf1 Class\cf0 Main\par ?? \cf1 Private\cf0 \cf1 Sub\cf0 btnCallByRef_Click(\cf1 ByVal\cf0 sender \cf1 As\cf0 System.Object, \cf1 ByVal\cf0 e \cf1 As\cf0 System.EventArgs) \cf1 Handles\cf0 btnCallByRef.Click\par ?? ReadTextBox(txtName)\par ?? Debug.WriteLine(\cf4 "txtBox is passed to a function ByRef"\cf0 )\par ?? \cf1 End\cf0 \cf1 Sub\par ??\par ??\cf0 \cf1 Private\cf0 \cf1 Sub\cf0 ReadTextBox(\cf1 ByRef\cf0 txtbox \cf1 As\cf0 TextBox)\par ?? \cf5 ' nop\par ??\cf0 \cf1 End\cf0 \cf1 Sub\par ??\par ??\cf0 \cf1 Private\cf0 \cf1 Sub\cf0 txtName_Leave(\cf1 ByVal\cf0 sender \cf1 As\cf0 System.Object, \cf1 ByVal\cf0 e \cf1 As\cf0 System.EventArgs) \cf1 Handles\cf0 txtName.Leave\par ?? Debug.WriteLine(\cf4 "txtName_Leave handler"\cf0 )\par ?? \cf1 End\cf0 \cf1 Sub\par ??\par ??\cf0 \cf1 Private\cf0 \cf1 Sub\cf0 AnotherHandler(\cf1 ByVal\cf0 sender \cf1 As\cf0 System.Object, \cf1 ByVal\cf0 e \cf1 As\cf0 System.EventArgs)\par ?? Debug.WriteLine(\cf4 "another handler"\cf0 )\par ?? \cf1 End\cf0 \cf1 Sub\par ??\par ??\cf0 \cf1 Private\cf0 \cf1 Sub\cf0 Main_Load(\cf1 ByVal\cf0 sender \cf1 As\cf0 System.Object, \cf1 ByVal\cf0 e \cf1 As\cf0 System.EventArgs) \cf1 Handles\cf0 \cf1 MyBase\cf0 .Load\par ?? \cf1 AddHandler\cf0 txtName.Leave, \cf1 AddressOf\cf0 AnotherHandler\par ?? \cf1 End\cf0 \cf1 Sub\par ??End\cf0 \cf1 Class}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Public&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt; Main&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; btnCallByRef_Click(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color: blue;"&gt;Handles&lt;/span&gt; btnCallByRef.Click&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ReadTextBox(txtName)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(&lt;span style="color: #a31515;"&gt;"txtBox is passed to a function ByRef"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; ReadTextBox(&lt;span style="color: blue;"&gt;ByRef&lt;/span&gt; txtbox &lt;span style="color: blue;"&gt;As&lt;/span&gt; TextBox)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;' nop&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; txtName_Leave(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color: blue;"&gt;Handles&lt;/span&gt; txtName.Leave&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(&lt;span style="color: #a31515;"&gt;"txtName_Leave handler"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; AnotherHandler(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.EventArgs)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(&lt;span style="color: #a31515;"&gt;"another handler"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;Private&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt; Main_Load(&lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color: blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color: blue;"&gt;Handles&lt;/span&gt; &lt;span style="color: blue;"&gt;MyBase&lt;/span&gt;.Load&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;AddHandler&lt;/span&gt; txtName.Leave, &lt;span style="color: blue;"&gt;AddressOf&lt;/span&gt; AnotherHandler&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;End&lt;/span&gt; &lt;span style="color: blue;"&gt;Class&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The textbox "txtName" has a design time handler "txtName_Leave" defined for its "Leave" event. During form load, another handler "AnotherHandler" is added dynamically to handle the same "Leave" event. The client application had a framework, which uses a generic event handler to monitor form all kinds of events - the "AnotherHandler" is just simulating that handler in the framework. Note that the framework's generic handler needs to be called &lt;b&gt;last&lt;/b&gt; in the delegate chain as it needs to look at the final attributes of the controls, since they may be changed by handlers that are put there at design time by form developers. &lt;br /&gt;&lt;br /&gt;This is all working pretty well when I tab out the textbox to fire the Leave event. See the following in the output window while debugging:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;txtName_Leave handler&lt;br /&gt;another handler&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;well, pretty well until the "btnCallByRef_Click" function is called:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;txtBox is passed to a function ByRef&lt;br /&gt;another handler&lt;br /&gt;txtName_Leave handler&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/br&gt;&lt;br /&gt;When I tab out the textbox to fire the Leave event, the execution order of the handlers has been reversed. What happened here? It turns out that when a control is declared as in the following:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 Friend\cf0 \cf1 WithEvents\cf0 txtName \cf1 As\cf0 System.Windows.Forms.TextBox}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;Friend&lt;/span&gt; &lt;span style="color: blue;"&gt;WithEvents&lt;/span&gt; txtName &lt;span style="color: blue;"&gt;As&lt;/span&gt; System.Windows.Forms.TextBox&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The VB.NET compiler will create a private field "_txtName" and a public property "txtName" encapsulating the field and what's more interesting is the setter of the property as seen in IL:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;.method assembly newslot specialname strict virtual &lt;br /&gt;instance void set_txtName(class [System.Windows.Forms]System.Windows.Forms.TextBox WithEventsValue) cil managed synchronized&lt;br /&gt;{&lt;br /&gt;.custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) &lt;br /&gt;// Code size 93 (0x5d)&lt;br /&gt;.maxstack 3&lt;br /&gt;.locals init (bool V_0)&lt;br /&gt;IL_0000: ldarg.0&lt;br /&gt;IL_0001: ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::_txtName&lt;br /&gt;IL_0006: ldnull&lt;br /&gt;IL_0007: ceq&lt;br /&gt;IL_0009: ldc.i4.0&lt;br /&gt;IL_000a: ceq&lt;br /&gt;IL_000c: stloc.0&lt;br /&gt;IL_000d: ldloc.0&lt;br /&gt;IL_000e: brfalse.s IL_0029&lt;br /&gt;IL_0010: ldarg.0&lt;br /&gt;IL_0011: ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::_txtName&lt;br /&gt;IL_0016: ldarg.0&lt;br /&gt;IL_0017: dup&lt;br /&gt;IL_0018: ldvirtftn instance void VBWinForm.Main::txtName_Leave(object,&lt;br /&gt;class [mscorlib]System.EventArgs)&lt;br /&gt;IL_001e: newobj instance void [mscorlib]System.EventHandler::.ctor(object,&lt;br /&gt;native int)&lt;br /&gt;&lt;font color="red"&gt;IL_0023: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::remove_Leave(class [mscorlib]System.EventHandler)&lt;/font&gt;&lt;br /&gt;IL_0028: nop&lt;br /&gt;IL_0029: nop&lt;br /&gt;IL_002a: ldarg.0&lt;br /&gt;IL_002b: ldarg.1&lt;br /&gt;IL_002c: stfld class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::_txtName&lt;br /&gt;IL_0031: ldarg.0&lt;br /&gt;IL_0032: ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::_txtName&lt;br /&gt;IL_0037: ldnull&lt;br /&gt;IL_0038: ceq&lt;br /&gt;IL_003a: ldc.i4.0&lt;br /&gt;IL_003b: ceq&lt;br /&gt;IL_003d: stloc.0&lt;br /&gt;IL_003e: ldloc.0&lt;br /&gt;IL_003f: brfalse.s IL_005a&lt;br /&gt;IL_0041: ldarg.0&lt;br /&gt;IL_0042: ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::_txtName&lt;br /&gt;IL_0047: ldarg.0&lt;br /&gt;IL_0048: dup&lt;br /&gt;IL_0049: ldvirtftn instance void VBWinForm.Main::txtName_Leave(object,&lt;br /&gt;class [mscorlib]System.EventArgs)&lt;br /&gt;IL_004f: newobj instance void [mscorlib]System.EventHandler::.ctor(object,&lt;br /&gt;native int)&lt;br /&gt;&lt;font color="red"&gt;IL_0054: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::add_Leave(class [mscorlib]System.EventHandler)&lt;/font&gt;&lt;br /&gt;IL_0059: nop&lt;br /&gt;IL_005a: nop&lt;br /&gt;IL_005b: nop&lt;br /&gt;IL_005c: ret&lt;br /&gt;} // end of method Main::set_txtName&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;&lt;/br&gt;&lt;br /&gt;So it can be seen that the existing handler is removed, the field _txtName is set and the event handler is added back again. And if we take a look at the IL code of btnCallByRef_Click. Note how the "set_txtName" is called after the "ReadTextBox" call as a result of passing &lt;font color="red"&gt;ByRef&lt;/font&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;.method private instance void btnCallByRef_Click(object sender,&lt;br /&gt;class [mscorlib]System.EventArgs e) cil managed&lt;br /&gt;{&lt;br /&gt;// Code size 38 (0x26)&lt;br /&gt;.maxstack 2&lt;br /&gt;.locals init ([0] class [System.Windows.Forms]System.Windows.Forms.TextBox VB$t_ref$S0)&lt;br /&gt;IL_0000: nop&lt;br /&gt;IL_0001: ldarg.0&lt;br /&gt;IL_0002: ldarg.0&lt;br /&gt;IL_0003: callvirt instance class [System.Windows.Forms]System.Windows.Forms.TextBox VBWinForm.Main::get_txtName()&lt;br /&gt;IL_0008: stloc.0&lt;br /&gt;IL_0009: ldloca.s VB$t_ref$S0&lt;br /&gt;IL_000b: callvirt instance void VBWinForm.Main::ReadTextBox(class [System.Windows.Forms]System.Windows.Forms.TextBox&amp;)&lt;br /&gt;IL_0010: nop&lt;br /&gt;IL_0011: ldarg.0&lt;br /&gt;IL_0012: ldloc.0&lt;br /&gt;&lt;font color="red"&gt;IL_0013: callvirt instance void VBWinForm.Main::set_txtName(class [System.Windows.Forms]System.Windows.Forms.TextBox)&lt;/font&gt;&lt;br /&gt;IL_0018: nop&lt;br /&gt;IL_0019: ldstr "txtBox is passed to a function ByRef"&lt;br /&gt;IL_001e: call void [System]System.Diagnostics.Debug::WriteLine(string)&lt;br /&gt;IL_0023: nop&lt;br /&gt;IL_0024: nop&lt;br /&gt;IL_0025: ret&lt;br /&gt;} // end of method Main::btnCallByRef_Click&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/br&gt;&lt;br /&gt;This VB.NET compiler behavior is clearly designed for the convenience of developers so they don't have to manually add or remove handlers in their code. Unfortunately not knowing this and following an ill-advised practice involving ByRef led to a really unexpected bug.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-1503421848728957272?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/1503421848728957272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=1503421848728957272' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1503421848728957272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/1503421848728957272'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/byref-snafu.html' title='ByRef Snafu'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_UTl9xtmUmII/RbTgyiH_-HI/AAAAAAAAAAY/93heSLgOiA8/s72-c/VB_ByRef.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-6809764685022320982</id><published>2007-01-21T20:54:00.000-05:00</published><updated>2008-12-08T15:58:52.930-05:00</updated><title type='text'>How To Create Custom Database With Enterprise Library 2.0 Data Access Block</title><content type='html'>There seems to be little documentation on how to create custom database object to be used for Enterprise Library 2.0 Data Access block. Tom Hollander in this &lt;a href="http://blogs.msdn.com/tomholl/archive/2005/09/14/466298.aspx"&gt;blog&lt;/a&gt; confirms that this is definitely a possibility:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;In the new version, we still have the SqlDatabase and OracleDatabase class – but we also have a new GenericDatabase class. The GenericDatabase can be used with any .NET managed provider (including the ODBC and OLE-DB providers that ship with .NET) – but the catch is that it doesn’t support all of the DAAB functionality. Most significantly, the overloads that use parameter discovery do not work (since these methods aren’t supported on .NET’s DbConnection or DbCommand classes). There’s still the option to build your own Database-derived classes to support this advanced functionality and provide improved database transparency – this is why we built SqlDatabase and OracleDatabase – but at least you’ll be able to use most of the block against any type of database.&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Since I installed Firebird, I have been itching to write a custom Database for Firebird in the EntLib 2.0 framework. I know there are customers who want to do this as well because they have Sybase, DB2 in their environment. The GenericDatanase would be an option with ODBC and OLEDB. But for the long term, it makes sense to leverage the native ADO.NET providers if they do exist.&lt;br /&gt;&lt;br /&gt;So I started digging into the source code and trying to figure out how a custom Database object would be created by EntLib besides the three ones provided out of the box. Finally I came upon the GetProviderMapping() function of DatabaseConfigurationView class:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \par ??\tab \tab \cf3 public\cf0 \cf4 DbProviderMapping\cf0 GetProviderMapping(\cf3 string\cf0 name, \cf3 string\cf0 dbProviderName)\par ??\tab \tab \{\par ??\tab \tab \tab \cf4 DatabaseSettings\cf0 settings = \cf3 this\cf0 .DatabaseSettings;\par ??\tab \tab \tab \cf3 if\cf0 (settings != \cf3 null\cf0 )\par ??\tab \tab \tab \{\par ??\tab \tab \tab \tab \cf4 DbProviderMapping\cf0 existingMapping = settings.ProviderMappings.Get(dbProviderName);\par ??\tab \tab \tab \tab \cf3 if\cf0 (existingMapping != \cf3 null\cf0 )\par ??\tab \tab \tab \tab \{\par ??\tab \tab \tab \tab \tab \cf3 return\cf0 existingMapping;\par ??\tab \tab \tab \tab \}\par ??\tab \tab \tab \}\par ??\par ??\tab \tab \tab \cf4 DbProviderMapping\cf0 defaultMapping = \cf3 this\cf0 .GetDefaultMapping(name, dbProviderName);\par ??\tab \tab \tab \cf3 if\cf0 (defaultMapping != \cf3 null\cf0 )\par ??\tab \tab \tab \{\par ??\tab \tab \tab \tab \cf3 return\cf0 defaultMapping;\par ??\tab \tab \tab \}\par ??\par ??\tab \tab \tab \cf3 return\cf0 \cf3 this\cf0 .GetGenericMapping();\par ??\tab \tab \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt; GetProviderMapping(&lt;span style="color: blue;"&gt;string&lt;/span&gt; name, &lt;span style="color: blue;"&gt;string&lt;/span&gt; dbProviderName)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DatabaseSettings&lt;/span&gt; settings = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.DatabaseSettings;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (settings != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt; existingMapping = settings.ProviderMappings.Get(dbProviderName);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (existingMapping != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; existingMapping;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt; defaultMapping = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.GetDefaultMapping(name, dbProviderName);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (defaultMapping != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; defaultMapping;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.GetGenericMapping();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This function calls the ProviderMappings property of the DatabaseSettings class:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;\red128\green128\blue128;\red0\green128\blue0;}??\fs20 \par ??\tab \cf3 public\cf0 \cf3 class\cf0 \cf4 DatabaseSettings\cf0 : \cf4 SerializableConfigurationSection\par ??\cf0 \tab \{\par ??\tab \tab \cf3 private\cf0 \cf3 const\cf0 \cf3 string\cf0 defaultDatabaseProperty = \cf5 "defaultDatabase"\cf0 ;\par ??\tab \tab \cf3 private\cf0 \cf3 const\cf0 \cf3 string\cf0 dbProviderMappingsProperty = \cf5 "providerMappings"\cf0 ;\par ??\par ??\tab \tab \cf6 ///\cf7 \cf6 &amp;lt;summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 The name of the data configuration section.\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/summary&amp;gt;\par ??\cf0 \tab \tab \cf3 public\cf0 \cf3 const\cf0 \cf3 string\cf0 SectionName = \cf5 "dataConfiguration"\cf0 ;\par ??\par ??\tab \tab \cf6 ///\cf7 \cf6 &amp;lt;summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;para&amp;gt;\cf7 Initializes a new instance of the \cf6 &amp;lt;see cref="DatabaseSettings"/&amp;gt;\cf7 class.\cf6 &amp;lt;/para&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/summary&amp;gt;\par ??\cf0 \tab \tab \cf3 public\cf0 DatabaseSettings()\par ??\tab \tab \tab : \cf3 base\cf0 ()\par ??\tab \tab \{\par ??\tab \tab \}\par ??\par ??\tab \tab \cf6 ///\cf7 \cf6 &amp;lt;summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 Retrieves the \cf6 &amp;lt;see cref="DatabaseSettings"/&amp;gt;\cf7 from a configuration source.\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;param name="configurationSource"&amp;gt;\cf7 The \cf6 &amp;lt;see cref="IConfigurationSource"/&amp;gt;\cf7 to query for the database settings.\cf6 &amp;lt;/param&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;returns&amp;gt;\cf7 The database settings from the configuration source, or \cf6 &amp;lt;see langword="null"/&amp;gt;\cf7 (\cf6 &amp;lt;b&amp;gt;\cf7 Nothing\cf6 &amp;lt;/b&amp;gt;\cf7 in Visual Basic) if the \par ??\cf0 \tab \tab \cf6 ///\cf7 configuration source does not contain database settings.\cf6 &amp;lt;/returns&amp;gt;\par ??\cf0 \tab \tab \cf3 public\cf0 \cf3 static\cf0 \cf4 DatabaseSettings\cf0 GetDatabaseSettings(\cf4 IConfigurationSource\cf0 configurationSource)\par ??\tab \tab \{\par ??\tab \tab \tab \cf3 return\cf0 (\cf4 DatabaseSettings\cf0 )configurationSource.GetSection(SectionName);\par ??\tab \tab \}\par ??\par ??\tab \tab \cf6 ///\cf7 \cf6 &amp;lt;summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;para&amp;gt;\cf7 Gets or sets the default database instance name.\cf6 &amp;lt;/para&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;value&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;para&amp;gt;\cf7 The default database instance name.\cf6 &amp;lt;/para&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/value&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;remarks&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;para&amp;gt;\cf7 This property maps to the \cf6 &amp;lt;c&amp;gt;\cf7 defaultInstance\cf6 &amp;lt;/c&amp;gt;\cf7 element in configuration.\cf6 &amp;lt;/para&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/remarks&amp;gt;\par ??\cf0 \tab \tab [\cf4 ConfigurationProperty\cf0 (defaultDatabaseProperty, IsRequired = \cf3 false\cf0 )]\par ??\tab \tab \cf3 public\cf0 \cf3 string\cf0 DefaultDatabase\par ??\tab \tab \{\par ??\tab \tab \tab \cf3 get\par ??\cf0 \tab \tab \tab \{\par ??\tab \tab \tab \tab \cf3 return\cf0 (\cf3 string\cf0 )\cf3 this\cf0 [defaultDatabaseProperty];\par ??\tab \tab \tab \}\par ??\tab \tab \tab \cf3 set\par ??\cf0 \tab \tab \tab \{\par ??\tab \tab \tab \tab \cf3 this\cf0 [defaultDatabaseProperty] = \cf3 value\cf0 ;\par ??\tab \tab \tab \}\par ??\tab \tab \}\par ??\par ??\tab \tab \cf6 ///\cf7 \cf6 &amp;lt;summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 Holds the optional mappings from ADO.NET's database providers to Enterprise Library's database types.\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;/summary&amp;gt;\par ??\cf0 \tab \tab \cf6 ///\cf7 \cf6 &amp;lt;seealso cref="DbProviderMapping"/&amp;gt;\par ??\cf0 \tab \tab [\cf4 ConfigurationProperty\cf0 (dbProviderMappingsProperty, IsRequired = \cf3 false\cf0 )]\par ??\tab \tab \cf3 public\cf0 \cf4 NamedElementCollection\cf0 &amp;lt;\cf4 DbProviderMapping\cf0 &amp;gt; ProviderMappings\par ??\tab \tab \{\par ??\tab \tab \tab \cf3 get\par ??\cf0 \tab \tab \tab \{\par ??\tab \tab \tab \tab \cf3 return\cf0 (\cf4 NamedElementCollection\cf0 &amp;lt;\cf4 DbProviderMapping\cf0 &amp;gt;)\cf3 base\cf0 [dbProviderMappingsProperty];\par ??\tab \tab \tab \}\par ??\tab \tab \}\par ??\tab \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DatabaseSettings&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;SerializableConfigurationSection&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;!--StartFragment--&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;}??\fs20 \par ?? \cf3 // code ommited for brevity}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div style="font-size: 10pt; background: white; color: black; font-family: Courier New"&gt;&lt;br /&gt;&lt;p style="margin: 0px"&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px"&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: green"&gt;// code ommited for brevity&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;!--EndFragment--&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; Holds the optional mappings from ADO.NET's database providers to Enterprise Library's database types.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;seealso cref="DbProviderMapping"/&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;ConfigurationProperty&lt;/span&gt;(dbProviderMappingsProperty, IsRequired = &lt;span style="color: blue;"&gt;false&lt;/span&gt;)]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;NamedElementCollection&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt;&amp;gt; ProviderMappings&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;NamedElementCollection&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt;&amp;gt;)&lt;span style="color: blue;"&gt;base&lt;/span&gt;[dbProviderMappingsProperty];&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This shows that the configuration drives the creation of the custom Database, if any. So I openned up the EntLib configuration console and now the "Custom Mapping Providers" made sense - all we have to do is to provide a mapping between a name and a custom Database type. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_UTl9xtmUmII/RbQhICH_-GI/AAAAAAAAAAM/F_oSA6T3BOY/s1600-h/EntLi_DAAB_Config.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_UTl9xtmUmII/RbQhICH_-GI/AAAAAAAAAAM/F_oSA6T3BOY/s320/EntLi_DAAB_Config.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5022675906318039138" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I will detail creating the assembler class along with the custom Database object in a future blog. To see how these all work together, Here is the CreateObject() function of the DatabaseCustomFactory class that provides a clear view how the mapping is queried, then assembler is created from the mapping before the Database gets created. :&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \par ??\tab \tab \cf3 public\cf0 \cf3 object\cf0 CreateObject(\cf4 IBuilderContext\cf0 context, \cf3 string\cf0 name, \cf4 IConfigurationSource\cf0 configurationSource, \cf4 ConfigurationReflectionCache\cf0 reflectionCache)\par ??\tab \tab \{\par ??\tab \tab \tab \cf4 DatabaseConfigurationView\cf0 configurationView = \cf3 new\cf0 \cf4 DatabaseConfigurationView\cf0 (configurationSource);\par ??\tab \tab \tab \cf4 ConnectionStringSettings\cf0 connectionStringSettings = configurationView.GetConnectionStringSettings(name);\par ??\tab \tab \tab \cf4 DbProviderMapping\cf0 mapping = configurationView.GetProviderMapping(name, connectionStringSettings.ProviderName);\par ??\par ??\tab \tab \tab \cf4 IDatabaseAssembler\cf0 assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);\par ??\tab \tab \tab \cf4 Database\cf0 database = assembler.Assemble(name, connectionStringSettings, configurationSource);\par ??\par ??\tab \tab \tab \cf3 return\cf0 database;\par ??\tab \tab \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; CreateObject(&lt;span style="color: #2b91af;"&gt;IBuilderContext&lt;/span&gt; context, &lt;span style="color: blue;"&gt;string&lt;/span&gt; name, &lt;span style="color: #2b91af;"&gt;IConfigurationSource&lt;/span&gt; configurationSource, &lt;span style="color: #2b91af;"&gt;ConfigurationReflectionCache&lt;/span&gt; reflectionCache)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DatabaseConfigurationView&lt;/span&gt; configurationView = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DatabaseConfigurationView&lt;/span&gt;(configurationSource);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;ConnectionStringSettings&lt;/span&gt; connectionStringSettings = configurationView.GetConnectionStringSettings(name);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DbProviderMapping&lt;/span&gt; mapping = configurationView.GetProviderMapping(name, connectionStringSettings.ProviderName);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;IDatabaseAssembler&lt;/span&gt; assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;Database&lt;/span&gt; database = assembler.Assemble(name, connectionStringSettings, configurationSource);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; database;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-6809764685022320982?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/6809764685022320982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=6809764685022320982' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6809764685022320982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/6809764685022320982'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/how-to-create-custom-database-with.html' title='How To Create Custom Database With Enterprise Library 2.0 Data Access Block'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UTl9xtmUmII/RbQhICH_-GI/AAAAAAAAAAM/F_oSA6T3BOY/s72-c/EntLi_DAAB_Config.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-4940017312421263801</id><published>2007-01-20T11:58:00.000-05:00</published><updated>2007-01-20T15:02:23.694-05:00</updated><title type='text'>Firebird ADO.NET Provider</title><content type='html'>Recently I have installed open source database Firebird and its ADO.NET provider. I was really impressed and thought this would definitely be my choice of database for future personal projects. I did run into a few things though.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1) The sample on &lt;a href="http://www.dotnetfirebird.org/"&gt;the web site&lt;/a&gt; mentioned that you can use the ADO.NET factory model as in the following:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red163\green21\blue21;\red0\green0\blue255;\red0\green128\blue0;}??\fs20 \par ?? \cf3 DbProviderFactory\cf0 factory = \cf3 DbProviderFactories\cf0 .GetFactory(\cf4 "FirebirdSql.Data.FirebirdClient"\cf0 );\par ?? \cf5 using\cf0 (\cf3 DbConnection\cf0 conn = factory.CreateConnection())\par ?? \{\par ?? \cf3 FbConnectionStringBuilder\cf0 sb = \cf5 new\cf0 \cf3 FbConnectionStringBuilder\cf0 ();\par ?? \cf6 // code omiited for brevity\par ??\cf0 \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;DbProviderFactory&lt;/span&gt; factory = &lt;span style="color: #2b91af;"&gt;DbProviderFactories&lt;/span&gt;.GetFactory(&lt;span style="color: #a31515;"&gt;"FirebirdSql.Data.FirebirdClient"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;using&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;DbConnection&lt;/span&gt; conn = factory.CreateConnection())&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;FbConnectionStringBuilder&lt;/span&gt; sb = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;FbConnectionStringBuilder&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// code omiited for brevity&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In order for this to work, you will need to modify the system.data section of the machine.config file:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red163\green21\blue21;\red255\green0\blue0;\red0\green0\blue0;}??\fs20 \par ??\cf1 &amp;lt;\cf3 system.data\cf1 &amp;gt;\par ?? &amp;lt;\cf3 DbProviderFactories\cf1 &amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 Odbc Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 System.Data.Odbc\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 .Net Framework Data Provider for Odbc\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 OleDb Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 System.Data.OleDb\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 .Net Framework Data Provider for OleDb\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 OracleClient Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 System.Data.OracleClient\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 .Net Framework Data Provider for Oracle\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 SqlClient Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 System.Data.SqlClient\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 .Net Framework Data Provider for SqlServer\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 SQL Server CE Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 Microsoft.SqlServerCe.Client\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 .NET Framework Data Provider for Microsoft SQL Server 2005 Mobile Edition\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 Microsoft.SqlServerCe.Client.SqlCeClientFactory, Microsoft.SqlServerCe.Client, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;\cf3 add\cf1 \cf4 name\cf1 =\cf0 "\cf1 Firebird Data Provider\cf0 "\cf1 \cf4 invariant\cf1 =\cf0 "\cf1 FirebirdSql.Data.FirebirdClient\cf0 "\cf1 \cf4 description\cf1 =\cf0 "\cf1 Firebird\cf0 "\cf1 \cf4 type\cf1 =\cf0 "\cf1 FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.0.1.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c\cf0 "\cf1 /&amp;gt;\par ?? &amp;lt;/\cf3 DbProviderFactories\cf1 &amp;gt;\par ?? &amp;lt;/\cf3 system.data\cf1 &amp;gt;}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;system.data&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;DbProviderFactories&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Odbc Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.Odbc&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;.Net Framework Data Provider for Odbc&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;OleDb Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.OleDb&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;.Net Framework Data Provider for OleDb&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.OleDb.OleDbFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;OracleClient Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.OracleClient&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;.Net Framework Data Provider for Oracle&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.OracleClient.OracleClientFactory, System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;SqlClient Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.SqlClient&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;.Net Framework Data Provider for SqlServer&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;System.Data.SqlClient.SqlClientFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;SQL Server CE Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Microsoft.SqlServerCe.Client&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;.NET Framework Data Provider for Microsoft SQL Server 2005 Mobile Edition&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Microsoft.SqlServerCe.Client.SqlCeClientFactory, Microsoft.SqlServerCe.Client, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;add&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Firebird Data Provider&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;invariant&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;FirebirdSql.Data.FirebirdClient&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;description&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Firebird&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient, Version=2.0.1.0, Culture=neutral, PublicKeyToken=3750abcc3150b00c&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;DbProviderFactories&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;system.data&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) The &lt;a href="http://www.firebirdsql.org/index.php?op=devel&amp;sub=engine&amp;amp;id=fb20_release"&gt;Firebird 2.0 Release&lt;/a&gt; note says that security feature is enhanced with password hashing. I was interested in seeing how the ADO.NET client sends credentials to the server to get authenticated so I started investigation using three of my favorite tools: Reflector, Windbg and SOS (if I had had an additional machine I could have used network monitor or something similar to sniff the packets of course). With Reflector, it's not difficult to find that the FirebirdSql.Data.Client.Gds.GdsDatabase.Attach() is the last method on the call chain to send the parameters from connection string to the database server:&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20 \par ?? \cf3 public\cf0 \cf3 void\cf0 Attach(DatabaseParameterBuffer dpb, \cf3 string\cf0 dataSource, \cf3 int\cf0 port, \cf3 string\cf0 database)\par ?? \{\par ?? \cf3 lock\cf0 (\cf3 this\cf0 )\par ?? \{\par ?? \cf3 try\par ??\cf0 \{\par ?? \cf3 this\cf0 .connection.Connect(dataSource, port, \cf3 this\cf0 .packetSize, \cf3 this\cf0 .charset);\par ?? \cf3 this\cf0 .Identify(database);\par ?? \cf3 this\cf0 .Send.Write(0x13);\par ?? \cf3 this\cf0 .Send.Write(0);\par ?? \cf3 this\cf0 .Send.Write(database);\par ?? \cf3 this\cf0 .Send.WriteBuffer(dpb.ToArray());\par ?? \cf3 this\cf0 .Send.Flush();\par ?? \cf3 try\par ??\cf0 \{\par ?? GdsGenericResponse response1 = (GdsGenericResponse)\cf3 this\cf0 .ReadResponse();\par ?? \cf3 this\cf0 .handle = response1.ObjectHandle;\par ?? \}\par ?? \cf3 catch\cf0 (IscException)\par ?? \{\par ?? \cf3 try\par ??\cf0 \{\par ?? \cf3 this\cf0 .connection.Disconnect();\par ?? \}\par ?? \cf3 catch\par ??\cf0 \{\par ?? \}\par ?? \cf3 throw\cf0 ;\par ?? \}\par ?? \}\par ?? \cf3 catch\cf0 (IOException)\par ?? \{\par ?? \cf3 this\cf0 .connection.Disconnect();\par ?? \cf3 throw\cf0 \cf3 new\cf0 IscException(0x14000197);\par ?? \}\par ?? \cf3 this\cf0 .serverVersion = \cf3 this\cf0 .GetServerVersion();\par ?? \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Attach(DatabaseParameterBuffer dpb, &lt;span style="color: blue;"&gt;string&lt;/span&gt; dataSource, &lt;span style="color: blue;"&gt;int&lt;/span&gt; port, &lt;span style="color: blue;"&gt;string&lt;/span&gt; database)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;lock&lt;/span&gt; (&lt;span style="color: blue;"&gt;this&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.connection.Connect(dataSource, port, &lt;span style="color: blue;"&gt;this&lt;/span&gt;.packetSize, &lt;span style="color: blue;"&gt;this&lt;/span&gt;.charset);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Identify(database);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Send.Write(0x13);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Send.Write(0);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Send.Write(database);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Send.WriteBuffer(dpb.ToArray());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Send.Flush();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; GdsGenericResponse response1 = (GdsGenericResponse)&lt;span style="color: blue;"&gt;this&lt;/span&gt;.ReadResponse();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.handle = response1.ObjectHandle;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (IscException)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.connection.Disconnect();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (IOException)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.connection.Disconnect();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; IscException(0x14000197);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;this&lt;/span&gt;.serverVersion = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.GetServerVersion();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There doesn't seem to be hashing or encryption code so I started debugging. In Windbg, I set a break point at the Attach() function:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:003&gt; !bpmd FirebirdSql.Data.FirebirdClient.dll FirebirdSql.Data.Client.Gds.GdsDatabase.Attach&lt;br /&gt;Found 1 methods...&lt;br /&gt;MethodDesc = 00a28c90&lt;br /&gt;Setting breakpoint: bp 00D62FA0 [FirebirdSql.Data.Client.Gds.GdsDatabase.Attach(FirebirdSql.Data.Common.DatabaseParameterBuffer, System.String, Int32, System.String)]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After the break point is hit, I print out the stack trace and the parameters passed:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; !clrstack -p&lt;br /&gt;OS Thread Id: 0xadc (0)&lt;br /&gt;ESP EIP &lt;br /&gt;0012f3c8 00d62fa0 FirebirdSql.Data.Client.Gds.GdsDatabase.Attach(FirebirdSql.Data.Common.DatabaseParameterBuffer, System.String, Int32, System.String)&lt;br /&gt;PARAMETERS:&lt;br /&gt;this = 0x013aa6c0&lt;br /&gt;dpb = 0x013aa70c&lt;br /&gt;dataSource = 0x013a9260&lt;br /&gt;port = 0x00000bea&lt;br /&gt;database = 0x013a906c&lt;br /&gt;&lt;br /&gt;0012f3d8 00d61f8c FirebirdSql.Data.FirebirdClient.FbConnectionInternal.Connect()&lt;br /&gt;PARAMETERS:&lt;br /&gt;this = 0x013aa67c&lt;br /&gt;&lt;br /&gt;0012f408 00d61c32 FirebirdSql.Data.FirebirdClient.FbConnection.Open()&lt;br /&gt;PARAMETERS:&lt;br /&gt;this = 0x013a02c0&lt;br /&gt;&lt;br /&gt;0012f438 00d601d3 FbTest.Program.GetJobCode()&lt;br /&gt;0012f478 00d600a9 FbTest.Program.Main(System.String[])&lt;br /&gt;PARAMETERS:&lt;br /&gt;args = 0x01381ccc&lt;br /&gt;&lt;br /&gt;0012f69c 79e88f63 [GCFrame: 0012f69c]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Let's just focus on the paramaeters passed to the Attach function, starting from "database":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; !do 0x013a906c&lt;br /&gt;Name: System.String&lt;br /&gt;MethodTable: 790fa3e0&lt;br /&gt;EEClass: 790fa340&lt;br /&gt;Size: 156(0x9c) bytes&lt;br /&gt;(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)&lt;br /&gt;String: &lt;font style="background-color: yellow"&gt;C:\Program Files\Firebird\Firebird_2_0\examples\empbuild\EMPLOYEE.FDB&lt;/font&gt;&lt;br /&gt;Fields:&lt;br /&gt;MT Field Offset Type VT Attr Value Name&lt;br /&gt;790fed1c 4000096 4 System.Int32 0 instance 70 m_arrayLength&lt;br /&gt;790fed1c 4000097 8 System.Int32 0 instance 69 m_stringLength&lt;br /&gt;790fbefc 4000098 c System.Char 0 instance 43 m_firstChar&lt;br /&gt;790fa3e0 4000099 10 System.String 0 shared static Empty&lt;br /&gt;&gt;&gt; Domain:Value 0014eb80:790d6584 &lt;&lt;&gt;&gt; Domain:Value 0014eb80:013813dc &lt;&lt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So that's just the database file path. "port" is an integer:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; ?0x00000bea&lt;br /&gt;Evaluate expression: 3050 = 00000bea&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;which shows that it uses tcp port number 3050 to communicate with the server. Next we move on to "dataSource":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; !do 0x013a9260&lt;br /&gt;Name: System.String&lt;br /&gt;MethodTable: 790fa3e0&lt;br /&gt;EEClass: 790fa340&lt;br /&gt;Size: 36(0x24) bytes&lt;br /&gt;(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)&lt;br /&gt;String: &lt;font style="background-color: yellow"&gt;localhost&lt;/font&gt;&lt;br /&gt;Fields:&lt;br /&gt;MT Field Offset Type VT Attr Value Name&lt;br /&gt;790fed1c 4000096 4 System.Int32 0 instance 10 m_arrayLength&lt;br /&gt;790fed1c 4000097 8 System.Int32 0 instance 9 m_stringLength&lt;br /&gt;790fbefc 4000098 c System.Char 0 instance 6c m_firstChar&lt;br /&gt;790fa3e0 4000099 10 System.String 0 shared static Empty&lt;br /&gt;&gt;&gt; Domain:Value 0014eb80:790d6584 &lt;&lt;&gt;&gt; Domain:Value 0014eb80:013813dc &lt;&lt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;which is server name "localhost". What's left now is the "dpb" parameter:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; !do 013aa70c&lt;br /&gt;Name: FirebirdSql.Data.Common.DatabaseParameterBuffer&lt;br /&gt;MethodTable: 00a2835c&lt;br /&gt;EEClass: 01078910&lt;br /&gt;Size: 16(0x10) bytes&lt;br /&gt;(C:\WINDOWS\assembly\GAC_MSIL\FirebirdSql.Data.FirebirdClient\2.0.1.0__3750abcc3150b00c\FirebirdSql.Data.FirebirdClient.dll)&lt;br /&gt;Fields:&lt;br /&gt;MT Field Offset Type VT Attr Value Name&lt;br /&gt;791098d8 40000c1 4 ...m.IO.MemoryStream 0 instance 013aa71c stream&lt;br /&gt;79104f64 40000c2 8 System.Boolean 0 instance 0 isLittleEndian&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Keep dumping the "stream" object referenced by "dpb":&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0:000&gt; !do 013aa71c&lt;br /&gt;Name: System.IO.MemoryStream&lt;br /&gt;MethodTable: 791098d8&lt;br /&gt;EEClass: 79109858&lt;br /&gt;Size: 52(0x34) bytes&lt;br /&gt;(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)&lt;br /&gt;Fields:&lt;br /&gt;MT Field Offset Type VT Attr Value Name&lt;br /&gt;790f9c18 4000184 4 System.Object 0 instance 00000000 __identity&lt;br /&gt;79177788 4001b1d 8 ...ream+ReadDelegate 0 instance 00000000 _readDelegate&lt;br /&gt;79177818 4001b1e c ...eam+WriteDelegate 0 instance 00000000 _writeDelegate&lt;br /&gt;7910ccf4 4001b1f 10 ...ng.AutoResetEvent 0 instance 00000000 _asyncActiveEvent&lt;br /&gt;790fed1c 4001b20 14 System.Int32 0 instance 1 _asyncActiveCount&lt;br /&gt;790fe3c8 4001b1c 55c System.IO.Stream 0 shared static Null&lt;br /&gt;&gt;&gt; Domain:Value 0014eb80:0139e07c &lt;&lt;&lt;br /&gt;79124418 4001bc7 18 System.Byte[] 0 instance 013aa75c _buffer&lt;br /&gt;790fed1c 4001bc8 1c System.Int32 0 instance 0 _origin&lt;br /&gt;790fed1c 4001bc9 20 System.Int32 0 instance 44 _position&lt;br /&gt;790fed1c 4001bca 24 System.Int32 0 instance 44 _length&lt;br /&gt;790fed1c 4001bcb 28 System.Int32 0 instance 256 _capacity&lt;br /&gt;79104f64 4001bcc 2c System.Boolean 0 instance 1 _expandable&lt;br /&gt;79104f64 4001bcd 2d System.Boolean 0 instance 1 _writable&lt;br /&gt;79104f64 4001bce 2e System.Boolean 0 instance 1 _exposable&lt;br /&gt;79104f64 4001bcf 2f System.Boolean 0 instance 1 _isOpen&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The "_buffer" should hold what's interesting to us:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;0:000&gt; db 013aa75c&lt;br /&gt;013aa75c 18 44 12 79 00 01 00 00-01 3a 04 78 0a 00 00 3f .D.y.....:.x...?&lt;br /&gt;013aa76c 04 03 00 00 00 30 04 4e-6f 6e 65 39 04 00 00 00 .....0.None9....&lt;br /&gt;013aa77c 0f 1c 06 53 59 53 44 42-41 1d 09 6d 61 73 74 65 ...SYSDBA..maste&lt;br /&gt;013aa78c 72 6b 65 79 00 00 00 00-00 00 00 00 00 00 00 00 rkey............&lt;br /&gt;013aa79c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................&lt;br /&gt;013aa7ac 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................&lt;br /&gt;013aa7bc 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................&lt;br /&gt;013aa7cc 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sure enough, we can see that the user id and password are in the buffer. And password is not hashed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-4940017312421263801?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/4940017312421263801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=4940017312421263801' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4940017312421263801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/4940017312421263801'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/firebird-adonet-provider.html' title='Firebird ADO.NET Provider'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-362796945673239800.post-741156396502986054</id><published>2007-01-19T18:54:00.000-05:00</published><updated>2007-01-19T19:44:17.000-05:00</updated><title type='text'>Starting to blog about .NET ...</title><content type='html'>I have finally decided to start blogging. This will be an interesting experience for me as I've never been a diary writer myself. I remember struggling with it when I was at young age. But I have been learning so much from reading other people's technical blogs that I thought not sharing mine would be too selfish. I do have a selfish incentive as well :-) When I come across certain problems that I have researched before, I sometimes find myself have to do the research again simply because I didn't document the first time.&lt;br /&gt;&lt;br /&gt;For the last 6 years or so, I have been working for a consulting company, which is focused on delivering Microsoft-centric solutions. As the company grows and I progress in the career path, I have found myself a minority in terms of working hard to keep up both breadth and depth in technologies. This would mean getting hands dirty all the time, which some of my peers in the consulting business just don't have a whole lot of time and passion for anymore.&lt;br /&gt;&lt;br /&gt;Being an architect, I have worked on numerous projects with my current company, ranging from COM/C++ to .NET gigs. With the exception of a few, I've had fun with most of them, be that a project of designing and building a customized framework, refactoring/salvaging a poorly-implemented and seemingly-hopeless application, or debugging/diagnosing bugs and performance issues in production environment. Nothing beats the gratification of delivering a successful solution and/or solving the problems for the customers and making them happy in the end.&lt;br /&gt;&lt;br /&gt;So with that, I hope that I can start leveraging this blog to share my experiences and knowledge with the community. I think I will have fun doing this and I hope you will find it interesting too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/362796945673239800-741156396502986054?l=tigerang.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tigerang.blogspot.com/feeds/741156396502986054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=362796945673239800&amp;postID=741156396502986054' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/741156396502986054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/362796945673239800/posts/default/741156396502986054'/><link rel='alternate' type='text/html' href='http://tigerang.blogspot.com/2007/01/starting-to-blog-about-net.html' title='Starting to blog about .NET ...'/><author><name>Hugh Ang</name><uri>http://www.blogger.com/profile/09609747815666754891</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
