<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>NetQuarry &#187; Blog</title>
	<atom:link href="http://www.netquarry.com/index.php/category/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.netquarry.com</link>
	<description>The Enterprise Application Platform</description>
	<lastBuildDate>Wed, 21 Apr 2010 18:30:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Chrome 2.0 and Browser Compatibility</title>
		<link>http://www.netquarry.com/index.php/2009/06/chrome-20-and-browser-compatibility-10332/</link>
		<comments>http://www.netquarry.com/index.php/2009/06/chrome-20-and-browser-compatibility-10332/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 19:05:56 +0000</pubDate>
		<dc:creator>Cam Woods</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Browsers]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Platform]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/index.php/2009/06/chrome-20-and-browser-compatibility-10332/</guid>
		<description><![CDATA[Chrome 2.0 renders some tables with empty content.  Here's the fix and why the NetQuarry platform insulates its clients from browser compatibility problems.]]></description>
			<content:encoded><![CDATA[<p>Google Chrome 2.0 was released recently.&#160; We’re big fans of Chrome.&#160; It’s fast, maximizes screen real estate, and, overall, very compatible.&#160; When Chrome 1.0 rolled out we found very few incompatibilities with it.&#160; Our platform, and applications developed on our platform, looked great on Chrome 1.0 with few or no changes.</p>
<p>Unfortunately <strong>Chrome 2.0 rolled out with some significant rendering problems.</strong>&#160; Actually it looks to us like it might be just one problem, but with wide-ranging repercussions.&#160; Essentially a lot of pages get rendered with a lot of missing content – blank tables!&#160; For the NetQuarry platform the result was that our Datasheet (a very functional bound data grid) was rendered in Chrome 2.0 as an empty grid.&#160; A few icon buttons rendered, but the text content was gone!&#160; One day we were on Chrome 1.x and everything was fine, and the next day Chrome 2.0 was pushed out to us (like it or not) and voila! </p>
<p>After quickly verifying that it was a Chrome 2.0-specific problem, we did some Googling.&#160; We expected to find lots of people complaining about this and some quick help on a fix or workaround.&#160; Surprisingly there didn’t seem to be a widespread uproar.&#160; We did find that it was a known problem and that lots of main stream sites were essentially unusable with Chrome 2.0 (<a href="http://code.google.com/p/chromium/issues/detail?id=9904">http://code.google.com/p/chromium/issues/detail?id=9904</a>).&#160; Apparently the list of affected sites includes Facebook, Twitter, WordPress, and even Google Calendar. Unfortunately my search turned up no tips on what to do about it.&#160; It seemed to be some kind of clipping problem that was found before Chrome 2.0 was pushed out to general distribution, but not fixed until after that (or in subsequent releases so far).&#160; Seeing that the problem was so widespread we decided to wait a few days assuming that Google would push out a fix.&#160; A few days later Chrome v2.0.172.31 was pushed out, but lo and behold, the problem persisted.</p>
<p>After a few more days, and customer complaints, we decided that we couldn’t wait.&#160; We did some testing on our datasheet and more Googling and found this Chrome issue (<a href="http://code.google.com/p/chromium/issues/detail?id=13333">http://code.google.com/p/chromium/issues/detail?id=13333</a>) which matched our problem exactly.&#160; What’s more it gave us a suitable workaround.&#160; Five minutes later we had the fix in test and shortly after that it was checked in and ready for the next build.&#160; Here’s our thanks to <a href="http://code.google.com/u/terrybarthdesign/">terrybarthdesign</a> for providing the workaround.&#160; In short, <strong>Chrome 2.0 does not like the overflow:hidden style on a tr tag</strong>.&#160; With the overflow hidden the entire table row content is not rendered.&#160; The content is there in the HTML and sometimes flashes briefly when the page is first rendered, but it doesn’t render.</p>
<p>The frustrating thing about this was that it was actually pretty hard to find this.&#160; We tried Googling on things like “empty table Chrome 2.0”, “missing data Chrome”, “blank grid Chrome”, and about every combination of similar keywords that we could think of and it wasn’t until late last night that we stumbled upon the issue report from <a href="http://code.google.com/u/terrybarthdesign/">terrybarthdesign</a>.</p>
<p>There are really two purposes for this post.&#160; The first is to hopefully help someone else stumble onto a way to resolve a very significant problem.&#160; The second, is to point out that the great thing about a platform like NetQuarry is that we, NetQuarry, spent our time figuring this out – once.&#160; Our clients don’t have to worry about it.&#160; Well, they had to worry about it until we fixed it of course, but we investigated and determined it was a Chrome bug, we explained what was going on, we experimented, tested, researched, and provided a fix in our platform – and all our clients benefited.&#160; Today or tomorrow we’ll be releasing a new version of the platform (which was coming regardless) and it will have this fix.&#160; Our clients won’t have to do a thing except install the new platform.&#160; They won’t have to change their code one iota.</p>
<p><strong>The NetQuarry platform supports all recent versions of Chrome, Firefox, Safari, Opera, and IE 6, 7, and 8.</strong>&#160; The platform takes care of all the browser differences with no overhead for our clients.&#160; And, when a supported browser releases a new version, NetQuarry makes sure that the platform is completely compatible.&#160; Better yet, the platform is engineered to ensure that such breakage rarely occurs.&#160; The platform is designed not just for compatibility with the latest version of each browser, but for forward compatibility as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/06/chrome-20-and-browser-compatibility-10332/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>IssueTrak Movie</title>
		<link>http://www.netquarry.com/index.php/2009/04/issuetrak-movie-10304/</link>
		<comments>http://www.netquarry.com/index.php/2009/04/issuetrak-movie-10304/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 01:31:39 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[demo]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=304</guid>
		<description><![CDATA[We've just uploaded a short, recorded demo of building the IssueTrak application. The demo is available from the homepage (click on the large, friendly blue button) or by  (<a href="http://www.netquarry.com/wp-content/themes/netquarry/flash/IssueTrak1.html">clicking here</a>).

]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve just uploaded a short, recorded demo of building the IssueTrak application. The demo is available from the homepage (click on the large, friendly blue button) or by  (<a href="http://www.netquarry.com/wp-content/themes/netquarry/flash/IssueTrak1.html">clicking here</a>).</p>
<p>The movie demonstrates how you can quickly generate a working application that is not only completely functional, but looks great as well. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/04/issuetrak-movie-10304/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Configure SSL Host Headers in IIS 6</title>
		<link>http://www.netquarry.com/index.php/2009/03/how-to-configure-ssl-host-headers-in-iis-6-10297/</link>
		<comments>http://www.netquarry.com/index.php/2009/03/how-to-configure-ssl-host-headers-in-iis-6-10297/#comments</comments>
		<pubDate>Fri, 06 Mar 2009 00:05:20 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/index.php/2009/03/how-to-configure-ssl-host-headers-in-iis-6-10297/</guid>
		<description><![CDATA[At NetQuarry, we write software. We sell a software product &#8211; the NetQuarry Platform &#8211; that we wrote and own and we support the customers that use our product. Software. That’s it. So, it may seem a little surprising that a blog about IIS and SSL is even here, and more surprising, especially if you [...]]]></description>
			<content:encoded><![CDATA[<p>At NetQuarry, we write <strong>software.</strong> We sell a software product &#8211; the NetQuarry Platform &#8211; that we wrote and own and we support the customers that use our product. Software. That’s it. So, it may seem a little surprising that a blog about IIS and SSL is even here, and more surprising, especially if you know me, that I’m the one writing about it. </p>
<p>We recently wanted to install an SSL certificate on our main build server so that multiple sites hosted on that server could (and in some cases must) use SSL. So, I bought a $199 “wildcard” certificate from <a href="http://www.godaddy.com">GoDaddy.com</a> and installed it onto our Windows 2003 / IIS 6.0 build machine. Everything worked until I tried to add the same certificate to multiple sites on the same server. I started searching for an answer &#8211; “SSL certificate IIS subdomain multiple” and found that it wasn’t possible. Host headers – the thing you use to allow one IP address to act like different sites – doesn’t work with IIS 6.0. </p>
<p>I eventually bumped into this article: <a href="http://www.sslshopper.com/article-how-to-configure-ssl-host-headers-in-iis-6.html">http://www.sslshopper.com/article-how-to-configure-ssl-host-headers-in-iis-6.html</a> that solved the problem. Turns out it’s pretty simple, but you can’t do it using the MMC IIS snap-in. </p>
<p>Here’s the script (run from /inetpub/adminscripts):</p>
<p><span style="text-align: left; widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: italic 13px arial; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(51,51,51); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0" class="Apple-style-span">cscript.exe adsutil.vbs set /w3svc/<strong>&lt;site ID&gt;</strong>/SecureBindings &quot;:443:<strong>&lt;host header&gt;</strong>&quot;</span></p>
<p>Note that I found that you had to install your wildcard certificate, run the script, and restart IIS before everything worked.</p>
<p>Ryan</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/03/how-to-configure-ssl-host-headers-in-iis-6-10297/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Master Pages, AJAX, and Javascript</title>
		<link>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/</link>
		<comments>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 00:19:48 +0000</pubDate>
		<dc:creator>Cam Woods</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Platform]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-2-10292/</guid>
		<description><![CDATA[We recently decided to add support for MasterPages to the NetQuarry Enterprise Application Platform. The platform provides a set of .aspx “templates” that are used to host content in various configurations. The standard templates include Wizard, Console, and several flavors of Subform templates as well as support for custom templates. The basic idea is to [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">We recently decided to add support for MasterPages to the NetQuarry Enterprise Application Platform.<span style="mso-spacerun: yes"> </span>The platform provides a set of .aspx “templates” that are used to host content in various configurations.<span style="mso-spacerun: yes"> </span>The standard templates include Wizard, Console, and several flavors of Subform templates as well as support for custom templates.<span style="mso-spacerun: yes"> </span>The basic idea is to support hosting templates in .master pages.<span style="mso-spacerun: yes"> </span>Note that NetQuarry is currently using .Net 2.0. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">Everything started out well enough.<span style="mso-spacerun: yes"> </span>I created a master page called minimal.master and added it to my project.<span style="mso-spacerun: yes"> </span>The .master file was very simple:</span></span><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold"> </span> </span></p>
<p class="Code"><span style="background: yellow; mso-highlight: yellow">&lt;%</span>@ <span style="color: #a31515">Master</span> <span style="color: red">Language</span>=&#8221;C#&#8221; <span style="color: red">AutoEventWireup</span>=&#8221;true&#8221; <span style="color: red">CodeBehind</span>=&#8221;minimal.master.cs&#8221; <span style="color: red">Inherits</span>=&#8221;NetQuarry.minimal&#8221; <span style="background: yellow; mso-highlight: yellow">%&gt; </span></p>
<p class="Code"><span style="background: yellow; mso-highlight: yellow">&lt;%</span>@ <span style="color: #a31515">Register</span> <span style="color: red">TagPrefix</span>=&#8221;eap&#8221; <span style="color: red">Namespace</span>=&#8221;NetQuarry.WebControls&#8221; <span style="color: red">Assembly</span>=&#8221;EAP.WebControls&#8221; <span style="background: yellow; mso-highlight: yellow">%&gt; </span></p>
<p class="Code">&lt;!<span style="color: #a31515">DOCTYPE</span> <span style="color: red">HTML</span> <span style="color: red">PUBLIC</span> &#8220;-//W3C//DTD HTML 4.0 Transitional//EN&#8221; &gt;</p>
<p class="Code">&lt;<span style="color: #a31515">html</span> <span style="color: red">xmlns</span>=&#8221;http://www.w3.org/1999/xhtml&#8221; &gt;<br />
&lt;<span style="color: #a31515">head</span> <span style="color: red">runat</span>=&#8221;server&#8221;&gt;<br />
<span style="mso-tab-count: 1"> </span>&lt;<span style="color: #a31515">title</span> <span style="color: red">runat</span>=&#8221;server&#8221; <span style="color: red">id</span>=&#8221;pageTitle&#8221;&gt;Untitled Page&lt;/<span style="color: #a31515">title</span>&gt;<br />
<span style="mso-spacerun: yes"> </span>&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">ContentPlaceHolder</span> <span style="color: red">id</span>=&#8221;header&#8221; <span style="color: red">runat</span>=&#8221;server&#8221;&gt;<br />
<span style="mso-spacerun: yes"> </span>&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">ContentPlaceHolder</span>&gt;<br />
&lt;/<span style="color: #a31515">head</span>&gt;</p>
<p class="Code">&lt;<span style="color: #a31515">body</span> <span style="color: red">runat</span>=&#8221;server&#8221; <span style="color: red">id</span>=&#8221;body&#8221; <span style="color: red">class</span>=&#8221;background&#8221;&gt;<br />
<span style="mso-tab-count: 1"> </span>&lt;<span style="color: #a31515">esp</span>:<span style="color: #a31515">ContentPlaceHolder</span> <span style="color: red">id</span>=&#8221;content&#8221; <span style="color: red">runat</span>=&#8221;server&#8221;/&gt;<br />
&lt;/<span style="color: #a31515">body</span>&gt;<br />
&lt;/<span style="color: #a31515">html</span>&gt;</p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">I made a few quick modifications to my templates wrapping my original header and body contents in appropriate asp:Content controls:</span></span><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold"> </span> </span></p>
<p class="Code">&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span> <span style="color: red">ID</span>=&#8221;header&#8221; <span style="color: red">ContentPlaceHolderID</span>=&#8221;header&#8221; <span style="color: red">runat</span>=&#8221;Server&#8221;&gt;<br />
&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span>&gt;</p>
<p class="Code">&lt;<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span> <span style="color: red">ID</span>=&#8221;content&#8221; <span style="color: red">ContentPlaceHolderID</span>=&#8221;content&#8221; <span style="color: red">runat</span>=&#8221;Server&#8221;&gt;<br />
&lt;/<span style="color: #a31515">asp</span>:<span style="color: #a31515">Content</span>&gt;</p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">A bit more tweaking, the basics were there, but I still had problems.<span style="mso-spacerun: yes"> </span>The big problem was that the NetQuarry platform is used to create web applications, not web sites.<span style="mso-spacerun: yes"> </span>Our applications include a fair amount of javascript and  AJAX and using master pages had broken lots of script.<span style="mso-spacerun: yes"> </span>It didn’t take long for me to figure out that the main problem was that all my client-side elements now had mangled names.<span style="mso-spacerun: yes"> </span>For example, instead of a textbox being named something like “first_name”, it was being rendered into the HTML as “ctl00_content_first_name”.<span style="mso-spacerun: yes"> </span>This mangling broke our script, and badly. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">The cause of the mangling is the .Net NamingContainer idea.<span style="mso-spacerun: yes"> </span>NamingContainers allow a page to host multiple instances of an object by automatically generating unique client-side names that represent the control hierarchy on the server.<span style="mso-spacerun: yes"> </span>In this case, the MasterPage class itself was a NamingContainer as well as the ContentPlaceHolder control.<span style="mso-spacerun: yes"> </span>Since I hadn’t provided an ID for my MasterPage .Net named it ctl00.<span style="mso-spacerun: yes"> </span>I had named the ContentPlaceHolder for the main page content “content”.<span style="mso-spacerun: yes"> </span>So, since my existing page content was all contained in the “content” ContentPlaceHolder and it was in turn contained in the “ctl00” MasterPage, .Net composed a unique client-side name for the any control in the “content”<span style="mso-spacerun: yes"> </span>prefixed with “ctl00_content_” and, voila, broken script. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">Now NamingContainers are a great feature of .Net and they allow a lot of things to work seamlessly.<span style="mso-spacerun: yes"> </span>However, in this case I didn’t want any stinking NamingContainers.<span style="mso-spacerun: yes"> </span>Unfortunately, there’s no way to turn off the NamingContainer feature of any control marked as a NamingContainer (a control is marked as a NamingContainer by deriving from the INamingContainer marker interface).<span style="mso-spacerun: yes"> </span><span style="mso-spacerun: yes"> </span>Hint to Microsoft, this would be a good feature. </span> </span></p>
<p class="MsoNormal"><span class="articletitle1"><span style="font-family: &quot;Verdana&quot;,&quot;sans-serif&quot;; color: #333333; font-size: 10pt; font-weight: normal; mso-bidi-font-weight: bold">I actually spent about two days fighting with this and scouring the internet to see if anyone else had come up with a solution.<span style="mso-spacerun: yes"> </span>I did find several partial solutions that helped me move in the right direction.<span style="mso-spacerun: yes"> </span>First there was a good article about MasterPages in general on <a href="http://www.odetocode.com/"><span style="mso-bidi-font-weight: normal">www.OdeToCode.com</span></a> –</span></span><span class="articletitle1"><span style="color: #333333; font-size: 13pt"> </span></span><a href="http://www.odetocode.com/articles/450.aspx">ASP.Net 2.0 &#8211; Master Pages: Tips, Tricks, and Traps</a>.<span style="mso-spacerun: yes"> </span>A bit more digging and I found a partial solution on Rick Strahl’s Web Log – <a href="http://www.west-wind.com/WebLog/posts/4605.aspx">Overriding ClientID and UniqueID on ASP.NET controls</a>.<span style="mso-spacerun: yes"> </span>I’ve found Rick’s blog to be very helpful in the past.<span style="mso-spacerun: yes"> </span>And, that article pointed me to one other helpful blog on glJakal blog – <a href="http://www.gljakal.com/blog/2007/09/12/getting-rid-of-the-naming-container-in-aspnet-20/">Getting rid of the Naming Container in asp.net 2.0</a>.</p>
<p class="MsoNormal">Together these articles showed how to defeat the NamingContainer for client-side naming.<span style="mso-spacerun: yes"> </span>The full code of the final solution is below, but defeating the NamingContainer for client-side id mangling involved overriding the ClientID, UniqueID, and ID properties on the MasterPage and ContentPlaceHolder classes to return null, and the NamingContainer property on the ContentPlaceHolder class to return null.<span style="mso-spacerun: yes"> </span>With that my pages rendered well and my javascript worked!</p>
<p class="MsoNormal">Alas, what didn’t work was any postbacks.<span style="mso-spacerun: yes"> </span>The problem was that the id’s of the client-side controls no longer matched the control hierarchy on the server!<span style="mso-spacerun: yes"> </span>It didn’t take me long to figure out that what I needed to do was figure out a way to make the server-side control hierarchy match my client-side naming.<span style="mso-spacerun: yes"> </span>Essentially this meant making the server-side hierarchy look like my pre-MasterPage hierarchy, as far as NamingContainers go that is.<span style="mso-spacerun: yes"> </span></p>
<p class="MsoNormal">After a day of failed attempts, I was able to work out how to accomplish this.<span style="mso-spacerun: yes"> </span>The secret was to rearrange the control tree during the page PreInit event.<span style="mso-spacerun: yes"> </span>The PreInit event is available only to Page objects and is the only time that you can rearrange controls in the way I needed to.<span style="mso-spacerun: yes"> </span>Eventually I figured out that two things needed to be done: 1) move the controls out of the MasterPage and ContentPlaceHolder controls so that .Net can match up the server-side controls with the unmangled client-side id’s, and 2) leave the controls in the MasterPage and ContentPlaceHolder controls for rendering purposes so that the contents are rendered correctly with respect to other elements in the MasterPage.</p>
<p class="MsoNormal"><strong>May 20, 2009 update:</strong> Thanks to Ritchie Annand for discovering a problem in the original code when run with .Net tracing enabled (via the &lt;trace&gt; tag) and pointing the way to a fix.  The code now includes a fix to ensure that all hosted controls get an ID which is required when tracing (see the call to AssignIDs() in TemplateMaster::OnPreRender()).  Note that there is still a glitch that affects our platform under certain circumstances when .Net tracing is enabled and <em>pageOutput </em>is turned on.</p>
<p class="MsoNormal">To use the code below you need to do just a few things:</p>
<ul style="margin-top: 0in" type="disc">
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Include the code below in your project,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Derive your master page from TemplateMaster instead of MasterPage,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">Use the &lt;eap:ContentPlaceHolder&gt; tag in place of &lt;asp:ContentPlaceHolder&gt;,</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">In your master page .designer file, use the new ContentPlaceHolder instead of the .Net ContentPlaceHolder, and</li>
<li class="MsoNormal" style="mso-list: l0 level1 lfo1; tab-stops: list .5in">In your page’s PreInit event, call the TemplateMaster.Rehost() method, something like this:<span style="mso-spacerun: yes"> </span></li>
</ul>
<p><!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreInit(EventArgs e)
{
    <span class="rem">//--- Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
    <span class="rem">//--- Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
    <span class="rem">//--- these controls on the server. </span>

    <span class="kwrd">if</span> (<span class="kwrd">this</span>.Master <span class="kwrd">is</span> TemplateMaster)
    {
        (<span class="kwrd">this</span>.Master <span class="kwrd">as</span> TemplateMaster).Rehost();
    } 

    <span class="kwrd">base</span>.OnPreInit(e);
}</pre>
<p class="MsoNormal">And finally, here’s the code:</p>
<p><!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="rem">//---------------------------------------------------------------------------------------</span>
<span class="rem">// Copyright (c) 2005-2009 by NetQuarry, Inc.</span>
<span class="rem">// All rights reserved.</span>
<span class="rem">//</span>
<span class="rem">// Licensed under the Eiffel Forum License, version 2:</span>
<span class="rem">//</span>
<span class="rem">// 1. Permission is hereby granted to use, copy, modify and/or</span>
<span class="rem">// distribute this package, provided that:</span>
<span class="rem">// * copyright notices are retained unchanged,</span>
<span class="rem">// * any distribution of this package, whether modified or not,</span>
<span class="rem">// includes this license text.</span>
<span class="rem">// 2. Permission is hereby also granted to distribute binary programs</span>
<span class="rem">// which depend on this package. If the binary program depends on a</span>
<span class="rem">// modified version of this package, you are encouraged to publicly</span>
<span class="rem">// release the modified version of this package.</span>
<span class="rem">//</span>
<span class="rem">// THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR</span>
<span class="rem">// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED</span>
<span class="rem">// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE</span>
<span class="rem">// DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY</span>
<span class="rem">// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</span>
<span class="rem">// DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.</span>
<span class="rem">//</span>
<span class="rem">// www.netquarry.com</span>
<span class="rem">//---------------------------------------------------------------------------------------</span>

<span class="kwrd">using</span> System;
<span class="kwrd">using</span> System.Web;
<span class="kwrd">using</span> System.Web.UI;
<span class="kwrd">using</span> System.Web.UI.WebControls;
<span class="kwrd">using</span> System.Web.UI.HtmlControls;
<span class="kwrd">using</span> System.Text;
<span class="kwrd">using</span> System.Collections.Generic;

[assembly: TagPrefix(<span class="str">"NetQuarry.WebControls"</span>, <span class="str">"eap"</span>)]

<span class="kwrd">namespace</span> NetQuarry.WebControls
{
    <span class="rem">/// &lt;summary&gt; </span>
    <span class="rem">/// Base class that must be used for any master page hosting platform templates. </span>
    <span class="rem">/// &lt;/summary&gt; </span>
    <span class="kwrd">public</span> <span class="kwrd">abstract</span> <span class="kwrd">class</span> TemplateMaster : System.Web.UI.MasterPage
    {
        <span class="kwrd">private</span> <span class="kwrd">class</span> ContentContainer : Control
        {
            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Render(HtmlTextWriter writer)
            {
                <span class="rem">//base.Render(writer);  // Ignore the normal render. </span>
            }

            <span class="kwrd">public</span> <span class="kwrd">void</span> ExternalRender(HtmlTextWriter writer)
            {
                <span class="kwrd">base</span>.Render(writer);    <span class="rem">// Now render! </span>
            }

            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnPreRender(EventArgs e)
            {
                <span class="kwrd">base</span>.OnPreRender(e);

                <span class="kwrd">int</span> nIDIndex = 0;

                AssignIDs(<span class="kwrd">this</span>, <span class="kwrd">this</span>.ID, <span class="kwrd">ref</span> nIDIndex);
            }

            <span class="rem">/// &lt;summary&gt;</span>
            <span class="rem">/// In .Net TRACE enabled every control in the hierarchy MUST have and ID and our juggling rehosting </span>
            <span class="rem">/// controls messes up .Net's id assignment.  Here we recursively search through the specified control</span>
            <span class="rem">/// and provide unique ID's to any controls so lacking.</span>
            <span class="rem">/// &lt;/summary&gt;</span>
            <span class="rem">/// &lt;param name="ctrl"&gt;The control whose hierarchy should be scanned and assigned.&lt;/param&gt;</span>
            <span class="rem">/// &lt;param name="baseName"&gt;The base name for any subcontrols.&lt;/param&gt;</span>
            <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when assigning a unique ID.&lt;/param&gt;</span>
            <span class="kwrd">private</span> <span class="kwrd">void</span> AssignIDs(Control ctrl, <span class="kwrd">string</span> baseName, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
            {
                <span class="kwrd">if</span> (<span class="kwrd">string</span>.IsNullOrEmpty(ctrl.ID))
                {
                    ctrl.ID = baseName + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                    idIndex++;
                }

                <span class="kwrd">if</span> (ctrl.Controls != <span class="kwrd">null</span>)
                {
                    <span class="kwrd">foreach</span> (Control child <span class="kwrd">in</span> ctrl.Controls)
                    {
                        AssignIDs(child, baseName, <span class="kwrd">ref</span> idIndex);
                    }
                }
            }
        }

        <span class="kwrd">private</span> <span class="kwrd">class</span> ContentRenderer : Control
        {
            ContentContainer _container = <span class="kwrd">null</span>;

            <span class="kwrd">public</span> ContentRenderer(ContentContainer container)
            {
                _container = container;
            }

            <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Render(HtmlTextWriter writer)
            {
                <span class="kwrd">if</span> (_container != <span class="kwrd">null</span>) _container.ExternalRender(writer); <span class="rem">// Ask associated container to render. </span>
            }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ClientID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ClientID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null UniqueID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> UniqueID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net MasterPage being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
            set { <span class="kwrd">base</span>.ID = <span class="kwrd">value</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
        <span class="rem">/// these controls on the server.  </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="rem">/// &lt;param name="parent"&gt;The parent control whose children should be rehosted.&lt;/param&gt;</span>
        <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when providing ID's to controls so lacking.&lt;/param&gt;</span>
        <span class="kwrd">private</span> <span class="kwrd">void</span> MoveControlsToPage(Control parent, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
        {
            <span class="kwrd">if</span> (<span class="kwrd">base</span>.Page != <span class="kwrd">null</span> &amp;&amp; <span class="kwrd">this</span>.Controls.Count &gt; 0)
            {
                List&lt;Control&gt; lst = <span class="kwrd">new</span> List&lt;Control&gt;(<span class="kwrd">this</span>.Controls.Count);
                ContentContainer container = <span class="kwrd">new</span> ContentContainer();                <span class="rem">// Container will host the controls w/out a NamingContainer. </span>
                ContentRenderer renderer = <span class="kwrd">new</span> ContentRenderer(container);        <span class="rem">// Renderer will render contents of container. </span>

                <span class="rem">//--- In .Net TRACE enabled every control in the hierarchy MUST have</span>
                <span class="rem">//--- and ID and our juggling rehosting controls messes up .Net's id assignment.</span>

                container.ID = <span class="str">"ctlcont"</span> + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                renderer.ID = <span class="str">"ctlrend"</span> + idIndex.ToString().PadLeft(3, <span class="str">'0'</span>);
                idIndex++;

                <span class="rem">//--— Create collection of all controls to move.</span>

                <span class="kwrd">for</span> (<span class="kwrd">int</span> ii = 0; ii &lt; parent.Controls.Count; ii++)
                {
                    lst.Add(parent.Controls[ii]);
                }

                <span class="rem">//--— Determine index of this container. </span>

                Control root = parent;

                <span class="kwrd">while</span> (root != <span class="kwrd">null</span> &amp;&amp; root.Parent != <span class="kwrd">null</span> &amp;&amp; !(root.Parent <span class="kwrd">is</span> Page))
                {
                    root = root.Parent;
                }

                <span class="kwrd">int</span> nIndex = (root == <span class="kwrd">null</span>) ? -1 : root.Parent.Controls.IndexOf(root);

                <span class="rem">//--— Remove controls from original parent and add them to new container. </span>

                <span class="kwrd">for</span> (<span class="kwrd">int</span> ii = 0; ii &lt; lst.Count; ii++)
                {
                    Control ctrl = lst[ii];

                    parent.Controls.Remove(ctrl);
                    container.Controls.AddAt(ii, ctrl);
                }

                <span class="rem">//--— Add new renderer to replace original controls and new container to the page itself. </span>
                <span class="rem">//—-- The container is used to extablish the control hierarchy and in this way collapsing  </span>
                <span class="rem">//—-- the MasterPage so that it doesn’t act as a NamingContainer for the purposes of the </span>
                <span class="rem">//—-- control hierarchy.  The container will ignore the control’s normal Render() method. </span>
                <span class="rem">//--— The renderer has no controls, just a reference to the container.  When the renderer’s </span>
                <span class="rem">//--— Render() method is called it will have the container render in its place.</span>

                parent.Controls.Add(renderer);                    <span class="rem">// Render controls as if contained in master. </span>
                Page.Controls.AddAt(nIndex + 1, container);        <span class="rem">// But host them flat on the page instead of nested in NamingContainers. </span>
            }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the </span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of </span>
        <span class="rem">/// these controls on the server.  </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="rem">/// &lt;param name="parent"&gt;The tree of controls from which to rehost.&lt;/param&gt;</span>
        <span class="rem">/// &lt;param name="idIndex"&gt;The ID index to use when providing ID's to controls so lacking.&lt;/param&gt;</span>
        <span class="kwrd">private</span> <span class="kwrd">void</span> RehostMasterControls(Control parent, <span class="kwrd">ref</span> <span class="kwrd">int</span> idIndex)
        {
            <span class="rem">//--— Find all ContentPlaceHolder controls and rehost the children to the page itself. </span>

            <span class="kwrd">foreach</span> (Control ctrl <span class="kwrd">in</span> parent.Controls)
            {
                <span class="kwrd">if</span> (ctrl <span class="kwrd">is</span> NetQuarry.WebControls.ContentPlaceHolder)
                {
                    MoveControlsToPage(ctrl, <span class="kwrd">ref</span> idIndex);        <span class="rem">// Rehost children to page. </span>
                }
                <span class="kwrd">else</span>
                {
                    RehostMasterControls(ctrl, <span class="kwrd">ref</span> idIndex);    <span class="rem">// Recurse. </span>
                }
            }
        }

        <span class="rem">/// &lt;summary&gt;</span>
        <span class="rem">/// Rehost controls from MasterPage/Content/ContentPlaceHolder hierarchy onto the</span>
        <span class="rem">/// Page itself.  This has the effect of cancelling the NamingContainer effect of</span>
        <span class="rem">/// these controls on the server. </span>
        <span class="rem">/// &lt;/summary&gt;</span>
        <span class="kwrd">public</span> <span class="kwrd">void</span> Rehost()
        {
            <span class="kwrd">int</span> nIDIndex = 0;        <span class="rem">// Need to provide unique ID's for controls so lacking.</span>

            RehostMasterControls(<span class="kwrd">this</span>.Page.Master, <span class="kwrd">ref</span> nIDIndex);
        }
    }

    <span class="rem">/// &lt;summary&gt; </span>
    <span class="rem">/// Replacement control for System.Web.UI.WebControls.ContentPlaceHolder for use when it is desired </span>
    <span class="rem">/// to NOT have the MasterPage, Content, and ContentPlaceHolder controls behave as naming </span>
    <span class="rem">/// containers.  There are two aspects to this: 1) the effect a NamingContainer has on the  </span>
    <span class="rem">/// client-side control NAME and ID mangling, and 2) the control hierarchy on the server. </span>
    <span class="rem">/// &lt;/summary&gt; </span>
    <span class="kwrd">public</span> <span class="kwrd">class</span> ContentPlaceHolder : System.Web.UI.WebControls.ContentPlaceHolder
    {
        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null NamingContainer. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> Control NamingContainer
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ClientID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ClientID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null UniqueID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> UniqueID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
        }

        <span class="rem">/// &lt;summary&gt; </span>
        <span class="rem">/// Defeat the effect of the .Net ContentPlaceHolder being a NamingContainer with regard </span>
        <span class="rem">/// to client-side NAME and ID attributes rendering by always returning a null ID. </span>
        <span class="rem">/// &lt;/summary&gt; </span>
        <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ID
        {
            get { <span class="kwrd">return</span> <span class="kwrd">null</span>; }
            set { <span class="kwrd">base</span>.ID = <span class="kwrd">value</span>; }
        }
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/03/master-pages-ajax-and-javascript-10292/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Fresh Beginnings</title>
		<link>http://www.netquarry.com/index.php/2009/02/fresh-beginnings-10267/</link>
		<comments>http://www.netquarry.com/index.php/2009/02/fresh-beginnings-10267/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 19:19:43 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Platform]]></category>
		<category><![CDATA[Versions]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/index.php/2009/02/fresh-beginnings-10267/</guid>
		<description><![CDATA[One of the things I hear myself saying nearly all the time sounds something like “if I were starting over&#8230;” If you make a living writing software, building websites, building databases, or writing reports you must have, on a regular basis, one of these moments.
For me, the reason I feel this way is because there [...]]]></description>
			<content:encoded><![CDATA[<p>One of the things I hear myself saying nearly all the time sounds something like “if I were starting over&#8230;” If you make a living writing software, building websites, building databases, or writing reports you must have, on a regular basis, one of these moments.</p>
<p>For me, the reason I feel this way is because there are always parts of an application that aren&#8217;t quite right. I&#8217;d like a chance to make it better.</p>
<p>Since this isn’t always possible we’ve made a huge effort to allow for a way to add and remove <em>parts </em>of your application in a simple, safe, and discoverable way. In fact, this idea of “feature versions” is a first class concept in the Platform.</p>
<p>A feature version allows you to add metadata and code and tag it with a name that won’t be available in your live application unless you enable the version. This works for all important metadata objects – pages, mappers, fields, and extensions. Because it works with extensions you can actually write code, add it to the build, installer, and publish it to your live site without any risk of the code kicking in before the feature is absolutely ready.</p>
<p>Feature versions allow you to make your Great New Feature – the one you got to “start over” on – show up at several levels. The simplest way is by setting the version on an extension – for example, say you’ve built Version 1.0 of a task queue feature and you’ve written an extension for Version 2.0 that does much, much more. In this scenario, you would set the MinVersion value on the ‘task’ version to 1 and the MaxVersion to 1. Then you set the MinVersion for the next extension to 2. </p>
<p>When you set the value of the version to 2 your new extensions automatically kicks in. Simple, safe. You’ve just started over.</p>
<p>If you <em>are </em>lucky enough to be starting a new project then you really, really should take a good look at the NetQuarry Platform <strong>today</strong>. Contrary to the popular thinking of project managers and software architects, custom applications do NOT require custom infrastructure. Really. Spend a few minutes with us – talk to <em>one </em>of our customers. It’ll be short. We promise.</p>
<p>NetQuarry – Start Right.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2009/02/fresh-beginnings-10267/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Are we there yet?</title>
		<link>http://www.netquarry.com/index.php/2007/09/are-we-there-yet-1020/</link>
		<comments>http://www.netquarry.com/index.php/2007/09/are-we-there-yet-1020/#comments</comments>
		<pubDate>Tue, 04 Sep 2007 01:25:17 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[Product]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=20</guid>
		<description><![CDATA[The thing that always surprises us is the fact that we have to do much of what we have to do to produce our product. The complexity of enterprise application development is startling. You basically need to be an expert on about 10 things just to get started.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been absorbed lately with the nagging question that keeps coming up every time I solve what I <em>thought</em> was going to be a simple problem &#8211; &#8220;Are we the only ones doing this?&#8221; This is followed by the more important question &#8211; &#8220;How is everyone else doing this?&#8221; At NetQuarry, we sell, effectively, answers to these questions. The problem, and the thing that always suprises me is the fact that we have to do much of what we have to do to produce our product. The complexity of enterprise application development is startling. You basically need to be an expert on about 10 things just to get started.</p>
<p>I&#8217;ve been personally involved in an enterprise architecture project for a well funded valley company (it was J2EE, to be fair) that had 100 people (including QA, Docs, and a <em>bunch</em> of managers) working for 2 years to implement an enterprise application architecture. We spent nearly 40 million dollars (seriously) on development. I&#8217;ve spoken to CTOs at software companies (ISVs) who are solving this and have arrived at the conclusion that nobody knows exactly where to start.</p>
<p>Most people in my position would roughly agree with me, at least in principle, but most would have a hard time citing real examples of why this is so hard. So, here are some examples:</p>
<p><strong>Simple example first &#8211; permissions. </strong></p>
<p>When you build an application of any reasonable complexity, you will have to architect and <em>implement</em> a way to authenticate users, retrieve a set of profiles (groups), and restrict access to parts of an application based on who the user is and which profiles have been assigned to them. How could you accomplish this? There are a ton of ideas out there. There is an idea of a database directory that .NET will build for you in SQL Server. There is a decent way to hook in Microsoft Passport authentication. There is a user/password/reset password control. There is the &#8220;forms based authentication&#8221; that takes a real time investment to understand and once you do you wish you hadn&#8217;t. What doesn&#8217;t exist anywhere is a reasonable way to consume the information you get from your authenticated users.</p>
<p>What also <em>doesn&#8217;t </em>exist (and this is the important bit) is a way for you to <em>declaratively </em>hide a column in a grid based on which user just logged in. Hold on, I&#8217;m going to explain.</p>
<p>Say I have a column in my DataView grid (say a salary column) that I only want users with the Administration Profile to see. Further, I want to define this by checking a little box somewhere that says &#8220;Hide from general users, please.&#8221; Then, I want that information stored in some persistent format that allows me to <strong>check it into source control</strong>. Asking too much? You might say this is easy. All you have to do is&#8230; build a file that holds the data, or put the data in a database (this sort of discussion ends relationships), write a little tool that edits the file or just screw with it yourself, store this file in source code, add it to your installation script, build a tool to change it inside your application (which you need to secure as well), copy it to the server before you go live, &#8230; Crazy.</p>
<p><strong>Another example  - filtering</strong></p>
<p>The .NET Framework and Visual Studio, along with the competition (J2EE, and the slew of tools available here) has a way to take data out of a database and present it in a grid. Generally there is a way to handle sorting, paging, hiding columns, and, of course, applying some sort of theme. However, what if you want to filter the list in some way? Simple, right? All you do is build another set of controls on the form for each column that you want to use in your filter. Some of the columns are foreign keys to other tables, so you&#8217;ll want to build some sort of interface to deal with these. Many of your foreign keys are really just lookup values, so you&#8217;ll want a way to build a DropDownList control with these values in it. Next, you&#8217;ll have to take the result of a postback on this form, determine if it has to do with your filter controls, and construct some sort of SQL filter for your database and re-display your list. If your users want to be able to filter on <em>multiple</em> values, well, then, its a bit harder. You&#8217;ll need either a new interface, or you&#8217;ll have to handle filters like: &#8220;BETWEEN x AND y&#8221; or &#8220;This Month&#8221; or &#8220;&gt;Today&#8221; or &#8220;=FRED&#8221; or &#8220;Starts With Fred&#8221; and likely a bunch of others.</p>
<p>The kicker &#8211; you have to do this with <strong>every </strong>grid. You&#8217;ll probably get clever and build a base class that reads information from the DataSource and builds some filtering capabilities. Once you&#8217;ve done this, you&#8217;ll think its pretty easy. Honestly, though, a full featured grid view with good filtering (forget about column wise permissions) is a bunch of work. Even if you are pretty good at this you&#8217;ll still have the problem of managing the thousands of foreign key lists. (Much more on this idea <a href="http://www.netquarry.com/?p=50">here</a>.) And, each one is just a little different. So, you probably end up with a bunch of pages all with slightly different code in them to change the properties of the particular page you are working with. At least you can check these into source control.</p>
<p><strong>Meaning?</strong></p>
<p>Enterprise application development is hard, really hard. Any way you look at it, you absolutely must solve most of these problems, even if you solve them poorly. Generally this is done by giving your Highly Paid talent the title of Architect and asking them to guide you through this process. If you are smart you&#8217;ll get two of these smart folks, because one smart guy alone will always come up with dumb ideas. If he is working by himself then you&#8217;ll usually end up implementing some of these ideas. Loosely quoting Brian DePalma &#8211; &#8220;Every time you think up a perfect architecture there are 50 ways to screw it up. If you think of 25 of them, you&#8217;re a genius.&#8221;</p>
<p>The solution always looks about like this:</p>
<ol>
<li>Hire 1 or 2 expensive people and let them think for 3-6 months.</li>
<li>Add a productive resource and start writing a low-level database access class library that wraps ADO.NET. or JDBC. This puts you 6-9 months into the project.</li>
<li>Add another productive resource and build a reasonable grid, detail view, and a simple navigation metaphor. You are at least 9 months into the task now.</li>
<li>Frantically add a bunch of not so productive (read, cheap) resources and tell them you are behind. Sometimes you send your application to India, China, or Iowa at this point.</li>
<li>Scramble for another 6 months or so until you begin slashing features as fast as you can.</li>
<li>Release your first version 18 months from the start of your project to resounding cries of disappointment and astonishment from your user base.</li>
</ol>
<p>This isn&#8217;t just me talking. There are well known research reports from respected analysts that assure us that more enterprise projects fail than don&#8217;t. Below, from <a href="http://www.softwaremag.com/L.cfm?Doc=newsletter/2004-01-15/Standish">Software Magazine</a>, a blurb on the Standish CHAOS report:</p>
<blockquote><p><em>&#8220;The 10th edition of the annual CHAOS report from The Standish Group, which researches the reasons for IT project failure in the United States, indicates that project success rates have increased to 34 percent of all projects. That’s more than a 100-percent improvement from the success rate found in the first study in 1994.&#8221;</em></p></blockquote>
<p>So, we&#8217;re getting better. Only 66% fail. I&#8217;m not suggesting that poor architecture implementation is the only reason projects fail. I&#8217;m betting that it isn&#8217;t even the leading <em>direct</em> cause. But I do know who gets blamed when the project doesn&#8217;t go correctly &#8211; the Highly Paid developers. And, I believe it isn&#8217;t necessary.</p>
<p><strong>Why hasn&#8217;t this been solved?</strong></p>
<p>I believe that eventually Microsoft will introduce enterprise infrastructure to the .NET Framework that solves a good chunk of this problem. What they have done so far is give us the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/entlib2.asp">Enterprise Library</a>, which solves some real problems, but is still, as its name suggests, a <em>library. </em>You&#8217;ll still need an implementation of an architecture <em>using</em> this library before you can start your application. Why the Enterprise Library isn&#8217;t directly part of .NET is another question. I <em>love </em>this quote:</p>
<blockquote><p><em>&#8220;Enterprise Library is a guidance offering, designed to be reused, customized, and extended. It is not a Microsoft product.&#8221;</em></p></blockquote>
<p>So, why hasn&#8217;t Microsoft solved this yet? I think they don&#8217;t want to offend anyone. When one implements an architecture you have to make choices that will cause concern and questions from almost any of the consumers. Where is the application metadata stored &#8211; relational database or the file system? Is the object mapping strictly typed or not? What is the external access strategy &#8211; Web Services? What about authentication? Permissions? Data Permissions? Deployment? Testing? Localization? Internationalization?</p>
<p>The other reason there isn&#8217;t any cohesive strategy around an implementation of an enterprise architecture is because there are a lot of people that get paid a lot of money who are pretty interested in continuing to get paid to design and implement terrible applications. If I had a choice between a year getting paid $200 (or more) an hour or simply using an available solution, it would be a simple choice.</p>
<p>The other problem is that depending on the group of people you are talking to, many are convinced that this problem can be solved by <em>using the right tools or selecting the correct grid control</em>. Really. I&#8217;ve spoken to presumably smart people who have told me that the problem with enterprise development is simply management process. This is generally followed by a conversation with someone who <em>knows</em> that if you would simply get the requirements right nothing would go wrong. Next, I&#8217;ll speak to an Architect who has landed on a architecture that is, in its entirety, .NET. And, of course, you can throw a rock and hit someone who believes that the answer is UML. The worst, of course, is this: &#8220;we&#8217;re using SOA.&#8221;</p>
<p><strong>I-got-a-good-idea</strong></p>
<p>NetQuarry is an <em>enterprise </em>application platform (for Microsoft .NET). What this means is that we have a layer of runtime code that reads a definition of your application at runtime and produces an ISV quality web-based application. The definition includes references to code that you write (extensions), profiles you declare, schema that you design, and presentation that you build. Much of the definition is built using our tooling (NetQuarry Studio). When you write your code you use Visual Studio, we&#8217;re not in the IDE business. <a href="http://www.netquarry.com/?page_id=7"> Read more here</a>.</p>
<p>The important point to understand about NetQuarry is that it is <em>both</em> an architecture and <em>an implementation </em>of an architecture. It is also important to understand what it is not. It is <strong>not</strong> a code generator and it is most decidedly <strong>not </strong>a framework.</p>
<p>We also think that the real promise of NetQuarry isn&#8217;t simply an architecture <em>with implementation</em>, but rather what you might do with this implementation once it becomes generally available. The largest idea is the concept of application content. What I mean by this is the availability of functional application parts that can be deployed into a platform (like NetQuarry). Real application assembly. Salesforce.com has done something like this with <a href="http://www.salesforce.com/developer/">AppExchange.</a> I like AppExchange but of course I can&#8217;t see how I&#8217;d use this to create <a href="http://www.optionease.com">OptionEase</a>, <a href="http://www.diforza.com/">DiForza</a>, or <a href="http://www.iluxcars.com/">iLUXCARS</a>. For these sorts of applications I have to build it myself. So, the content parts should be a bit less coupled with the application, which is hard, but possible, again, once we have a real implementation of a platform.</p>
<p>If you are interested in the NetQuarry platform or what you might be able to do with it please feel free to contact us: <a href="mailto:info@netquarry.com">info@netquarry.com</a>.</p>
<p>Ryan</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2007/09/are-we-there-yet-1020/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VisualBasic</title>
		<link>http://www.netquarry.com/index.php/2006/09/visualbasic-1037/</link>
		<comments>http://www.netquarry.com/index.php/2006/09/visualbasic-1037/#comments</comments>
		<pubDate>Thu, 14 Sep 2006 02:20:28 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Legacy]]></category>
		<category><![CDATA[Product]]></category>
		<category><![CDATA[Rant]]></category>
		<category><![CDATA[Visual Basic]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=37</guid>
		<description><![CDATA[It occurs to me, and not just because we write and sell a .NET product, that a good number of owners of large VB 6.0 applications are about to become a little nervous. As part of a proposal for one of these companies, I was tracking down the support dates and end-of-life statements by Microsoft about VB 6.0. It says, basically, that the Visual Basic runtime (or an updated version) will ship will Windows Vista and will be supported fully for 5 years, and not so fully for 5 more years after that.]]></description>
			<content:encoded><![CDATA[<p>It occurs to me, and not just because we write and sell a .NET product, that a good number of owners of large VB 6.0 applications are about to become a little nervous. As part of a proposal for one of these companies, I was tracking down the support dates and end-of-life statements by Microsoft about VB 6.0. It says, basically, that the Visual Basic runtime (or an updated version) will ship will Windows Vista and will be supported fully for 5 years, and not so fully for 5 more years after that.</p>
<p>The actual support of Visual Basic and Visual Studio 6.0 (in which VB 6.0 shipped) is over now. This sort of surprised me. I assumed that Microsoft would continue to support VB more or less forever, silly as that may sound. The actual dates for &#8220;support&#8221; are here: <a href="http://support.microsoft.com/lifecycle/search/?sort=PNα=Visual+Basic+6.0">Visual Basic Product Lifecycle</a>, and this says that real support ended 3/31/2005, and extended support will last until 4/8/2008.</p>
<p>I was a <em>long</em> time Visual Basic user &#8212; our last product used it as the extension language &#8212; and if I had a large VB 6.0 application, I would probably worry. I&#8217;m pretty sure that many VB 6.0 applications will continue to run. I&#8217;m also pretty sure that if they didn&#8217;t, and if they were mission critical, most enterprises would be able to find someone to tweak their application so that it would continue correctly.</p>
<p>What <em>would</em> worry me is less concrete. If you manage or develop an important product for a large enterprise and the language that the application was written in was out of official support, I&#8217;d start thinking that maybe it was time to think about a port. Why? If nothing else because anything large enough to worry about is likely to take until April of 2008 to get ported.</p>
<p>All of this is a somewhat shameless pitch for NetQuarry, of course. Actually, I don&#8217;t see how one would begin a reasonable port of a large Visual Basic application without at least the start of the infrastructure that we provide. Many of these applications are <strong>huge</strong> &#8212; e.g. 1000s of pages, tables, and complex rules. Most of the folks who built and probably deeply understand the application are off on other projects (presumably in a more modern language).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2006/09/visualbasic-1037/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web Projects and .NET 2.0</title>
		<link>http://www.netquarry.com/index.php/2006/04/web-projects-and-net-20-1026/</link>
		<comments>http://www.netquarry.com/index.php/2006/04/web-projects-and-net-20-1026/#comments</comments>
		<pubDate>Sun, 30 Apr 2006 02:11:59 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[.NET 2.0]]></category>
		<category><![CDATA[Headache]]></category>
		<category><![CDATA[Rant]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=26</guid>
		<description><![CDATA[I've spent a frustrating day (again) attempting to setup a web project that is a sub-project of our main application. For whatever reason, I can't reference code in a referenced assembly unless I load it as a control reference and, at least in most cases, copy the referenced assembly to the main /bin folder.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve spent a frustrating day (again) attempting to setup a web project that is a sub-project of our main application. For whatever reason, I can&#8217;t reference code in a <strong>referenced </strong>assembly unless I load it as a control reference <em>and</em>, at least in most cases, copy the referenced assembly to the main /bin folder.</p>
<p>Works like this:</p>
<ol>
<li>NetQuarry is installed. The core assemblies are in the &lt;webroot&gt;/bin folder.</li>
<li>The application needs some custom controls (mostly for wizard pages).</li>
<li>The application wants to reference another custom assembly. To do this, we copy the assembly to the /bin folder of the new project. We include the reference and we can use the code in the debugger.</li>
<li>The application&#8217;s new web project is installed and developed in a sub-folder of NetQuarry. (&lt;webroot&gt;/Apps/&lt;myapp&gt;).</li>
<li>The code compiles, but you can&#8217;t load any of the custom controls because it can&#8217;t resolve the type.</li>
<li>On most machines (I can&#8217;t tell you why this isn&#8217;t <strong>all</strong> machines) all you have to do is add a reference in the .ASCX page like this:<br />
<span style="font-size: x-small;"> &lt;%</span><span style="color: #0000ff; font-size: x-small;">@</span><span style="font-size: x-small;"> </span><span style="color: #800000; font-size: x-small;">Register</span><span style="font-size: x-small;"> </span><span style="color: #ff0000; font-size: x-small;">TagPrefix</span><span style="color: #0000ff; font-size: x-small;">=&#8221;myappref&#8221;</span><span style="font-size: x-small;"> </span><span style="color: #ff0000; font-size: x-small;">Namespace</span><span style="color: #0000ff; font-size: x-small;">=&#8221;MyApp.Common&#8221;</span><span style="font-size: x-small;"> </span><span style="color: #ff0000; font-size: x-small;">Assembly</span><span style="color: #0000ff; font-size: x-small;">=&#8221;MyApp.Common&#8221;</span><span style="font-size: x-small;"> %&gt;</span></li>
<li>On other machines, you have to copy the referenced assembly to the <strong>root</strong> /bin folder.</li>
</ol>
<p>Incidentally, I&#8217;ve tried the new Web Application Project model to solve this and failed as well. Scott Guthrie has a good post about it: <a href="http://weblogs.asp.net/scottgu/archive/2005/12/07/432630.aspx">Web Application Projects</a> that you should read. The (really) good news about this new project model is that it compiles significantly faster. The bad news is that I have a similar reference problem when I try to create a web user control dynamically unless the assembly is copied to the &lt;webroot&gt;/bin folder.</p>
<p>So, why not just copy the sub-project .DLLs to the main /bin folder? Because I <em>really</em> don&#8217;t like it. In NetQuarry, sub-projects are loaded dynamically (a somewhat foreign concept to everything ASP, I know) and they don&#8217;t have a dependency on the main NetQuarry Web assembly. The idea is that one installs the core NetQuarry web, then builds their own web components (web user controls), references them as components using the NetQuarry Studio and uses them as PageElements to build wizards.</p>
<p>NetQuarry also loads extensions dynamically, which is exactly what we want to do with these web projects. So, I tried converting to the new Web Application Project model for sub-projects and loading the assemblies dynamically. Still didn&#8217;t work. Since these are web projects, you would think that the way to do this is in two steps: first, load the assembly, and second, load the user control via its virtual path. Once the assembly is loaded .NET <em>should </em>understand the types in the control but for some reason it doesn&#8217;t.</p>
<p>The idea behind NetQuarry is that you don&#8217;t have to know any of this stuff, but just so you know, the idea (that doesn&#8217;t work) is like this:</p>
<blockquote><p><span style="font-family: 'Courier New';">private IWizPage LoadWizardPage(NetQuarry.ComponentInfo ci)<br />
{<br />
    System.Reflection.Assembly asm = ci.LoadAssembly();<br />
    return LoadControl(ci.Component) as IWizPage;<br />
}</span></p></blockquote>
<p>Where the ComponentInfo.LoadAssembly method is a little complex (and ommitted here for brevity). Basically, we try and find it in the list of loaded assemblies first, then in the specified path, then in &lt;webroot&gt;/bin, and finally in Apps/&lt;appid&gt;/bin.</p>
<p>Turns out that after you load the assembly, the component still doesn&#8217;t load. So we&#8217;re still discussing this. Perhaps I&#8217;ll break down and have custom projects deployed to the &lt;approot&gt;/bin folder, but I sort of doubt it. As ususal, it feels as if we&#8217;re the only ones solving this problem, but I did find this post from over a year ago (<a href="http://www.mcse.ms/message1556506.html">Dynamic LoadControl of ascx with dll not in bin path</a>) and there is a response there (from a DevelopMentor staffer) that says: <em>&#8220;ASP.NET mandates implicit loading of assemblies from ~/bin or the GAC. You can always call Assembly.LoadFrom, but I&#8217;m not sure if the LoadControl will work with that. It&#8217;s worth a try.&#8221;</em></p>
<p>I nearly refused to believe it, but after about 2 bad days on this, I&#8217;m convinced. Love to know why, Microsoft, anyone?</p>
<p>For now, we are leaving it alone and leaving the hacky @Register business in place.</p>
<p>We did, however, convert our main project (EAP.WebHost) into the new model and boy oh boy is it better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2006/04/web-projects-and-net-20-1026/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Picklists</title>
		<link>http://www.netquarry.com/index.php/2006/03/picklists-1050/</link>
		<comments>http://www.netquarry.com/index.php/2006/03/picklists-1050/#comments</comments>
		<pubDate>Wed, 08 Mar 2006 03:02:00 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Features]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=50</guid>
		<description><![CDATA[We"ve spent a bunch of time solving the problem of vocabulary lists for a database application. A vocabulary list is one of those tables that have a key (typically an integer or a GUID) and some text. The “key” (primary key in DBMS-speak) is referenced by a column in a more important table. Most of the time, the end-user selects this key by choosing an item via a drop down list box that has some human readable text and the application stores the item’s “key” into the database. We call the object that solves this problem a Picklist.]]></description>
			<content:encoded><![CDATA[<p>We&#8221;ve spent a bunch of time solving the problem of vocabulary lists for a database application. A vocabulary list is one of those tables that have a key (typically an integer or a GUID) and some text. The “key” (primary key in DBMS-speak) is referenced by a column in a more important table. Most of the time, the end-user selects this key by choosing an item via a drop down list box that has some human readable text and the application stores the item’s “key” into the database. We call the object that solves this problem a Picklist.</p>
<p style="margin-top: 12pt">Normally, you solve the problem by creating a 2 column table with a key and some descriptive text. For example, say you wanted to have a status table:</p>
<p style="margin-top: 12pt">Table: status</p>
<div class="picklist-blog">
<table border="1">
<tbody>
<tr>
<td width="96" valign="top"><span>StatusID</span></td>
<td width="96" valign="top"><span>StatusText</span></td>
</tr>
<tr>
<td width="96" valign="top">1</td>
<td width="96" valign="top">Open</td>
</tr>
<tr>
<td width="96" valign="top">2</td>
<td width="96" valign="top">Closed</td>
</tr>
</tbody>
</table>
</div>
<p style="margin-top: 12pt">You might get a stab of reusability and conclude that a good idea is to store these sorts of things in a table that has a type and therefore keep yourself from having to create 300 of these tables in your database. So, the table might look like this:</p>
<p style="margin-top: 12pt">Reusable design: <span>picklist</span></p>
<div>
<table border="1">
<tbody>
<tr>
<td width="96" valign="top">id</td>
<td width="96" valign="top">description</td>
<td width="96" valign="top">list_type</td>
</tr>
<tr>
<td width="96" valign="top">1</td>
<td width="96" valign="top">Open</td>
<td width="96" valign="top">status</td>
</tr>
<tr>
<td width="96" valign="top">2</td>
<td width="96" valign="top">Closed</td>
<td width="96" valign="top">status</td>
</tr>
</tbody>
</table>
</div>
<p style="margin-top: 12pt">Now, all you have to do is change the SELECT statement and you can have one table to handle most everything. Next, you bump into a requirement where you have to store something besides and integer as the key (say, its data that you didn’t own and the key is some cryptic string). No problem, you just add another column to this list with an alternate ID (or another table, I suppose) and indicate that somehow.</p>
<p style="margin-top: 12pt">2<sup>nd</sup> try: <span>picklist</span></p>
<div>
<table border="1">
<tbody>
<tr>
<td width="96" valign="top">id</td>
<td width="96" valign="top">text_id</td>
<td width="96" valign="top">description</td>
<td width="96" valign="top">list_type</td>
</tr>
<tr>
<td width="96" valign="top">1</td>
<td width="96" valign="top">OP</td>
<td width="96" valign="top">Open</td>
<td width="96" valign="top">status</td>
</tr>
<tr>
<td width="96" valign="top">2</td>
<td width="96" valign="top">CL</td>
<td width="96" valign="top">Closed</td>
<td width="96" valign="top">status</td>
</tr>
</tbody>
</table>
</div>
<p style="margin-top: 12pt">Next, you decide that some of the items in this list are required to be shown, but you don’t want the user to select them. So you add <em>another</em> column to the table and indicate which items are disabled.</p>
<p style="margin-top: 12pt">3<sup>rd</sup> try: <span>picklist</span></p>
<div>
<table border="1">
<tbody>
<tr>
<td width="96" valign="top">id</td>
<td width="96" valign="top">text_id</td>
<td width="96" valign="top">description</td>
<td width="96" valign="top">list_type</td>
<td width="96" valign="top">disabled</td>
</tr>
<tr>
<td width="96" valign="top">1</td>
<td width="96" valign="top">OP</td>
<td width="96" valign="top">Open</td>
<td width="96" valign="top">status</td>
<td width="96" valign="top">0</td>
</tr>
<tr>
<td width="96" valign="top">2</td>
<td width="96" valign="top">CL</td>
<td width="96" valign="top">Closed</td>
<td width="96" valign="top">status</td>
<td width="96" valign="top">0</td>
</tr>
<tr>
<td width="96" valign="top">3</td>
<td width="96" valign="top">PO</td>
<td width="96" valign="top">Nearly Closed</td>
<td width="96" valign="top">status</td>
<td width="96" valign="top">1</td>
</tr>
</tbody>
</table>
</div>
<p style="margin-top: 12pt">At this point you’ve thought of several more interesting requirements so your table design ends up with several more columns to support these:</p>
<ul>
<li>Localization. If you plan to support a multi-lingual application you are very likely to need to have your vocabulary displayed in the user’s culture.</li>
<li>Readable string as a way to lookup an ID. The common case for this is when you want either to set a default value in a field but do not want to hard code some opaque primary key values in your code or you want to take some action based on the value that a user chooses and you don’t want to hardcode the primary key value.</li>
<li>Caching (or not) the items in the list. If you are going to model this, you’ve likely decided that you need to metadata tables – Picklist (for the name of the list and some attributes like “cache”), and PicklistItems (for the actual items).</li>
<li>Discrimination. Often you’ll have a requirement where the value in one column filters (or discriminates) the potential values in another. For example, you may have a list of vehicle make types in one list and based on the selection, you need to show the available models in another. The typical way to solve this is to take the value from the first control, post the results to the server, dynamically determine the new SELECT statement, and return the page with the second control filtered.</li>
<li>Two-way lookup. Often you have the value of the item’s key only and you need to find the text, but we have found that you just a frequently need to do the reverse (e.g. you have the text and you want the key). We use the reverse lookup, for example, when searching or filtering in a list – the user enters “Open” and we search for “1.”</li>
</ul>
<p style="margin-top: 12pt">The next issue you solve is how to fill the controls with the contents of these lists. The most straightforward method is to write code to open a <span>DataReader</span> with a statement like (SELECT id, description FROM <span>picklist</span> WHERE <span>list_type</span> = ‘<span>status’</span>) and add these items to a <span>DropDownList</span> control like this:</p>
<p class="code">while (dr.Read())<br />
{<br />
    listControl.Items.Add(new ListItem (dr.GetString(0), dr.GetInt32(1)));<br />
}</p>
<p style="margin-top: 12pt">Or, a better way is to bind using the DataBinding features of the DropDownList– something along these lines:</p>
<p class="code">DataTable dt = CreateTableFromPickListSQL();<br />
dropList.DataSource = dt;<br />
dropList.DataTextField = “id”;<br />
dropList.DataValueField = “description”;<br />
dropList.DataBind();</p>
<p style="margin-top: 12pt">In both cases, you are responsible for creating either the DataReader or DataTable and properly disposing of it. Most folks know how to do this, or at least they know how to cut and paste some code somewhere that does it reasonably well. It’s still a pain and generally isn’t written in such a way to promote even moderate reusability.</p>
<p style="margin-top: 12pt">Another consideration is that you may need to use one of these lists for something <em>other</em> than as a <span>DataSource</span> for a <span>DropDownList</span> control. For example, if you are displaying a table of data that has several columns which are foreign keys to your <span>picklist</span> table you either must create some sort of view to resolve these or do a lookup as you fill the list (this is almost never an option for performance reasons). The trouble with the view is that unless you strictly enforce the integrity of your data you are likely to lose some rows because the values in your main table have foreign key values that are invalid.</p>
<p style="margin-top: 12pt">There are a bunch of other factors, of course, which is why there is a dedicated object to solve this problem. Again, a Picklist represents a domain specific list of values that can be used to translate the key of an item (typically a foreign key in a database table) to a description.</p>
<p style="margin-top: 12pt">In the NetQuarry Platform, Picklists are of one of three distinct types:</p>
<ul style="margin-top: 0in" type="disc">
<li>A “standard” Picklist. This type of list is loaded from the metadata and supports the descriptive text in the current user’s culture (language). We use a pattern similar to the one just described to model this. (Picklist, <span>PicklistItems</span> (with a foreign key to a “Text” table to support localization))</li>
<li>A “SQL” Picklist. This type of list is loaded from one of the databases (can be the “main” operational database or the repository) and can contain 1 to 3 columns of data.</li>
<li>An “Enumeration” Picklist. This list is a 2 column Picklist loaded from a string type name that represents an Enumeration as its source. (The NetQuarry Studio makes good use of this.)</li>
<li>For the most part, Picklists tend to have the <span>LimitToList</span> attribute set. This attribute says that the item selected by the user MUST be one of the items in this list. There are several other attributes of interest as well, listed here and briefly explained:</li>
</ul>
<p> </p>
<table border="1">
<tbody>
<tr>
<td width="23%" valign="top"><strong><span>Member Name</span></strong></td>
<td width="76%" valign="top"><strong><span>Description</span></strong></td>
</tr>
<tr>
<td width="23%" valign="top"><span>Cache</span></td>
<td width="76%" valign="top"><span>This list should be cached.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>HasDiscrim</span></td>
<td width="76%" valign="top"><span>This list uses a discriminator to break items into sets.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>LimitToList</span></td>
<td width="76%" valign="top"><span>This list has at least 2 columns and the values must come from the list.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>HideUnknownItems</span></td>
<td width="76%" valign="top"><span>The list should hide unknown items.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>MarkUnknownItems</span></td>
<td width="76%" valign="top"><span>The list should mark unknown items.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>StoreAltText</span></td>
<td width="76%" valign="top"><span>The list stores the item&#8221;s Alternate Key Text column in the DB and uses it as it&#8221;s </span><span>ID.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>StoreAltInt</span></td>
<td width="76%" valign="top"><span>The list stores the item&#8221;s Alternate Key </span><span>Int</span> column in the DB and uses it as it&#8221;s <span>ID.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>StoreItemName</span></td>
<td width="76%" valign="top"><span>The list stores the item&#8221;s Name column in the DB and uses it as it&#8221;s </span><span>ID.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>NoNullEntry</span></td>
<td width="76%" valign="top"><span>The list does not need to provide a null entry.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>SortByText</span></td>
<td width="76%" valign="top"><span>List should be sorted by the display text.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>SortDesc</span></td>
<td width="76%" valign="top"><span>List should be sorted in DESC order. (Standard Picklists only)</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>SortByKey</span></td>
<td width="76%" valign="top"><span>List should be sorted by the stored key.</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>AllowUserAdd</span></td>
<td width="76%" valign="top"><span>Users can add new items to this list (providing they have Configuration permission).</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>AllowUserDelete</span></td>
<td width="76%" valign="top"><span>Users can remove items from this list (providing they have Configuration permission).</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>AllowUserUpdate</span></td>
<td width="76%" valign="top"><span>Users can update items in this list (providing they have Configuration permission).</span></td>
</tr>
<tr>
<td width="23%" valign="top"><span>Disabled</span></td>
<td width="76%" valign="top"><span>The </span><span>picklist</span> is disabled.</td>
</tr>
<tr>
<td width="23%" valign="top"><span>IgnoreWhitespace</span></td>
<td width="76%" valign="top"><span>Ignore leading and trailing whitespace when matching values.</span></td>
</tr>
</tbody>
</table>
<div>&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2006/03/picklists-1050/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Architecture</title>
		<link>http://www.netquarry.com/index.php/2005/12/architecture-1066/</link>
		<comments>http://www.netquarry.com/index.php/2005/12/architecture-1066/#comments</comments>
		<pubDate>Thu, 01 Dec 2005 16:24:13 +0000</pubDate>
		<dc:creator>Ryan Reid</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://www.netquarry.com/?p=66</guid>
		<description><![CDATA[Keeping at the forefront in any industry requires that companies cannot only imagine great new products, but can get them from the vision stage into full production in the most efficient possible manner. The NetQuarry platform provides an engine for driving innovation, enabling products to be designed quickly, collaboratively, and iteratively.]]></description>
			<content:encoded><![CDATA[<p>Keeping at the forefront in any industry requires that companies cannot only imagine great new products, but can get them from the vision stage into full production in the most efficient possible manner. The NetQuarry platform provides an engine for driving innovation, enabling products to be designed quickly, collaboratively, and iteratively.</p>
<p>Read the full <a href="http://www.netquarry.com/NetQuarry_Architecture.pdf" target="_blank">White Paper.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.netquarry.com/index.php/2005/12/architecture-1066/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
