<?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-15864493</id><updated>2011-12-15T10:06:57.988+07:00</updated><title type='text'>Recent reading</title><subtitle type='html'>Cool articles ! You must read them.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://lethanhhungreading.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-15864493.post-114802301893004918</id><published>2006-05-19T14:15:00.000+07:00</published><updated>2006-05-19T14:16:59.840+07:00</updated><title type='text'>Continuous Integration</title><content type='html'>&lt;div class="author"&gt; &lt;p&gt;&lt;a href="http://www.martinfowler.com/"&gt;  Martin Fowler&lt;/a&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p class="abstract"&gt;&lt;i&gt; Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. This article is a quick overview of Continuous Integration summarizing the technique and its current usage. &lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I vividly remember one of my first sightings of a large software project. I was taking a summer internship at a large English electronics company. My manager, part of the QA group,  gave me a tour of a site and we entered a huge depressing warehouse stacked full with cubes. I was told that this project had been in development for a couple of years and was currently integrating, and had been integrating for several months. My guide told me that nobody really knew how long it would take to finish integrating. From this I learned a common story of software projects: integration is a long and unpredictable process.&lt;/p&gt;&lt;p&gt;But this needn't be the way. Most projects done by my colleagues   at ThoughtWorks, and by many others around the world, treat   integration as a non-event. Any individual developer's work is   only a few hours away from a shared project state and can   integrated back into that state in minutes. Any integration errors   are found rapidly and can be fixed rapidly.&lt;/p&gt;&lt;p&gt;This contrast isn't the result of an expensive and complex   tool. The essence of it lies in the simple practice of everyone on   the team integrating frequently, usually daily, against a   controlled source code repository.  &lt;/p&gt;&lt;p&gt;When I've described this practice to people, I commonly find two reactions: "it can't work (here)" and "doing it won't make much difference". When people find that it's much easier than it sounds, and see that it makes a huge difference to development. Thus the third common reaction is "yes we do that - how could you live without it?"&lt;/p&gt;&lt;p&gt;The term 'Continuous Integration' originated with the Extreme   Programming development process, as one of its original twelve   practices. When I started at ThoughtWorks, as a consultant, I   encouraged the project I was working with to use the   technique. Matthew Foemmel turned my vague exhortations into solid   action and we saw the project go from rare and complex   integrations to the non-event I described. Matthew and I wrote up   our experience in the original version of this paper, which has   been one of the most popular papers on my site.&lt;/p&gt; &lt;div class="relatedArticle"&gt; &lt;p class="relatedArticle"&gt;&lt;span class="seeRelated"&gt;See Related Article: &lt;/span&gt;&lt;a href="http://www.martinfowler.com/articles/originalContinuousIntegration.html"&gt;Continuous Integration (original version)&lt;/a&gt;&lt;/p&gt;  &lt;p class="relatedArticleDesc"&gt;The original article    on Continuous Integration from this website. If you are    following most links, this is the article they intended you to    read (although I think the new one is better). It describes the    experiences that we went through as Matt helped put together    continuous integration through a project at ThoughtWorks in the    early 00's.&lt;/p&gt; &lt;/div&gt; &lt;p&gt;Although Continuous Integration is a practice that requires no particular tooling to deploy, we've found that it is useful to use a Continuous Integration server. The best known such server is CruiseControl, an open source tool originally built by several people at ThoughtWorks and now maintained by a wide community. The original CruiseControl is written in Java but is also available for the Microsoft platform as CruiseControl.net.&lt;/p&gt;&lt;hr class="topSection"&gt; &lt;a name="BuildingAFeatureWithContinuousIntegration"&gt;&lt;/a&gt;  &lt;h2&gt;Building a Feature with Continuous Integration&lt;/h2&gt; &lt;p&gt;The easiest way for me to explain what CI is and how it works is to show a quick example of how it works with the development of a small feature. Let's assume I have to do something to a piece of software, it doesn't really matter what the task is, for the moment I'll assume it's small and can be done in a few hours. (We'll explore longer tasks, and other issues later on.)&lt;/p&gt;&lt;p&gt;I begin by taking a copy of the current integrated source    onto my local development machine. I do this by using a source    code management system by checking out a working copy from the    mainline.&lt;/p&gt;&lt;p&gt;The above paragraph will make sense to people who use source    code control systems, but be gibberish to those who don't. So    let me quickly explain that for the latter. A source code    control system keeps all of a project's source coded in a    repository. The current state of the system is usually referred    to as the mainline. At any time a developer can do a controlled    copy of the mainline onto their own machine, this is called    checking out. The copy on the developer's machine    is called a working copy. (Most of the time you actually update    your working copy to the mainline - in practice it's the same thing.)&lt;/p&gt;&lt;p&gt;Now I take my working copy and do whatever I need to do to    complete my task. This will consist of both altering the    production code, and also adding or changing automated    tests. Continuous Integration assumes a high degree of tests    which are automated into the software: a facility I call    self-testing code. Often these use a version of the popular    XUnit testing frameworks.&lt;/p&gt;&lt;p&gt;Once I'm done (and usually at various points when I'm    working) I carry out an automated build on my development    machine. This takes the source code in my working copy, compiles    and links it into an executable, and runs the automated    tests. Only if it all builds and tests without errors is the    overall build considered to be good.&lt;/p&gt;&lt;p&gt;With a good build, I can then think about    committing my changes into the repository. The twist, of course, is    that other people may, and usually have, made changes to the    mainline before I get chance to commit. So first I update my    working copy with their changes and rebuild. If their changes    clash with my changes, it will manifest as a failure either in    the compilation or in the tests. In this case it's my    responsibility to fix this and repeat until I can build a    working copy that is properly synchronized with the mainline.&lt;/p&gt;&lt;p&gt;Once I have made my own build of a properly synchronized    working copy I can then finally commit my changes into the mainline,    which then updates the repository.&lt;/p&gt;&lt;p&gt;However my commit doesn't finish my work. At this point we    build again, but this time on an integration machine based on    the mainline code. Only when this build succeeds can we say that    my changes are done. There is always a chance that I missed    something on my machine and the repository wasn't properly    updated. Only when my committed changes build successfully on    the integration is my job done. This integration build can be    executed manually by me, or done automatically by CruiseControl.&lt;/p&gt;&lt;p&gt;If a clash occurs between two    developers, it is usually caught when the second developer to    commit builds their updated working copy. If not the integration    build should fail. Either way the error is detected rapidly. At    this point the most important task is to fix it, and get the    build working properly again. In a Continuous Integration    environment you should never have a failed integration build    stay failed for long. A good team should have many correct    builds a day. Bad builds do occur from time to time, but should    be quickly fixed.&lt;/p&gt;&lt;p&gt;The result of doing this is that there is a stable piece of    software that works properly and contains few bugs. Everybody    develops off that shared stable base and never gets so far away    from that base that it takes very long to integrate back with    it. Less time is spent trying to find bugs because they show up    quickly.&lt;/p&gt;&lt;hr class="topSection"&gt; &lt;a name="PracticesOfContinuousIntegration"&gt;&lt;/a&gt;  &lt;h2&gt;Practices of Continuous Integration&lt;/h2&gt; &lt;p&gt;The story above is the overview of CI and how it works in    daily life. Getting all this to work smoothly is obviously    rather more than that. I'll focus now on the key practices that    make up effective CI.&lt;/p&gt; &lt;a name="MaintainASingleSourceRepository."&gt;&lt;/a&gt;  &lt;h3&gt;Maintain a Single Source Repository.&lt;/h3&gt; &lt;p&gt;Software projects involve lots of files that need to be orchestrated together to build a product. Keeping track of all of these is a major effort, particularly when there's multiple people involved. So it's not surprising that over the years software development teams have built tools to manage all this. These tools - called Source Code Management tools, configuration management, version control systems, repositories, or various other names - are an integral part of most development projects. The sad and surprising thing is that they aren't part of &lt;i&gt;all&lt;/i&gt; projects. It is rare, but I do run into projects that don't use such a system and use some messy combination of local and shared drives.&lt;/p&gt;&lt;p&gt;So as a simple basis make sure you get a decent source code management system. Cost isn't an issue as good quality open-source tools are available. The current open source repository of choice is &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;. (The older open-source tool &lt;a href="http://www.nongnu.org/cvs/"&gt;CVS&lt;/a&gt; is still widely used, and is much better than nothing, but Subversion is the modern choice.) Interestingly as I talk to developers I know most commercial source code management tools are liked less than Subversion. The only tool I've consistently heard people say is worth paying for is &lt;a href="http://www.perforce.com/"&gt;Perforce&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Once you get a source code management system, make sure it     is the well known place for everyone to go get source     code. Nobody should ever ask "where is the foo-whiffle file?"     Everything should be in the repository.&lt;/p&gt;&lt;p&gt;Although many teams use repositories a common mistake I see     is that they don't put everything in the repository. If people     use one they'll put code in there, but everything you need to     do a build should in     there including: test scripts, properties files, database     schema, install scripts, and third party     libraries. I've known projects that check their compilers into     the repository (important in the early days of flaky C++     compilers). The basic rule of thumb is that you should be able     to walk up to the project with a virgin machine, do a     checkout, and be able to fully build the system. Only a     minimal amount of things should be on the virgin machine -     usually things that are large, complicated to install, and     stable. An operating system, Java development environment, or base     database system are typical examples.&lt;/p&gt;&lt;p&gt;You must put everything required for a build in the source     control system, however you may also put other stuff that     people generally work with in there too. IDE configurations     are good to put in there because that way it's easy for people     to share the same IDE setups.&lt;/p&gt;&lt;p&gt;One of the features of version control systems is that they     allow you to create multiple branches, to handle different     streams of development. This is a useful, nay essential,     feature - but it's frequently overused and gets people into     trouble. Keep your use of branches to a minimum. In particular     have a &lt;b&gt;mainline&lt;/b&gt;: a single branch of the project     currently under development. Pretty much everyone should work     off this mainline most of the time. (Reasonable branches are     bug fixes of prior production releases and temporary experiments.) &lt;/p&gt;&lt;p&gt;In general you should store in source control everything     you need to build anything, but nothing that you actually     build. Some people do keep the build products in source     control, but I consider that to be a smell - an indication of     a deeper problem, usually an inability to reliably recreate builds.&lt;/p&gt; &lt;a name="AutomateTheBuild"&gt;&lt;/a&gt;  &lt;h3&gt;Automate the Build&lt;/h3&gt; &lt;p&gt;Getting the sources turned into a running system can often be a complicated process involving compilation, moving files around, loading schemas into the databases, and so on. However like most tasks in this part of software development it can be automated - and as a result should be automated. Asking people to type in strange commands or clicking through dialog boxes is a waste of time and a breeding ground for mistakes.&lt;/p&gt;&lt;p&gt;Automated environments for builds are a common feature of systems. The Unix world has had make for decades, the Java community developed Ant, the .NET community has had Nant and now has MSBuild. Make sure you can build and launch your system using these scripts using a single command.&lt;/p&gt;&lt;p&gt;A common mistake is not to include everything in the automated build. The build should include getting the database schema out of the repository and firing it up in the execution environment. I'll elaborate my earlier rule of thumb: anyone should be able to bring in a virgin machine, check the sources out of the repository, issue a single command, and have a running system on their machine.&lt;/p&gt;&lt;p&gt;Build scripts come in various flavors and are often particular to a platform or community, but they don't have to be. Although most of our Java projects use Ant, some have used Ruby (the Ruby Rake system is a very nice build script tool). We got a lot of value from automating an early Microsoft COM project with Ant.&lt;/p&gt;&lt;p&gt;A big build often takes time, you don't want to do all of these steps if you've only made a small change. So a good build tool analyzes what needs to be changed as part of the process. The common way to do this is to check the dates of the source and object files and only compile if the source date is later. Dependencies then get tricky: if one object file changes those that depend on it may also need to be rebuilt. Compilers may handle this kind of thing, or they may not.&lt;/p&gt;&lt;p&gt;Depending on what you need, you may need different kinds of things to be built. You can build a system with or without test code, or with different sets of tests. Some components can be built stand-alone. A build script should allow you to build alternative targets for different cases.&lt;/p&gt;&lt;p&gt;Many of us use IDEs, and most IDEs have some kind of build management process within them. However these files are always proprietary to the IDE and often fragile. Furthermore they need the IDE to work. It's okay for IDE users set up their own project files and use them for individual development. However it's essential to have a master build that is usable on a server and runnable from other scripts. So on a Java project we're okay with having developers build in their IDE, but the master build uses Ant to ensure it can be run on the development server.&lt;/p&gt; &lt;a name="MakeYourBuildSelf-testing"&gt;&lt;/a&gt;  &lt;h3&gt;Make Your Build Self-Testing&lt;/h3&gt; &lt;p&gt;Traditionally a build means compiling, linking, and all the additional stuff required to get a program to execute. A program may run, but that doesn't mean it does the right thing. Modern statically typed languages can catch many bugs, but far more slip through that net.&lt;/p&gt;&lt;p&gt;A good way to catch bugs more quickly and efficiently is to include automated tests in the build process. Testing isn't perfect, of course, but it can catch a lot of bugs - enough to be useful. In particular the rise of Extreme Programming (XP) and Test Driven Development (TDD) have done a great deal to popularize self-testing code and as a result many people have seen the value of the technique.&lt;/p&gt;&lt;p&gt;Regular readers of my work will know that I'm a big fan both both TDD and XP, however I want to stress that neither of these approaches are necessary to gain the benefits of self-testing code. Both of these approaches make a point of writing tests before you write the code that makes them pass - in this mode the tests are as much about exploring the design of the system as they are about bug catching. This is a Good Thing, but it's not necessary for the purposes of Continuous Integration, where we have the weaker requirement of self-testing code. (Although TDD is my preferred way of producing self-testing code.)&lt;/p&gt;&lt;p&gt;For self-testing code you need a suite of automated tests that can check a large part of the code base for bugs. The tests need to be able to be kicked off from a simple command and to be self-checking. The result of running the test suite should indicate if any tests failed. For a build to be self-testing the failure of a test should cause the build to fail.&lt;/p&gt;&lt;p&gt;Over the last few years the rise of TDD has popularized the &lt;a href="http://www.martinfowler.com/bliki/Xunit.html"&gt;XUnit family&lt;/a&gt; of open-source tools which are ideal for this kind of testing. XUnit tools have proved very valuable to us at ThoughtWorks and I always suggest to people that they use them. These tools, pioneered by Kent Beck, make it very easy for you to set up a fully self-testing environment.&lt;/p&gt;&lt;p&gt;XUnit tools are certainly the starting point for making your code self-testing. You should also look out for other tools that focus on more end-to-end testing, there's quite a range of these out there at the moment including &lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt;, &lt;a href="http://www.openqa.org/selenium/"&gt;Selenium&lt;/a&gt;, &lt;a href="http://sahi.sourceforge.net/"&gt;Sahi&lt;/a&gt;, &lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt;, &lt;a href="http://fitnesse.org/"&gt;FITnesse&lt;/a&gt;, and plenty of others that I'm not trying to comprehensively list here.&lt;/p&gt;&lt;p&gt;Of course you can't count on tests to find everything. As it's often been said: tests don't prove the absence of bugs. However perfection isn't the only point at which you get payback for a self-testing build. Imperfect tests, run frequently, are much better than perfect tests that are never written at all.&lt;/p&gt; &lt;a name="EveryoneCommitsEveryDay"&gt;&lt;/a&gt;  &lt;h3&gt;Everyone Commits Every Day&lt;/h3&gt; &lt;p&gt;Integration is primarily about communication. Integration     allows developers to tell other developers about the changes     they have made. Frequent communication allows people to know     quickly as changes develop.&lt;/p&gt;&lt;p&gt;The one prerequisite for a developer committing to the     mainline is that they can correctly build their code. This, of     course, includes passing the build tests. As with any commit     cycle the developer first updates their working copy to match     the mainline, resolves any conflicts with the mainline, then     builds on their local machine. If the build passes, then they     are free to commit to the mainline.&lt;/p&gt;&lt;p&gt;By doing this frequently, developers quickly find out if     there's a conflict between two developers. The key to fixing     problems quickly is finding them quickly. With developers     committing every few hours a conflict can be detected within a     few hours of it occurring, at that point not much has     happened and it's easy to resolve. Conflicts that stay     undetected for weeks can be very hard to resolve.&lt;/p&gt;&lt;p&gt;The fact that you build when you update your working copy     means that you detect compilation conflicts as well as textual     conflicts. Since the build is self-testing, you also detect     conflicts in the running of the code. The latter conflicts are     particularly awkward bugs to find if they sit for a long time     undetected in the code. Since there's only a few hours of     changes between commits, there's only so many places where the     problem could be hiding. Furthermore since not much has     changed you can use &lt;a href="http://www.martinfowler.com/bliki/DiffDebugging.html"&gt;diff-debugging&lt;/a&gt; to help you find the bug.&lt;/p&gt;&lt;p&gt;My general rule of thumb is that every developer should     commit to the repository every day. In practice it's often     useful if developers commit more frequently than     that. The more frequently you commit, the less places you have     to look for conflict errors, and the more rapidly you fix     conflicts.&lt;/p&gt;&lt;p&gt;Frequent commits encourage developers to break down their     work into small chunks of a few hours each. This helps     track progress and provides a sense of progress. Often people     initially feel they can't do something meaningful in just a few     hours, but we've found that mentoring and practice helps them learn.&lt;/p&gt; &lt;a name="EveryCommitShouldBuildTheMainlineOnAnIntegrationMachine"&gt;&lt;/a&gt;  &lt;h3&gt;Every Commit Should Build the Mainline on an Integration Machine&lt;/h3&gt; &lt;p&gt;Using daily commits, a team gets frequent tested     builds. This ought to mean that the mainline stays in a     healthy state. In practice, however, things still do go     wrong. One reason is discipline, people not doing an update     and build before they commit. Another is environmental     differences between developers' machines.&lt;/p&gt;&lt;p&gt;As a result you should ensure that regular builds happen on     an integration machine and only if this integration build     succeeds should the commit be considered to be done. Since the     developer who commits is responsible for this, that developer     needs to monitor the mainline build so they can fix it if it     breaks. A corollary of this is that you shouldn't go home     until the mainline build has passed with any commits you've     added late in the day.&lt;/p&gt;&lt;p&gt;There are two main ways I've seen to ensure this: using a manual build or a continuous integration server.&lt;/p&gt;&lt;p&gt;The manual build approach is the simplest one to     describe. Essentially it's a similar thing to the local build     that a developer does before the commit into the     repository. The developer goes to the integration machine,     checks out the head of the mainline (which now houses his last     commit) and kicks off the integration build. He keeps an eye     on its progress, and if the build succeeds he's done with his     commit. (Also see Jim Shore's &lt;a href="http://www.jamesshore.com/Blog/Continuous-Integration-on-a-Dollar-a-Day.html"&gt;description&lt;/a&gt;.)&lt;/p&gt;&lt;p&gt;A continuous integration server acts as a monitor to the     repository. Every time a commit against the repository     finishes the server automatically checks out the sources onto     the integration machine, initiates a build, and notifies the     committer of the result of the build. The committer isn't done     until she gets the notification - usually an email.&lt;/p&gt;&lt;p&gt;At ThoughtWorks, we're big fans of continuous integration servers - indeed we led the development of &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt; and &lt;a href="http://ccnet.thoughtworks.com/"&gt;CruiseControl.net&lt;/a&gt;, the widely used open-source CI servers. ThoughtWorkers like Paul Julius, Jason Yip, and Owen Rodgers are still active committers to these open source projects. We use CruiseControl on nearly every project we do and have been very happy with the results.&lt;/p&gt;&lt;p&gt;Not everyone prefers to use a CI server. Jim Shore gave a     &lt;a href="http://www.jamesshore.com/Blog/Continuous-Integration-is-an-Attitude.html"&gt;well argued description&lt;/a&gt; of why he prefers the manual     approach. I agree with him that CI is much more than just     installing Cruise Control. All the practices here need to be     in play to do Continuous Integration effectively. But equally     many teams who do CI well find Cruise Control a helpful     tool.&lt;/p&gt;&lt;p&gt;Many organizations do regular builds on a timed schedule,     such as every night. This is not the same thing as a     continuous build and isn't enough for continuous     integration. The whole point of continuous integration is to     find problems as soon as you can. Nightly builds mean that     bugs lie undetected for a whole day before anyone discovers     them. Once they are in the system that long, it takes a long     time to find and remove them.&lt;/p&gt;&lt;p&gt;A key part of doing a continuous build is that if the     mainline build fails, it needs to be fixed right away. The     whole point of working with CI is that you're always     developing on a known stable base. It's not a bad thing for     the mainline build to break, although if it's happening all     the time it suggests people aren't being careful enough about     updating and     building locally before a commit. When the mainline build does     break, however, it's important that it gets fixed fast.&lt;/p&gt;&lt;p&gt;When teams are introducing CI, often this is one of the     hardest things to sort out. Early on a team can struggle to     get into the regular habit of working mainline builds,     particularly if they are working on an existing code     base. Patience and steady application does seem to regularly     do the trick, so don't get discouraged.&lt;/p&gt; &lt;a name="KeepTheBuildFast"&gt;&lt;/a&gt;  &lt;h3&gt;Keep the Build Fast&lt;/h3&gt; &lt;p&gt;The whole point of Continuous Integration is to provide     rapid feedback. Nothing sucks the blood of a CI activity more     than a build that takes a long time. Here I must admit a     certain crotchety old guy amusement at what's considered to     be a long build. Most of my colleagues consider a build that     takes an hour to be totally unreasonable. I remember teams     dreaming that they could get it so fast - and occasionally we     still run into cases where it's very hard to get builds to     that speed.&lt;/p&gt;&lt;p&gt;For most projects, however, the XP guideline of a ten     minute build is perfectly within reason. Most of our modern     projects achieve this. It's worth putting in concentrated     effort to make it happen, because every minute you reduce off     the build time is a minute saved for each developer every time     they commit. Since CI demands frequent commits, this adds up     to a lot of time.&lt;/p&gt;&lt;p&gt;If you're staring at a one hour build time, then getting to     a faster build may seem like a daunting prospect. It can even     be daunting to work on a new project and think about how to     keep things fast. For enterprise applications, at least, we've     found the usual bottleneck is testing - particularly tests     that involve external services such as a database.&lt;/p&gt;&lt;p&gt;Probably the most crucial step is to start working on setting up a staged build. The idea behind a &lt;b&gt;staged build&lt;/b&gt; (also known as &lt;b&gt;build pipeline&lt;/b&gt;) is that there are in fact multiple builds done in sequence. The commit to the mainline triggers the first build - what I call the commit build. The &lt;b&gt;commit build&lt;/b&gt; is the build that's needed when someone commits to the mainline. The commit build is the one that has to be done quickly, as a result it will take a number of shortcuts that will reduce the ability to detect bugs. The trick is to balance the needs of bug finding and speed so that a good commit build is stable enough for other people to work on.&lt;/p&gt;&lt;p&gt;Once the commit build is good then other people can work on     the code with confidence. However there are further, slower,     tests that you can start to do. Additional machines can run     further testing routines on the build that take longer to     do.&lt;/p&gt;&lt;p&gt;A simple example of this is a two stage build. The first     stage would do the compilation and run tests that are more     localized unit tests with the database completely stubbed out.     Such tests can run very fast, keeping within the ten minute     guideline. However any bugs that involve larger scale     interactions, particularly those involving the real database,     won't be found. The second stage build runs a different suite     of tests that do hit the real database and involve more     end-to-end behavior. This suite might take a couple of hours     to run.&lt;/p&gt;&lt;p&gt;In this scenario people use the first stage as  the commit build and use this     as their main CI cycle. The second-stage build is a &lt;b&gt;secondary     build&lt;/b&gt; which runs when it     can, picking up the latest good commit build for further     testing. If the secondary build fails, then this doesn't     have the same 'stop everything' quality, but the team does aim     to fix such bugs as rapidly as possible, while keeping the     commit build running. Indeed the secondary build     doesn't have to stay good, as long as each known bug is     identified and dealt with in a next few days.&lt;/p&gt;&lt;p&gt;If the secondary build detects a bug, that's a sign that the commit build could do with another test. As much as possible you want to ensure that any secondary build failure leads to new tests in the commit build that would have caught the bug, so the bug stays fixed in the commit build. This way the commit tests are strengthened whenever something gets past them. There are cases where there's no way to build a fast-running test that exposes the bug, so you may decide to only test for that condition in the secondary build. Most of time, fortunately, you can add suitable tests to the commit build.&lt;/p&gt;&lt;p&gt;This example is of a two-stage build, but the basic     principle can be extended to any number of later builds. The     builds after the commit build can also be done in parallel, so if     you have two hours of secondary tests you can improve     responsiveness by having two machines that run half the tests     each. By using parallel secondary builds like this you can     introduce all sorts of further automated testing, including     performance testing, into the regular build process. (I've run     into a lot of interesting techniques around this as I've     visited various ThoughtWorks projects over the last couple of     years - I'm hoping to persuade some of the developers to write   these up.)&lt;/p&gt; &lt;a name="TestInACloneOfTheProductionEnvironment"&gt;&lt;/a&gt;  &lt;h3&gt;Test in a Clone of the Production Environment&lt;/h3&gt; &lt;p&gt;The point of testing is to flush out, under controlled     conditions, any problem that the system will have in     production. A significant part of this is the environment     within which the production system will run. If you test in a     different environment, every difference results in a risk that     what happens under test won't happen in production.&lt;/p&gt;&lt;p&gt;As a result you want to set up your test environment to be     as exact a mimic of your production environment as     possible. Use the same database software, with the same     versions, use the same version of operating system. Put all     the appropriate libraries that are in the production     environment into the test environment, even if the system     doesn't actually use them. Use the same IP addresses and     ports, run it on the same hardware.&lt;/p&gt;&lt;p&gt;Well, in reality there are limits. If you're writing     desktop software it's not practicable to test in a clone of     every possible desktop with all the third party software that     different people are running. Similarly some production     environments may be prohibitively expensive to duplicate     (although I've often come across false economies by not duplicating     moderately expensive environments). Despite these limits your     goal should still be to duplicate the production environment     as much as you can, and to understand the risks you are     accepting for every difference between test and production.&lt;/p&gt;&lt;p&gt;If you have a pretty simple setup without many awkward     communications, you may be able to run your commit build in a     mimicked environment. Often, however, you need to use &lt;a href="http://www.martinfowler.com/bliki/TestDouble.html"&gt;test     doubles&lt;/a&gt; because systems respond slowly or intermittently. As a     result its common to have a very artificial environment for     the commit tests for speed, and use a production clone for     secondary testing.&lt;/p&gt;&lt;p&gt;I've noticed a growing interest in using virtualization to     make it easy to put together test environments. Virtualized     machines can be saved with all the necessary elements baked     into the virtualization. It's then relatively straightforward     to install the latest build and run tests. Furthermore this     can allow you to run multiple tests on one machine, or     simulate multiple machines in a network on a single     machine. As the performance penalty of virtualization     decreases, this option makes more and more sense.&lt;/p&gt; &lt;a name="MakeItEasyForAnyoneToGetTheLatestExecutable"&gt;&lt;/a&gt;  &lt;h3&gt;Make it Easy for Anyone to Get the Latest Executable&lt;/h3&gt; &lt;p&gt;One of the most difficult parts of software development is     making sure that you build the right software. We've found     that it's very hard to specify what you want in advance and be     correct; people find it much easier to see something that's     not quite right and say how it needs to be changed. Agile     development processes explicitly expect and take advantage of     this part of human behavior.&lt;/p&gt;&lt;p&gt;To help make this work, anyone involved with a software     project should be able to get the latest executable and be     able to run it: for demonstrations, exploratory testing, or     just to see what changed this week.&lt;/p&gt;&lt;p&gt;Doing this is pretty straightforward: make sure there's a     well known place where people can find the latest     executable. It may be useful to put several executables in     such a store. For the very latest you should put the latest     executable to pass the commit tests - such an executable     should be pretty stable providing the commit suite is     reasonably strong.&lt;/p&gt;&lt;p&gt;If you are following a process with well defined     iterations, it's usually wise to also put the end of iteration     builds there too. Demonstrations, in particular, need software     that whose features are familiar, so then it's usually worth     sacrificing the very latest for something that the     demonstrator knows how to operate.&lt;/p&gt; &lt;a name="EveryoneCanSeeWhatsHappening"&gt;&lt;/a&gt;  &lt;h3&gt;Everyone can see what's happening&lt;/h3&gt; &lt;p&gt;Continuous Integration is all about communication, so you     want to ensure that everyone can easily see the state of the     system and the changes that have been made to it.&lt;/p&gt;&lt;p&gt;One of the most important things to communicate is the     state of the mainline build. If you're using CruiseControl     there's a built in web site that will show you if there's a     build in progress and what was the state of the last mainline     build. Many teams like to make this even more apparent by     hooking up a continuous display to the build system - lights     that glow green when the build works, or red if it fails are     popular. A particularly common touch is red and green &lt;a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/Devices/BubbleBubbleBuildsInTrouble.rdoc"&gt;lava     lamps&lt;/a&gt; - not just do these indicate the state of the build, but     also how long it's been in that state. Bubbles on a red lamp     indicate the build's been broken for too long. Each team makes     its own choices on these build sensors - it's good to be     playful with your choice (recently I saw someone experimenting     with a dancing rabbit.)&lt;/p&gt;&lt;p&gt;If you're using a manual CI process, this visibility is     still essential. The monitor of the physical build machine     can show the status of the mainline build. Often you have a     build token to put on the desk of whoever's currently doing     the build (again something silly like a rubber chicken is a     good choice). Often people like to make a simple noise on good     builds, like ringing a bell.&lt;/p&gt;&lt;p&gt;CI servers' web pages can carry more information than this,     of course. CruiseControl provides an indication not just of     who is building, but what changes they made. Cruise also     provides a history of changes, allowing team members to get a     good sense of recent activity on the project. I know team     leads who like to use this to get a sense of what people have been     doing and keep a sense of the changes to the system.&lt;/p&gt;&lt;p&gt;Another advantage of using a web site is that those that     are not co-located can get a sense of the project's status. In     general I prefer to have everyone actively working on a     project sitting together, but often there are peripheral people     who like to keep an eye on things. It's also useful for groups     to aggregate together build information from multiple projects     - providing a simple and automated status of different projects.&lt;/p&gt;&lt;p&gt;Good information displays are not only those on a computer     screens. One of my favorite displays was for a project that     was getting into CI. It had a long history of being unable to     make stable builds. We put a calendar on the wall that showed     a full year with a small square for each day. Every day the QA     group would put a green sticker on the day if they had     received one stable build that passed the commit tests,     otherwise a red square. Over time the calendar revealed the     state of the build process showing a steady improvement until     green squares were so common that the calendar disappeared -     its purpose fulfilled.&lt;/p&gt; &lt;a name="AutomateDeployment"&gt;&lt;/a&gt;  &lt;h3&gt;Automate Deployment&lt;/h3&gt; &lt;p&gt;To do Continuous Integration you need multiple of     environments, one to run commit tests, one or more to run     secondary tests. Since you are moving executables between these     environments multiple times a day, you'll want to do this     automatically. So it's important to have scripts that will     allow you to deploy the application into any environment easily.&lt;/p&gt;&lt;p&gt;A natural consequence of this is that you should also have     scripts that allow you to deploy into production with similar     ease. You may not be deploying into production every day     (although I've run into projects that do), but automatic     deployment helps both speed up the process and reduce     errors. It's also a cheap option since it just uses the same     capabilities that you use to deploy into test environments.&lt;/p&gt;&lt;p&gt;If you deploy into production one extra automated     capability you should consider is automated rollback. Bad     things do happen from time to time, and if smelly brown     substances hit rotating metal, it's good to be able to quickly     go back to the last known good state. Being able to     automatically revert also reduces a lot of the tension of     deployment, encouraging people to deploy more frequently and     thus get new features out to users quickly. (The ruby on rails     community developed a tool called &lt;a href="http://manuals.rubyonrails.com/read/book/17"&gt;Capistrano&lt;/a&gt; that is a good     example of a tool that does this sort of thing.)&lt;/p&gt;&lt;p&gt;In clustered environments I've seen rolling deployments     where the new software is deployed to one node at a time,     gradually replacing the application over the course of a few     hours.&lt;/p&gt; &lt;div class="relatedArticle"&gt; &lt;p class="relatedArticle"&gt;&lt;span class="seeRelated"&gt;See Related Article: &lt;/span&gt;&lt;a href="http://www.martinfowler.com/articles/evodb.html"&gt;Evolutionary Database Design&lt;/a&gt;&lt;/p&gt;  &lt;p class="relatedArticleDesc"&gt;A common roadblock for many people doing frequent releases is database migration. Database changes are awkward because you can't just change database schemas, you also have to ensure data is correctly migrated. This article describes techniques used by my colleague Pramod Sadalage to do automated refactoring and migration of databases. The article is an early attempt the capture the information that's described in more detail by Pramod and Scott Amblers book on refactoring databases[ambler-sadalage].&lt;/p&gt; &lt;/div&gt; &lt;p&gt;A particularly interesting variation of this that I've come     across with public web application is the idea of deploying a     trial build to a subset of users. The team then sees how the     trial build is used before deciding whether to deploy it to     the full user population. This allows you to test out new     features and user-interfaces before committing to a final     choice. Automated deployment, tied into good CI discipline, is     essential to making this work.&lt;/p&gt;&lt;hr class="topSection"&gt; &lt;a name="BenefitsOfContinuousIntegration"&gt;&lt;/a&gt;  &lt;h2&gt;Benefits of Continuous Integration&lt;/h2&gt; &lt;p&gt;On the whole I think the greatest and most wide ranging    benefit of Continuous Integration is reduced risk. My mind still    floats back to that early software project I mentioned in my    first paragraph. There they were at the end (they hoped) of a    long project, yet with no real idea of how long it would be before    they were done.&lt;/p&gt;&lt;p&gt;The trouble with deferred integration is that it's very hard    to predict how long it will take to do, and worse it's very hard    to see how far you are through the process. The result is that    you are putting yourself into a complete blind spot right at one    of tensest parts of a project - even if you're one the rare    cases where you aren't already late.&lt;/p&gt;&lt;p&gt;Continuous Integration completely finesses this    problem. There's no long integration, you completely eliminate    the blind spot. At all times you know where you are, what works,    what doesn't, the outstanding bugs you have in your system.&lt;/p&gt;&lt;p&gt;Bugs - these are the nasty things that destroy confidence and    mess up schedules and reputations. Bugs in deployed software    make users angry with you. Bugs in work in progress get in your    way, making it harder to get the rest of the software working correctly.&lt;/p&gt;&lt;p&gt;Continuous Integrations doesn't get rid of bugs, but it does make them dramatically easier to find and remove. In this respect it's rather like self-testing code. If you introduce a bug and detect it quickly it's far easier to get rid of. Since you've only changed a small bit of the system, you don't have far to look. Since that bit of the system is the bit you just worked, it's fresh in your memory - again making it easier to find the bug. You can also use &lt;a href="http://www.martinfowler.com/bliki/DiffDebugging.html"&gt;diff debugging&lt;/a&gt; - comparing the current version of the system to an earlier one that didn't have the bug.&lt;/p&gt;&lt;p&gt;Bugs are also cumulative. The more bugs you have, the harder    it is to remove each one. This is partly because you get bug    interactions, where failures show as the result of multiple    faults - making each fault harder to find. It's also    psychological - people have less energy to find and get rid of    bugs when there are many of them - a phenomenon that the    Pragmatic Programmers call the &lt;a href="http://www.amazon.com/exec/obidos/ASIN/020161622X"&gt;Broken Windows syndrome&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;As a result projects with Continuous Integration tend to have    dramatically less bugs, both in production and in    process. However I should stress that the degree of this benefit    is directly tied to how good your test suite is. You should find    that it's not too difficult to build a test suite that makes a    noticeable difference. Usually, however, it takes a while before    a team really gets to the low level of bugs that they have the    potential to reach. Getting there means constantly working on    and improving your tests.&lt;/p&gt;&lt;p&gt;If you have continuous integration, it removes one of the    biggest barriers to frequent deployment. Frequent deployment is    valuable because is allows your users to get new features more    rapidly, to give more rapid feedback on those features, and    generally become more collaborative in the development    cycle. This helps break down the barriers between customers and    development - barriers which I believe are the biggest barriers    to successful software development.&lt;/p&gt;&lt;hr class="topSection"&gt; &lt;a name="IntroducingContinuousIntegration"&gt;&lt;/a&gt;  &lt;h2&gt;Introducing Continuous Integration&lt;/h2&gt; &lt;p&gt;So you fancy trying out Continuous Integration - where do you    start? The full set of practices I outlined above give you the    full benefits - but you don't need to start with all of them.&lt;/p&gt;&lt;p&gt;There's no fixed recipe here - much depends on the nature of    your setup and team. But here are a few things that we've    learned to get things going.&lt;/p&gt;&lt;p&gt;One of the first steps is to get the build automated. Get    everything you need into source control get it so that you can    build the whole system with a single command. For many projects    this is not a minor undertaking - yet it's essential for any of    the other things to work. Initially you may only do build    occasionally on demand, or just do an automated nightly    build. While these aren't continuous integration an automated    nightly build is a fine step on the way.&lt;/p&gt;&lt;p&gt;Introduce some automated testing into you build. Try to    identify the major areas where things go wrong and get automated    tests to expose those failures. Particularly on an existing    project it's hard to get a really good suite of tests going    rapidly - it takes time to build tests up. You have to start    somewhere though - all those cliches about Rome's build schedule    apply.&lt;/p&gt;&lt;p&gt;Try to speed up the commit build. Continuous Integration on a build    of a few hours is better than nothing, but getting down to that    magic ten minute number is much better. This usually requires    some pretty serious surgery on your code base to do as you break    dependencies on slow parts of the system.&lt;/p&gt;&lt;p&gt;If you are starting a new project, begin with Continuous    Integration from the beginning. Keep an eye on build times and    take action as soon as you start going slower than the ten    minute rule. By acting quickly you'll make the necessary    restructurings before the code base gets so big that it becomes    a major pain.&lt;/p&gt;&lt;p&gt;Above all get some help. Find someone who has done Continuous Integration before to help you. Like any new technique it's hard to introduce it when you don't know what the final result looks like. It may cost money to get a mentor, but you'll also pay in lost time and productivity if you don't do it. (Disclaimer / Advert - yes we at ThoughtWorks do do some consultancy in this area. After all we've made most of the mistakes that there are to make.)&lt;/p&gt;&lt;hr class="topSection"&gt; &lt;a name="FinalThoughts"&gt;&lt;/a&gt;  &lt;h2&gt;Final Thoughts&lt;/h2&gt; &lt;p&gt;In the years since Matt and I wrote the original paper on    this site, Continuous Integration has become a mainstream    technique for software development. Hardly any ThoughtWorks    projects goes without it - and we see others using CI all over    the world. I've hardly ever heard negative things about the    approach - unlike some of the more controversial Extreme    Programming practices.&lt;/p&gt;&lt;p&gt;If you're not using Continuous Integration I strongly urge    you give it a try. If you are, maybe there are some ideas in    this article that can help you do it more effectively. We've    learned a lot about Continuous Integration in the last few    years, I hope there's still more to learn and improve. &lt;/p&gt;&lt;hr class="bodySep"&gt;  &lt;div class="appendix"&gt;&lt;hr class="topSection"&gt; &lt;a name="Acknowledgments"&gt;&lt;/a&gt;  &lt;h2&gt;Acknowledgments&lt;/h2&gt; &lt;p&gt;First and foremost to Kent Beck and my many colleagues on the    Chrysler Comprehensive Compensation (C3) project. This was my    first chance to see Continuous Integration in action with a    meaningful amount of unit tests. It showed me what was possible    and gave me an inspiration that led me for many years.&lt;/p&gt;&lt;p&gt;Thanks to Matt Foemmel, Dave Rice, and everyone else who    built and maintained Continuous Integration on Atlas. That    project was a sign of CI on a larger scale and showed the    benefits it made to an existing project.&lt;/p&gt;&lt;p&gt;Paul Julius, Jason Yip, Owen Rodgers, Mike Roberts and many    other open source contributors have     participated in building some variant of Cruise     Control. Although the tool isn't essential, many teams find it     helpful. Cruise has played a big part in popularizing and     enabling software developers to use Continuous Integration.&lt;/p&gt;&lt;p&gt;One of the reasons I work at ThoughtWorks is to get good    access to practical projects done by talented people. Nearly    every project I've visited has given tasty morsels of continuous    integration information.&lt;/p&gt;&lt;/div&gt;  &lt;div class="appendix"&gt; &lt;h2&gt; &lt;a name="SignificantRevisions"&gt;&lt;/a&gt; Significant Revisions&lt;/h2&gt;  &lt;p&gt;&lt;i&gt;01 May 06: &lt;/i&gt;Complete rewrite of article to bring it  up to date and to clarify the description of the approach.&lt;/p&gt;  &lt;p&gt;&lt;i&gt;10 Sep 00: &lt;/i&gt;Original version published.&lt;/p&gt; &lt;/div&gt;     © &lt;small&gt;Copyright &lt;a href="http://www.martinfowler.com/"&gt;Martin      Fowler&lt;/a&gt;, all rights reserved&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-114802301893004918?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114802301893004918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114802301893004918'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/05/continuous-integration.html' title='Continuous Integration'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-114095356813291933</id><published>2006-02-26T18:30:00.000+07:00</published><updated>2006-02-26T18:32:48.346+07:00</updated><title type='text'>URL Rewriting in ASP.NET</title><content type='html'>&lt;p&gt;Scott Mitchell&lt;br /&gt;&lt;br /&gt; 4GuysFromRolla.com&lt;/p&gt;&lt;br /&gt;&lt;p&gt;March 2004&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Applies to:&lt;br /&gt;&lt;br /&gt;    Microsoft® ASP.NET&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; Examines how to perform dynamic URL rewriting with  Microsoft ASP.NET. URL rewriting is the process of intercepting an  incoming Web request and automatically redirecting it to a different  URL. Discusses the various techniques for implementing URL rewriting,  and examines real-world scenarios of URL rewriting. (31 printed pages)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://download.microsoft.com/download/0/4/6/0463611e-a3f9-490d-a08c-877a83b797cf/MSDNURLRewriting.msi" target="_top"&gt;Download the source code for this article&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Contents&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic1" target="_self"&gt;Introduction&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic2" target="_self"&gt;Common Uses of URL Rewriting&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic3" target="_self"&gt;What Happens When a Request Reaches IIS&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic4" target="_self"&gt;Implementing URL Rewriting &lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic5" target="_self"&gt;Building a URL Rewriting Engine&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic6" target="_self"&gt;Performing Simple URL Rewriting with the URL Rewriting Engine&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic7" target="_self"&gt;Creating Truly "Hackable" URLs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic8" target="_self"&gt;Conclusion&lt;/a&gt;&lt;br /&gt;&lt;br /&gt; &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dnaspp/html/urlrewriting.asp#urlrewriting_topic10" target="_self"&gt;Related Books&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic1"&gt;&lt;/a&gt;Introduction&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Take a moment to look at some of the URLs on your website. Do you  find URLs like  http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&amp;type=summary?  Or maybe you have a bunch of Web pages that were moved from one  directory or website to another, resulting in broken links for visitors  who have bookmarked the old URLs. In this article we'll look at using &lt;em&gt;URL rewriting&lt;/em&gt; to shorten those ugly URLs to meaningful, memorable ones, by replacing  http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&amp;amp;type=summary  with something like http://yoursite.com/people/sales/chuck.smith. We'll  also see how URL rewriting can be used to create an intelligent 404  error.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;URL rewriting is the process of intercepting an incoming Web request  and redirecting the request to a different resource. When performing  URL rewriting, typically the URL being requested is checked and, based  on its value, the request is redirected to a different URL. For  example, in the case where a website restructuring caused all of the  Web pages in the /people/ directory to be moved to a /info/employees/  directory, you would want to use URL rewriting to check if a Web  request was intended for a file in the /people/ directory. If the  request was for a file in the /people/ directory, you'd want to  automatically redirect the request to the same file, but in the  /info/employees/ directory instead.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;With classic ASP, the only way to utilize URL rewriting was to write  an ISAPI filter or to buy a third-party product that offered URL  rewriting capabilities. With Microsoft® ASP.NET, however, you can  easily create your own URL rewriting software in a number of ways. In  this article we'll examine the techniques available to ASP.NET  developers for implementing URL rewriting, and then turn to some  real-world uses of URL rewriting. Before we delve into the  technological specifics of URL rewriting, let's first take a look at  some everyday scenarios where URL rewriting can be employed.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic2"&gt;&lt;/a&gt;Common Uses of URL Rewriting&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Creating data-driven ASP.NET websites often results in a single Web  page that displays a subset of the database's data based on querystring  parameters. For example, in designing an e-commerce site, one of your  tasks would be to allow users to browse through the products for sale.  To facilitate this, you might create a page called displayCategory.aspx  that would display the products for a given category. The category's  products to view would be specified by a querystring parameter. That  is, if the user wanted to browse the Widgets for sale, and all Widgets  had a had a CategoryID of 5, the user would visit:  http://yousite.com/displayCategory.aspx?CategoryID=5.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There are two downsides to creating a website with such URLs. First,  from the end user's perspective, the URL  http://yousite.com/displayCategory.aspx?CategoryID=5 is a mess.  Usability expert &lt;a href="http://useit.com/"&gt;Jakob Neilsen&lt;/a&gt; &lt;a href="http://www.useit.com/alertbox/990321.html"&gt;recommends&lt;/a&gt; that URLs be chosen so that they: &lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;Are short.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Are easy to type.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Visualize the site structure.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;"Hackable," allowing the user to navigate through the site by hacking off parts of the URL.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;I would add to that list that URLs should also be easy to remember.  The URL http://yousite.com/displayCategory.aspx?CategoryID=5 meets none  of Neilsen's criteria, nor is it easy to remember. Asking users to type  in querystring values makes a URL hard to type and makes the URL  "hackable" only by experienced Web developers who have an understanding  of the purpose of querystring parameters and their name/value pair  structure. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;A better approach is to allow for a sensible, memorable URL, such as  http://yoursite.com/products/Widgets. By just looking at the URL you  can infer what will be displayed—information about Widgets. The URL is  easy to remember and share, too. I can tell my colleague, "Check out  yoursite.com/products/Widgets," and she'll likely be able to bring up  the page without needing to ask me again what the URL was. (Try doing  that with, say, an Amazon.com page!) The URL also appears, and should  behave, "hackable." That is, if the user hacks of the end of the URL,  and types in http://yoursite.com/products, they should see a listing of &lt;em&gt;all&lt;/em&gt; products, or at least a listing of all categories of products they can view.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Note   &lt;/strong&gt;For a prime example of a "hackable" URL,  consider the URLs generated by many blog engines. To view the posts for  January 28, 2004, one visits a URL like http://someblog.com/2004/01/28.  If the URL is hacked down to http://someblog.com/2004/01, the user will  see all posts for January 2004. Cutting it down further to  http://someblog.com/2004 will display all posts for the year 2004.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In addition to simplifying URLs, URL rewriting is also often used to  handle website restructuring that would otherwise result in numerous  broken links and outdated bookmarks.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic3"&gt;&lt;/a&gt;What Happens When a Request Reaches IIS&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Before we examine exactly how to implement URL rewriting, it's  important that we have an understanding of how incoming requests are  handled by Microsoft® Internet Information Services (IIS). When a  request arrives at an IIS Web server, IIS examines the requested file's  extension to determine how handle the request. Requests can be handled  natively by IIS—as are HTML pages, images, and other static content—or  IIS can route the request to an ISAPI extension. (An ISAPI extension is  an unmanaged, compiled class that handles an incoming Web request. Its  task is to generate the content for the requested resource.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For example, if a request comes in for a Web page named Info.asp,  IIS will route the message to the asp.dll ISAPI extension. This ISAPI  extension will then load the requested ASP page, execute it, and return  its rendered HTML to IIS, which will then send it back to the  requesting client. For ASP.NET pages, IIS routes the message to the  aspnet_isapi.dll ISAPI extension. The aspnet_isapi.dll ISAPI extension  then hands off processing to the managed ASP.NET worker process, which  processes the request, returning the ASP.NET Web page's rendered HTML.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can customize IIS to specify what extensions are mapped to what  ISAPI extensions. Figure 1 shows the Application Configuration dialog  box from the Internet Information Services Administrative Tool. Note  that the ASP.NET-related extensions—.aspx, .ascx, .config, .asmx, .rem,  .cs, .vb, and others—are all mapped to the aspnet_isapi.dll ISAPI  extension.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig01.gif" alt="1" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 1. Configured mappings for file extensions&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A thorough discussion of how IIS manages incoming requests is a bit  beyond the scope of this article. A great, in-depth discussion, though,  can be found in Michele Leroux Bustamante's article &lt;a href="http://www.theserverside.net/articles/showarticle.tss?id=IIS_ASP"&gt;Inside IIS and ASP.NET&lt;/a&gt;.  It's important to understand that the ASP.NET engine gets its hands  only on incoming Web requests whose extensions are explicitly mapped to  the aspnet_isapi.dll in IIS.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Examining Requests with ISAPI Filters&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;In addition to mapping the incoming Web request's file extension to  the appropriate ISAPI extension, IIS also performs a number of other  tasks. For example, IIS attempts to authenticate the user making the  request and determine if the authenticated user has authorization to  access the requested file. During the lifetime of handling a request,  IIS passes through several states. At each state, IIS raises an event  that can be programmatically handled using ISAPI filters.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Like ISAPI extensions, ISAPI filters are blocks of unmanaged code  installed on the Web server. ISAPI extensions are designed to generate  the response for a request to a particular file type. ISAPI filters, on  the other hand, contain code to respond to events raised by IIS. ISAPI  filters can intercept and even modify the incoming and outgoing data.  ISAPI filters have numerous applications, including: &lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;Authentication and authorization.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Logging and monitoring.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;HTTP compression.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;URL rewriting.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;While ISAPI filters can be used to perform URL rewriting, this  article examines implementing URL rewriting using ASP.NET. However, we  will discuss the tradeoffs between implementing URL rewriting as an  ISAPI filter versus using techniques available in ASP.NET.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;What Happens When a Request Enters the ASP.NET Engine&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Prior to ASP.NET, URL rewriting on IIS Web servers needed to be  implemented using an ISAPI filter. URL rewriting is possible with  ASP.NET because the ASP.NET engine is strikingly similar to IIS. The  similarities arise because the ASP.NET engine: &lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;Raises events as it processes a request.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Allows an arbitrary number of &lt;em&gt;HTTP modules&lt;/em&gt; handle the events that are raised, akin to IIS's ISAPI filters.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Delegates rendering the requested resource to an &lt;em&gt;HTTP handler&lt;/em&gt;, which is akin to IIS's ISAPI extensions.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p&gt;Like IIS, during the lifetime of a request the ASP.NET engine fires  events signaling its change from one state of processing to another.  The &lt;strong&gt;BeginRequest&lt;/strong&gt; event, for example, is fired when the ASP.NET engine first responds to a request. The &lt;strong&gt;AuthenticateRequest&lt;/strong&gt; event fires next, which occurs when the identity of the user has been established. (There are numerous other events—&lt;strong&gt;AuthorizeRequest&lt;/strong&gt;, &lt;strong&gt;ResolveRequestCache&lt;/strong&gt;, and &lt;strong&gt;EndRequest&lt;/strong&gt;, among others. These events are events of the &lt;strong&gt;System.Web.HttpApplication&lt;/strong&gt; class; for more information consult the &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/cpref/html/frlrfSystemWebHttpApplicationClassTopic.asp"&gt;HttpApplication Class Overview&lt;/a&gt; technical documentation.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As we discussed in the previous section, ISAPI filters can be  created to respond to the events raised by IIS. In a similar vein,  ASP.NET provides &lt;em&gt;HTTP modules&lt;/em&gt; that can respond to the events  raised by the ASP.NET engine. An ASP.NET Web application can be  configured to have multiple HTTP modules. For each request processed by  the ASP.NET engine, each configured HTTP module is initialized and  allowed to wire up event handlers to the events raised during the  processing of the request. Realize that there are a number of built-in  HTTP modules utilized on each an every request. One of the built-in  HTTP modules is the &lt;strong&gt;FormsAuthenticationModule&lt;/strong&gt;, which first  checks to see if forms authentication is being used and, if so, whether  the user is authenticated or not. If not, the user is automatically  redirected to the specified logon page.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Recall that with IIS, an incoming request is eventually directed to  an ISAPI extension, whose job it is to return the data for the  particular request. For example, when a request for a classic ASP Web  page arrives, IIS hands off the request to the asp.dll ISAPI extension,  whose task it is to return the HTML markup for the requested ASP page.  The ASP.NET engine utilizes a similar approach. After initializing the  HTTP modules, the ASP.NET engine's next task is to determine what &lt;em&gt;HTTP handler&lt;/em&gt; should process the request. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;All requests that pass through the ASP.NET engine eventually arrive  at an HTTP handler or an HTTP handler factory (an HTTP handler factory  simply returns an instance of an HTTP handler that is then used to  process the request). The final HTTP handler renders the requested  resource, returning the response. This response is sent back to IIS,  which then returns it to the user that made the request.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;ASP.NET includes a number of built-in HTTP handlers. The &lt;strong&gt;PageHandlerFactory&lt;/strong&gt;, for example, is used to render ASP.NET Web pages. The &lt;strong&gt;WebServiceHandlerFactory&lt;/strong&gt; is used to render the response SOAP envelopes for ASP.NET Web services. The &lt;strong&gt;TraceHandler&lt;/strong&gt; renders the HTML markup for requests to &lt;strong&gt;trace.axd&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Figure 2 illustrates how a request for an ASP.NET resource is  handled. First, IIS receives the request and dispatches it to  aspnet_isapi.dll. Next, the ASP.NET engine initializes the configured  HTTP modules. Finally, the proper HTTP handler is invoked and the  requested resource is rendered, returning the generated markup back to  IIS and back to the requesting client.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig02.gif" alt="2" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 2. Request processing by IIS and ASP.NET&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Creating and Registering Custom HTTP Modules and HTTP Handlers&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Creating custom HTTP modules and HTTP handlers are relatively simple  tasks, which involve created a managed class that implements the  correct interface. HTTP modules must implement the &lt;strong&gt;System.Web.IHttpModule&lt;/strong&gt; interface, while HTTP handlers and HTTP handler factories must implement the &lt;strong&gt;System.Web.IHttpHandler&lt;/strong&gt; interface and &lt;strong&gt;System.Web.IHttpHandlerFactory&lt;/strong&gt; interface, respectively. The specifics of creating HTTP handlers and  HTTP modules is beyond the scope of this article. For a good  background, read Mansoor Ahmed Siddiqui's article, &lt;a href="http://www.15seconds.com/issue/020417.htm"&gt;HTTP Handlers and HTTP Modules in ASP.NET&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once a custom HTTP module or HTTP handler has been created, it must  be registered with the Web application. Registering HTTP modules and  HTTP handlers for an entire Web server requires only a simple addition  to the machine.config file; registering an HTTP module or HTTP handler  for a specific Web application involves adding a few lines of XML to  the application's Web.config file.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Specifically, to add an HTTP module to a Web application, add the  following lines in the Web.config's configuration/system.web section:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;httpModules&amp;gt;     &amp;lt;add type="type" name="name" /&amp;gt;  &amp;lt;/httpModules&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The &lt;em&gt;type&lt;/em&gt; value provides the assembly and class name of the HTTP module, whereas the &lt;em&gt;name&lt;/em&gt; value provides a friendly name by which the HTTP module can be referred to in the Global.asax file.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;HTTP handlers and HTTP handler factories are configured by the  &amp;lt;httpHandlers&amp;gt; tag in the Web.config's configuration/system.web  section, like so:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;httpHandlers&amp;gt;     &amp;lt;add verb="verb" path="path" type="type" /&amp;gt;  &amp;lt;/httpHandlers&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Recall that for each incoming request, the ASP.NET engine determines  what HTTP handler should be used to render the request. This decision  is made based on the incoming requests verb and path. The verb  specifies what type of HTTP request was made—GET or POST—whereas the  path specifies the location and filename of the file requested. So, if  we wanted to have an HTTP handler handle all requests—either GET or  POST—for files with the .scott extension, we'd add the following to the  Web.config file:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;httpHandlers&amp;gt;     &amp;lt;add verb="*" path="*.scott" type="type" /&amp;gt;  &amp;lt;/httpHandlers&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;where &lt;em&gt;type&lt;/em&gt; was the type of our HTTP handler.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;When registering HTTP handlers, it is  important to ensure that the extensions used by the HTTP handler are  mapped in IIS to the ASP.NET engine. That is, in our .scott example, if  the .scott extension is not mapped in IIS to the aspnet_isapi.dll ISAPI  extension, a request for the file foo.scott will result in IIS  attempting to return the contents of the file foo.scott. In order for  the HTTP handler to process this request, the .scott extension must be  mapped to the ASP.NET engine. The ASP.NET engine, then, will route the  request correctly to the appropriate HTTP handler.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;For more information on registering HTTP modules and HTTP handlers, be sure to consult the &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/cpgenref/html/gngrfHttpmodulesSection.asp"&gt;&amp;lt;httpModules&amp;gt; element documentation&lt;/a&gt; along with the &lt;a href="http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/cpgenref/html/gngrfHttphandlersSection.asp"&gt;&amp;lt;httpHandlers&amp;gt; element documentation&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic4"&gt;&lt;/a&gt;Implementing URL Rewriting &lt;/h2&gt;&lt;br /&gt;&lt;p&gt;URL rewriting can be implemented either with ISAPI filters at the  IIS Web server level, or with either HTTP modules or HTTP handlers at  the ASP.NET level. This article focuses on implementing URL rewriting  with ASP.NET, so we won't be delving into the specifics of implementing  URL rewriting with ISAPI filters. There are, however, numerous  third-party ISAPI filters available for URL rewriting, such as: &lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.isapirewrite.com/"&gt;ISAPI Rewrite&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://www.qwerksoft.com/products/iisrewrite/"&gt;IIS Rewrite&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://port80software.com/products/pagexchanger/"&gt;PageXChanger&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;And many others!&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Implementing URL rewriting at the ASP.NET level is possible through the &lt;strong&gt;System.Web.HttpContext&lt;/strong&gt; class's &lt;strong&gt;RewritePath()&lt;/strong&gt; method. The &lt;strong&gt;HttpContext&lt;/strong&gt; class contains HTTP-specific information about a specific HTTP request. With each request received by the ASP.NET engine, an &lt;strong&gt;HttpContext&lt;/strong&gt; instance is created for that request. This class has properties like: &lt;strong&gt;Request&lt;/strong&gt; and &lt;strong&gt;Response&lt;/strong&gt;, which provide access to the incoming request and outgoing response; &lt;strong&gt;Application&lt;/strong&gt; and &lt;strong&gt;Session&lt;/strong&gt;, which provide access to application and session variables; &lt;strong&gt;User&lt;/strong&gt;, which provides information about the authenticated user; and other related properties. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;With the Microsoft® .NET Framework Version 1.0, the &lt;strong&gt;RewritePath()&lt;/strong&gt; method accepts a single string, the new path to use. Internally, the &lt;strong&gt;HttpContext&lt;/strong&gt; class's &lt;strong&gt;RewritePath(string)&lt;/strong&gt; method updates the &lt;strong&gt;Request&lt;/strong&gt; object's &lt;strong&gt;Path&lt;/strong&gt; and &lt;strong&gt;QueryString&lt;/strong&gt; properties. In addition to &lt;strong&gt;RewritePath(string)&lt;/strong&gt;, the .NET Framework Version 1.1 includes another form of the &lt;strong&gt;RewritePath()&lt;/strong&gt; method, one that accepts three string input parameters. This alternate overloaded form not only sets the &lt;strong&gt;Request&lt;/strong&gt; object's &lt;strong&gt;Path&lt;/strong&gt; and &lt;strong&gt;QueryString&lt;/strong&gt; properties, but also sets internal member variables that are used to compute the &lt;strong&gt;Request&lt;/strong&gt; object's values for its &lt;strong&gt;PhysicalPath&lt;/strong&gt;, &lt;strong&gt;PathInfo&lt;/strong&gt;, and &lt;strong&gt;FilePath&lt;/strong&gt; properties.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To implement URL rewriting in ASP.NET, then, we need to create an HTTP module or HTTP handler that: &lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;Checks the requested path to determine if the URL needs to be rewritten.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Rewrites the path, if needed, by calling the &lt;strong&gt;RewritePath()&lt;/strong&gt; method.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p&gt;For example, imagine that our website had information each employee,  accessible through /info/employee.aspx?empID=employeeID. To make the  URLs more "hackable," we might decide to have employee pages accessible  by: /people/EmployeeName.aspx. Here is a case where we'd want to use  URL rewriting. That is, when the page /people/ScottMitchell.aspx was  requested, we'd want to rewrite the URL so that the page  /info/employee.aspx?empID=1001 was used instead.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;URL Rewriting with HTTP Modules&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;When performing URL rewriting at the ASP.NET level you can use  either an HTTP module or an HTTP handler to perform the rewriting. When  using an HTTP module, you must decide at what point during the  request's lifecycle to check to see if the URL needs to be rewritten.  At first glance, this may seem to be an arbitrary choice, but the  decision can impact your application in both significant and subtle  ways. The choice of where to perform the rewrite matters because the  built-in ASP.NET HTTP modules use the &lt;strong&gt;Request&lt;/strong&gt; object's properties to perform their duties. (Recall that rewriting the path alters the &lt;strong&gt;Request&lt;/strong&gt; object's property values.) These germane built-in HTTP modules and the events they tie into are listed below:&lt;/p&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt; &lt;tbody&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="40%"&gt;&lt;strong&gt;HTTP Module&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="28%"&gt;&lt;strong&gt;Event&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="32%"&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="40%"&gt;&lt;strong&gt;FormsAuthenticationModule&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="28%"&gt;&lt;strong&gt;AuthenticateRequest&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="32%"&gt;Determines if the user is authenticated  using forms authentication. If not, the user is automatically  redirected to the specified logon page.&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="40%"&gt;&lt;strong&gt;FileAuthorizationMoudle&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="28%"&gt;&lt;strong&gt;AuthorizeRequest&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="32%"&gt;When using Windows authentication, this  HTTP module checks to ensure that the Microsoft® Windows® account has  adequate rights for the resource requested.&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="40%"&gt;&lt;strong&gt;UrlAuthorizationModule&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="28%"&gt;&lt;strong&gt;AuthorizeRequest&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="32%"&gt;Checks to make sure the requestor can  access the specified URL. URL authorization is specified through the  &amp;lt;authorization&amp;gt; and &amp;lt;location&amp;gt; elements in the Web.config  file.&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt; &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;Recall that the &lt;strong&gt;BeginRequest&lt;/strong&gt; event fires before &lt;strong&gt;AuthenticateRequest&lt;/strong&gt;, which fires before &lt;strong&gt;AuthorizeRequest&lt;/strong&gt;. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;One safe place that URL rewriting can be performed is in the &lt;strong&gt;BeginRequest&lt;/strong&gt; event. That means that if the URL needs to be rewritten, it will have  done so by the time any of the built-in HTTP modules run. The downside  to this approach arises when using forms authentication. If you've used  forms authentication before, you know that when the user visits a  restricted resource, they are automatically redirected to a specified  login page. After successfully logging in, the user is sent back to the  page they attempted to access in the first place. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;If URL rewriting is performed in the &lt;strong&gt;BeginRequest&lt;/strong&gt; or &lt;strong&gt;AuthenticateRequest &lt;/strong&gt;events,  the login page will, when submitted, redirect the user to the rewritten  page. That is, imagine that a user types into their browser window,  /people/ScottMitchell.aspx, which is rewritten to  /info/employee.aspx?empID=1001. If the Web application is configured to  use forms authentication, when the user first visits  /people/ScottMitchell.aspx, first the URL will be rewritten to  /info/employee.aspx?empID=1001; next, the &lt;strong&gt;FormsAuthenticationModule&lt;/strong&gt; will run, redirecting the user to the login page, if needed. The URL  the user will be sent to upon successfully logging in, however, will be  /info/employee.aspx?empID=1001, since that was the URL of the request  when the &lt;strong&gt;FormsAuthenticationModule&lt;/strong&gt; ran.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Similarly, when performing rewriting in the &lt;strong&gt;BeginRequest&lt;/strong&gt; or &lt;strong&gt;AuthenticateRequest&lt;/strong&gt; events, the &lt;strong&gt;UrlAuthorizationModule&lt;/strong&gt; sees the rewritten URL. That means that if you use &amp;lt;location&amp;gt;  elements in your Web.config file to specify authorization for specific  URLs, you will have to refer to the rewritten URL.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To fix these subtleties, you might decide to perform the URL rewriting in the &lt;strong&gt;AuthorizeRequest&lt;/strong&gt; event. While this approach fixes the URL authorization and forms  authentication anomalies, it introduces a new wrinkle: file  authorization no longer works. When using Windows authentication, the &lt;strong&gt;FileAuthorizationModule&lt;/strong&gt; checks to make sure that the authenticated user has the appropriate access rights to access the specific ASP.NET page.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Imagine if a set of users does not have Windows-level file access to  C:\Inetput\wwwroot\info\employee.aspx; if such users attempt to visit  /info/employee.aspx?empID=1001, then they will get an authorization  error. However, if we move the URL rewriting to the &lt;strong&gt;AuthenticateRequest&lt;/strong&gt; event, when the &lt;strong&gt;FileAuthorizationModule&lt;/strong&gt; checks the security settings, it still thinks the file being requested  is /people/ScottMitchell.aspx, since the URL has yet to be rewritten.  Therefore, the file authorization check will pass, allowing this user  to view the content of the rewritten URL,  /info/employee.aspx?empID=1001.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, when should URL rewriting be performed in an HTTP module? It  depends on what type of authentication you're employing. If you're not  using any authentication, then it doesn't matter if URL rewriting  happens in &lt;strong&gt;BeginRequest&lt;/strong&gt;, &lt;strong&gt;AuthenticateRequest&lt;/strong&gt;, or &lt;strong&gt;AuthorizeRequest&lt;/strong&gt;. If you are using forms authentication and are not using Windows authentication, place the URL rewriting in the &lt;strong&gt;AuthorizeRequest&lt;/strong&gt; event handler. Finally, if you are using Windows authentication, schedule the URL rewriting during the &lt;strong&gt;BeginRequest&lt;/strong&gt; or &lt;strong&gt;AuthenticateRequest&lt;/strong&gt; events.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;URL Rewriting in HTTP Handlers&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;URL rewriting can also be performed by an HTTP handler or HTTP  handler factory. Recall that an HTTP handler is a class responsible for  generating the content for a specific type of request; an HTTP handler  factory is a class responsible for returning an instance of an HTTP  handler that can generate the content for a specific type of request.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In this article we'll look at creating a URL rewriting HTTP handler  factory for ASP.NET Web pages. HTTP handler factories must implement  the &lt;strong&gt;IHttpHandlerFactory&lt;/strong&gt; interface, which includes a &lt;strong&gt;GetHandler()&lt;/strong&gt; method. After initializing the appropriate HTTP modules, the ASP.NET  engine determines what HTTP handler or HTTP handler factory to invoke  for the given request. If an HTTP handler factory is to be invoked, the  ASP.NET engine calls that HTTP handler factory's &lt;strong&gt;GetHandler()&lt;/strong&gt; method passing in the &lt;strong&gt;HttpContext&lt;/strong&gt; for the Web request, along with some other information. The HTTP handler factory, then, must return an object that implements &lt;strong&gt;IHttpHandler&lt;/strong&gt; that can handle the request.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To perform URL rewriting through an HTTP handler, we can create an HTTP handler factory whose &lt;strong&gt;GetHandler()&lt;/strong&gt; method checks the requested path to determine if it needs to be rewritten. If it does, it can call the passed-in &lt;strong&gt;HttpContext&lt;/strong&gt; object's &lt;strong&gt;RewritePath()&lt;/strong&gt; method, as discussed earlier. Finally, the HTTP handler factory can return the HTTP handler returned by the &lt;strong&gt;System.Web.UI.PageParser&lt;/strong&gt; class's &lt;strong&gt;GetCompiledPageInstance()&lt;/strong&gt; method. (This is the same technique by which the built-in ASP.NET Web page HTTP handler factory, &lt;strong&gt;PageHandlerFactory&lt;/strong&gt;, works.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Since all of the HTTP modules will have been initialized prior to  the custom HTTP handler factory being instantiated, using an HTTP  handler factory presents the same challenges when placing the URL  rewriting in the latter stages of the events—namely, file authorization  will not work. So, if you rely on Windows authentication and file  authorization, you will want to use the HTTP module approach for URL  rewriting.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Over the next section we'll look at building a reusable URL  rewriting engine. Following our examination of the URL rewriting  engine—which is available in this article's code download—we'll spend  the remaining two sections examining real-world uses of URL rewriting.  First we'll look at how to use the URL rewriting engine and look at a  simple URL rewriting example. Following that, we'll utilize the power  of the rewriting engine's regular expression capabilities to provide  truly "hackable" URLs.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic5"&gt;&lt;/a&gt;Building a URL Rewriting Engine&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;To help illustrate how to implement URL rewriting in an ASP.NET Web  application, I created a URL rewriting engine. This rewriting engine  provides the following functionality: &lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;The ASP.NET page developer utilizing the URL rewriting engine can specify the rewriting rules in the Web.config file.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;The rewriting rules can use regular expressions to allow for powerful rewriting rules.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;URL rewriting can be easily configured to use an HTTP module or an HTTP handler.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;In this article we will examine URL rewriting with just the HTTP  module. To see how HTTP handlers can be used to perform URL rewriting,  consult the code available for download with this article.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Specifying Configuration Information for the URL Rewriting Engine&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Let's examine the structure of the rewrite rules in the Web.config  file. First, you'll need to indicate in the Web.config file if you want  perform URL rewriting with the HTTP module or the HTTP handler. In the  download, the Web.config file contains two entries that have been  commented out:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;!--  &amp;lt;httpModules&amp;gt;     &amp;lt;add type="URLRewriter.ModuleRewriter, URLRewriter"           name="ModuleRewriter" /&amp;gt;  &amp;lt;/httpModules&amp;gt;  --&amp;gt;    &amp;lt;!--  &amp;lt;httpHandlers&amp;gt;     &amp;lt;add verb="*" path="*.aspx"           type="URLRewriter.RewriterFactoryHandler, URLRewriter" /&amp;gt;  &amp;lt;/httpHandlers&amp;gt;  --&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Comment out the &amp;lt;httpModules&amp;gt; entry to use the HTTP module for  rewriting; comment out the &amp;lt;httpHandlers&amp;gt; entry instead to use  the HTTP handler for rewriting.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In addition to specifying whether the HTTP module or HTTP handler is  used for rewriting, the Web.config file contains the rewriting rules. A  rewriting rule is composed of two strings: the pattern to look for in  the requested URL, and the string to replace the pattern with, if  found. This information is expressed in the Web.config file using the  following syntax:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;RewriterConfig&amp;gt;     &amp;lt;Rules&amp;gt;     &amp;lt;RewriterRule&amp;gt;        &amp;lt;LookFor&amp;gt;pattern to look for&amp;lt;/LookFor&amp;gt;        &amp;lt;SendTo&amp;gt;string to replace pattern with&amp;lt;/SendTo&amp;gt;     &amp;lt;/RewriterRule&amp;gt;     &amp;lt;RewriterRule&amp;gt;        &amp;lt;LookFor&amp;gt;pattern to look for&amp;lt;/LookFor&amp;gt;        &amp;lt;SendTo&amp;gt;string to replace pattern with&amp;lt;/SendTo&amp;gt;     &amp;lt;/RewriterRule&amp;gt;     ...     &amp;lt;/Rules&amp;gt;  &amp;lt;/RewriterConfig&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Each rewrite rule is expressed by a &lt;strong&gt;&amp;lt;RewriterRule&amp;gt;&lt;/strong&gt; element. The pattern to search for is specified by the &lt;strong&gt;&amp;lt;LookFor&amp;gt;&lt;/strong&gt; element, while the string to replace the found pattern with is entered in the &lt;strong&gt;&amp;lt;SentTo&amp;gt;&lt;/strong&gt; element. These rewrite rules are evaluated from top to bottom. If a  match is found, the URL is rewritten and the search through the  rewriting rules terminates.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When specifying patterns in the &lt;strong&gt;&amp;lt;LookFor&amp;gt;&lt;/strong&gt; element,  realize that regular expressions are used to perform the matching and  string replacement. (In a bit we'll look at a real-world example that  illustrates how to search for a pattern using regular expressions.)  Since the pattern is a regular expression, be sure to escape any  characters that are reserved characters in regular expressions. (Some  of the regular expression reserved characters include: ., ?, ^, $, and  others. These can be escaped by being preceded with a backslash, like  \. to match a literal period.)&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;URL Rewriting with an HTTP Module&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Creating an HTTP module is as simple as creating a class that implements the &lt;strong&gt;IHttpModule&lt;/strong&gt; interface. The &lt;strong&gt;IHttpModule&lt;/strong&gt; interface defines two methods: &lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;strong&gt;Init(HttpApplication)&lt;/strong&gt;. This method fires when the HTTP module is initialized. In this method you'll wire up event handlers to the appropriate &lt;strong&gt;HttpApplication&lt;/strong&gt; events.&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;strong&gt;Dispose()&lt;/strong&gt;. This method is invoked when the request has completed and been sent back to IIS. Any final cleanup should be performed here.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;To facilitate creating an HTTP module for URL rewriting, I started by creating an abstract base class, &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt;. This class implements &lt;strong&gt;IHttpModule&lt;/strong&gt;. In the &lt;strong&gt;Init()&lt;/strong&gt; event, it wires up the &lt;strong&gt;HttpApplication&lt;/strong&gt;'s &lt;strong&gt;AuthorizeRequest&lt;/strong&gt; event to the &lt;strong&gt;BaseModuleRewriter_AuthorizeRequest&lt;/strong&gt; method. The &lt;strong&gt;BaseModuleRewriter_AuthorizeRequest&lt;/strong&gt; method calls the class's &lt;strong&gt;Rewrite()&lt;/strong&gt; method passing in the requested &lt;strong&gt;Path&lt;/strong&gt; along with the &lt;strong&gt;HttpApplication&lt;/strong&gt; object that was passed into the &lt;strong&gt;Init()&lt;/strong&gt; method. The &lt;strong&gt;Rewrite()&lt;/strong&gt; method is abstract, meaning that in the &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; class, the &lt;strong&gt;Rewrite()&lt;/strong&gt; method has no method body; rather, the class being derived from &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; &lt;em&gt;must&lt;/em&gt; override this method and provide a method body.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;With this base class in place, all we have to do now is to create a class derived from &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; that overrides &lt;strong&gt;Rewrite()&lt;/strong&gt; and performs the URL rewriting logic there. The code for &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; is shown below.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;public abstract class BaseModuleRewriter : IHttpModule  {     public virtual void Init(HttpApplication app)     {        // WARNING!  This does not work with Windows authentication!        // If you are using Windows authentication,         // change to app.BeginRequest        app.AuthorizeRequest += new            EventHandler(this.BaseModuleRewriter_AuthorizeRequest);     }       public virtual void Dispose() {}       protected virtual void BaseModuleRewriter_AuthorizeRequest(       object sender, EventArgs e)     {        HttpApplication app = (HttpApplication) sender;        Rewrite(app.Request.Path, app);     }       protected abstract void Rewrite(string requestedPath,        HttpApplication app);  }  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Notice that the &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; class performs URL rewriting in the &lt;strong&gt;AuthorizeRequest&lt;/strong&gt; event. Recall that if you use Windows authentication with file  authorization, you will need to change this so that URL rewriting is  performed in either the &lt;strong&gt;BeginRequest&lt;/strong&gt; or &lt;strong&gt;AuthenticateRequest&lt;/strong&gt; events.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The &lt;strong&gt;ModuleRewriter&lt;/strong&gt; class extends the &lt;strong&gt;BaseModuleRewriter&lt;/strong&gt; class and is responsible for performing the actual URL rewriting. &lt;strong&gt;ModuleRewriter&lt;/strong&gt; contains a single overridden method—&lt;strong&gt;Rewrite()&lt;/strong&gt;—which is shown below:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;protected override void Rewrite(string requestedPath,      System.Web.HttpApplication app)  {     // get the configuration rules     RewriterRuleCollection rules =        RewriterConfiguration.GetConfig().Rules;       // iterate through each rule...     for(int i = 0; i &amp;lt; rules.Count; i++)     {        // get the pattern to look for, and         // Resolve the Url (convert ~ into the appropriate directory)        string lookFor = "^" +           RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,           rules[i].LookFor) + "$";          // Create a regex (note that IgnoreCase is set...)        Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);          // See if a match is found        if (re.IsMatch(requestedPath))        {           // match found - do any replacement needed           string sendToUrl =   RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,               re.Replace(requestedPath, rules[i].SendTo));             // Rewrite the URL           RewriterUtils.RewriteUrl(app.Context, sendToUrl);           break;      // exit the for loop        }     }  }  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The &lt;strong&gt;Rewrite()&lt;/strong&gt; method starts with getting the set of rewriting  rules from the Web.config file. It then iterates through the rewrite  rules one at a time, and for each rule, it grabs its &lt;strong&gt;LookFor&lt;/strong&gt; property and uses a regular expression to determine if a match is found in the requested URL.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If a match is found, a regular expression replace is performed on the requested path with the value of the &lt;strong&gt;SendTo&lt;/strong&gt; property. This replaced URL is then passed into the &lt;strong&gt;RewriterUtils.RewriteUrl()&lt;/strong&gt; method. &lt;strong&gt;RewriterUtils&lt;/strong&gt; is a helper class that provides a couple of static methods used by both the URL rewriting HTTP module and HTTP handler. The &lt;strong&gt;RewriterUrl()&lt;/strong&gt; method simply calls the &lt;strong&gt;HttpContext&lt;/strong&gt; object's &lt;strong&gt;RewriteUrl()&lt;/strong&gt; method.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;You may have noticed that when performing the regular expression match and replacement, a call to &lt;strong&gt;RewriterUtils.ResolveUrl()&lt;/strong&gt; is made. This helper method simply replaces any instances of &lt;strong&gt;~&lt;/strong&gt; in the string with the value of the application's path.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;The entire code for the URL rewriting engine is available for  download with this article. We've examined the most germane pieces, but  there are other components as well, such as classes for deserializing  the XML-formatted rewriting rules in the Web.config file into an  object, as well as the HTTP handler factory for URL rewriting. The  remaining three sections of this article examine real-world uses of URL  rewriting.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic6"&gt;&lt;/a&gt;Performing Simple URL Rewriting with the URL Rewriting Engine&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;To demonstrate the URL rewriting engine in action, let's build an  ASP.NET Web application that utilizes simple URL rewriting. Imagine  that we work for a company that sells assorted products online. These  products are broken down into the following categories:&lt;/p&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt; &lt;tbody&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;&lt;strong&gt;Category ID&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;&lt;strong&gt;Category Name&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;Beverages&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;Condiments&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;Confections&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;Dairy Products&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt;   &lt;tr valign="top"&gt;&lt;br /&gt;     &lt;td width="36%"&gt;...&lt;/td&gt;&lt;br /&gt;     &lt;td width="64%"&gt;...&lt;/td&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt; &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;Assume we already have created an ASP.NET Web page called  ListProductsByCategory.aspx that accepts a Category ID value in the  querystring and displays all of the products belonging to that  category. So, users who wanted to view our Beverages for sale would  visit ListProductsByCategory.aspx?CategoryID=1, while users who wanted  to view our Dairy Products would visit  ListProductsByCategory.aspx?CategoryID=4. Also assume we have a page  called ListCategories.aspx, which lists the categories of products for  sale.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Clearly this is a case for URL rewriting, as the URLs a user is  presented with do not carry any significance for the user, nor do they  provide any "hackability." Rather, let's employ URL rewriting so that  when a user visits /Products/Beverages.aspx, their URL will be  rewritten to ListProductsByCategory.aspx?CategoryID=1. We can  accomplish this with the following URL rewriting rule in the Web.config  file:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;RewriterConfig&amp;gt;     &amp;lt;Rules&amp;gt;        &amp;lt;!-- Rules for Product Lister --&amp;gt;        &amp;lt;RewriterRule&amp;gt;           &amp;lt;LookFor&amp;gt;~/Products/Beverages\.aspx&amp;lt;/LookFor&amp;gt;           &amp;lt;SendTo&amp;gt;~/ListProductsByCategory.aspx?CategoryID=1&amp;lt;/SendTo&amp;gt;        &amp;lt;/RewriterRule&amp;gt;        &amp;lt;RewriterRule&amp;gt;     &amp;lt;/Rules&amp;gt;  &amp;lt;/RewriterConfig&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;As you can see, this rule searches to see if the path requested by  the user was /Products/Beverages.aspx. If it was, it rewrites the URL  as /ListProductsByCategory.aspx?CategoryID=1.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;Notice that the &lt;strong&gt;&amp;lt;LookFor&amp;gt;&lt;/strong&gt; element escapes the period in Beverages.aspx. This is because the &lt;strong&gt;&amp;lt;LookFor&amp;gt;&lt;/strong&gt; value is used in a regular expression pattern, and period is a special  character in regular expressions meaning "match any character," meaning  a URL of /Products/BeveragesQaspx, for example, would match. By  escaping the period (using \.) we are indicating that we want to match  a literal period, and not any old character.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;With this rule in place, when a user visits  /Products/Beverages.aspx, they will be shown the beverages for sale.  Figure 3 shows a screenshot of a browser visiting  /Products/Beverages.aspx. Notice that in the browser's Address bar the  URL reads /Products/Beverages.aspx, but the user is actually seeing the  contents of ListProductsByCategory.aspx?CategoryID=1. (In fact, there  doesn't even exist a /Products/Beverages.aspx file on the Web server at  all!)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig03.gif" alt="3" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 3. Requesting category after rewriting URL&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Similar to /Products/Beverages.aspx, we'd next add rewriting rules  for the other product categories. This simply involves adding  additional &lt;strong&gt;&amp;lt;RewriterRule&amp;gt;&lt;/strong&gt; elements within the &lt;strong&gt;&amp;lt;Rules&amp;gt;&lt;/strong&gt; element in the Web.config file. Consult the Web.config file in the  download for the complete set of rewriting rules for the demo.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To make the URL more "hackable," it would be nice if a user could  simply hack off the Beverages.aspx from /Products/Beverages.aspx and be  shown a listing of the product categories. At first glance, this may  appear a trivial task—just add a rewriting rule that maps /Products/ to  /ListCategories.aspx. However, there is a fine subtlety—you must first  create a /Products/ directory and add an empty Default.aspx file in the  /Products/ directory.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To understand why these extra steps need to be performed, recall  that the URL rewriting engine is at the ASP.NET level. That is, if the  ASP.NET engine is never given the opportunity to process the request,  there's no way the URL rewriting engine can inspect the incoming URL.  Furthermore, remember that IIS hands off incoming requests to the  ASP.NET engine only if the requested file has an appropriate extension.  So if a user visits /Products/, IIS doesn't see any file extension, so  it checks the directory to see if there exists a file with one of the  default filenames. (Default.aspx, Default.htm, Default.asp, and so on.  These default filenames are defined in the Documents tab of the Web  Server Properties dialog box in the IIS Administration dialog box.) Of  course, if the /Products/ directory doesn't exist, IIS will return an  HTTP 404 error. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, we need to create the /Products/ directory. Additionally, we  need to create a single file in this directory, Default.aspx. This way,  when a user visits /Products/, IIS will inspect the directory, see that  there exists a file named Default.aspx, and then hand off processing to  the ASP.NET engine. Our URL rewriter, then, will get a crack at  rewriting the URL.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After creating the directory and Default.aspx file, go ahead and add the following rewriting rule to the &lt;strong&gt;&amp;lt;Rules&amp;gt;&lt;/strong&gt; element:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;RewriterRule&amp;gt;     &amp;lt;LookFor&amp;gt;~/Products/Default\.aspx&amp;lt;/LookFor&amp;gt;     &amp;lt;SendTo&amp;gt;~/ListCategories.aspx&amp;lt;/SendTo&amp;gt;  &amp;lt;/RewriterRule&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;With this rule in place, when a user visits /Products/ or  /Products/Default.aspx, they will see the listing of product  categories, shown in Figure 4.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig04.gif" alt="4" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 4. Adding "hackability" to the URL&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Handling Postbacks&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;If the URLs you are rewriting contain a server-side Web Form and  perform postbacks, when the form posts back, the underlying URL will be  used. That is, if our user enters into their browser,  /Products/Beverages.aspx, they will still see in their browser's  Address bar, /Products/Beverages.aspx, but they will be shown the  content for ListProductsByCategory.aspx?CategoryID=1. If  ListProductsByCategory.aspx performs a postback, the user will be  posted back to ListProductsByCategory.aspx?CategoryID=1, not  /Products/Beverages.aspx. This won't break anything, but it can be  disconcerting from the user's perspective to see the URL change  suddenly upon clicking a button.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The reason this behavior happens is because when the Web Form is  rendered, it explicitly sets its action attribute to the value of the  file path in the &lt;strong&gt;Request&lt;/strong&gt; object. Of course, by the time the Web  Form is rendered, the URL has been rewritten from  /Products/Beverages.aspx to ListProductsByCategory.aspx?CategoryID=1,  meaning the &lt;strong&gt;Request&lt;/strong&gt; object is reporting that the user is  visiting ListProductsByCategory.aspx?CategoryID=1. This problem can be  fixed by having the server-side form simply not render an action  attribute. (Browsers, by default, will postback if the form doesn't  contain an action attribute.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Unfortunately, the Web Form does not allow you to explicitly specify  an action attribute, nor does it allow you to set some property to  disable the rendering of the action attribute. Rather, we'll have to  extend the &lt;strong&gt;System.Web.HtmlControls.HtmlForm&lt;/strong&gt; class ourselves, overriding the &lt;strong&gt;RenderAttribute()&lt;/strong&gt; method and explicitly indicating that it not render the action attribute.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Thanks to the power of inheritance, we can gain all of the functionality of the &lt;strong&gt;HtmlForm&lt;/strong&gt; class and only have to add a scant few lines of code to achieve the  desired behavior. The complete code for the custom class is shown below:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;namespace ActionlessForm {    public class Form : System.Web.UI.HtmlControls.HtmlForm    {       protected override void RenderAttributes(HtmlTextWriter writer)       {          writer.WriteAttribute("name", this.Name);          base.Attributes.Remove("name");            writer.WriteAttribute("method", this.Method);          base.Attributes.Remove("method");            this.Attributes.Render(writer);            base.Attributes.Remove("action");            if (base.ID != null)             writer.WriteAttribute("id", base.ClientID);       }    }  }  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The code for the overridden &lt;strong&gt;RenderAttributes()&lt;/strong&gt; method simply contains the exact code from the &lt;strong&gt;HtmlForm&lt;/strong&gt; class's &lt;strong&gt;RenderAttributes()&lt;/strong&gt; method, but without setting the action attribute. (I used Lutz Roeder's &lt;a href="http://www.aisto.com/roeder/DotNet/"&gt;Reflector&lt;/a&gt; to view the source code of the &lt;strong&gt;HtmlForm&lt;/strong&gt; class.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once you have created this class and compiled it, to use it in an  ASP.NET Web application, start by adding it to the Web application's  References folder. Then, to use it in place of the &lt;strong&gt;HtmlForm&lt;/strong&gt; class, simply add the following to the top of your ASP.NET Web page:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;%@ Register TagPrefix="skm" Namespace="ActionlessForm"      Assembly="ActionlessForm" %&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Then, where you have &amp;lt;form runat="server"&amp;gt;, replace that with:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;skm:Form id="Form1" method="post" runat="server"&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;and replace the closing &amp;lt;/form&amp;gt; tag with:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;/skm:Form&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;You can see this custom Web Form class in action in  ListProductsByCategory.aspx, which is included in this article's  download. Also included in the download is a Visual Studio .NET project  for the action-less Web Form.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;If the URL you are rewriting to does not perform a postback, there's no need to use this custom Web Form class.&lt;/blockquote&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic7"&gt;&lt;/a&gt;Creating Truly "Hackable" URLs&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The simple URL rewriting demonstrated in the previous section showed  how easily the URL rewriting engine can be configured with new  rewriting rules. The true power of the rewriting rules, though, shines  when using regular expressions, as we'll see in this section.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Blogs are becoming more and more popular these days, and it seems &lt;em&gt;everyone&lt;/em&gt; has their own blog. If you are not familiar with blogs, they are  often-updated personal pages that typically serve as an online journal.  Most bloggers simply write about their day-to-day happenings, others  focus on blogging about a specific theme, such as movie reviews, a  sports team, or a computer technology.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Depending on the author, blogs are updated anywhere from several  times a day to once every week or two. Typically the blog homepage  shows the most recent 10 entries, but virtually all blogging software  provides an archive through which visitors can read older postings.  Blogs are a great application for "hackable" URLs. Imagine while  searching through the archives of a blog you found yourself at the URL  /2004/02/14.aspx. Would you be terribly surprised if you found yourself  reading the posts made on February 14th, 2004? Furthermore, you might  want to view all posts for February 2004, in which case you might try  hacking the URL to /2004/02/. To view all 2004 posts, you might try  visiting /2004/.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When maintaining a blog, it would be nice to provide this level of  URL "hackability" to your visitors. While many blog engines provide  this functionality, let's look at how it can be accomplished using URL  rewriting. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;First, we need a single ASP.NET Web page that will show blog entries  by day, month, or year. Assume we have such a page,  ShowBlogContent.aspx, that takes in querystring parameters year, month,  and day. To view the posts for February 14th, 2004, we could visit  ShowBlogContent.aspx?year=2004&amp;amp;month=2&amp;day=14. To view all  posts for February 2004, we'd visit  ShowBlogContent.aspx?year=2004&amp;amp;month=2. Finally, to see all posts  for the year 2004, we'd navigate to ShowBlogContent.aspx?year=2004.  (The code for ShowBlogContent.aspx can be found in this article's  download.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, if a user visits /2004/02/14.aspx, we need to rewrite the URL to  ShowBlogContent.aspx?year=2004&amp;amp;month=2&amp;day=14. All three  cases—when the URL specifies a year, month, and day; when the URL  specifies just the year and month; and when the URL specifies only the  yea—can be handled with three rewrite rules:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&amp;lt;RewriterConfig&amp;gt;     &amp;lt;Rules&amp;gt;        &amp;lt;!-- Rules for Blog Content Displayer --&amp;gt;        &amp;lt;RewriterRule&amp;gt;           &amp;lt;LookFor&amp;gt;~/(\d{4})/(\d{2})/(\d{2})\.aspx&amp;lt;/LookFor&amp;gt;           &amp;lt;SendTo&amp;gt;~/ShowBlogContent.aspx?year=$1&amp;amp;amp;month=$2&amp;amp;day=$3&amp;lt;/SendTo&amp;gt;        &amp;lt;/RewriterRule&amp;gt;        &amp;lt;RewriterRule&amp;gt;           &amp;lt;LookFor&amp;gt;~/(\d{4})/(\d{2})/Default\.aspx&amp;lt;/LookFor&amp;gt;           &amp;lt;SendTo&amp;gt;&amp;lt;![CDATA[~/ShowBlogContent.aspx?year=$1&amp;month=$2]]&amp;gt;&amp;lt;/SendTo&amp;gt;        &amp;lt;/RewriterRule&amp;gt;        &amp;lt;RewriterRule&amp;gt;           &amp;lt;LookFor&amp;gt;~/(\d{4})/Default\.aspx&amp;lt;/LookFor&amp;gt;           &amp;lt;SendTo&amp;gt;~/ShowBlogContent.aspx?year=$1&amp;lt;/SendTo&amp;gt;        &amp;lt;/RewriterRule&amp;gt;     &amp;lt;/Rules&amp;gt;  &amp;lt;/RewriterConfig&amp;gt;  &lt;/pre&gt;&lt;br /&gt;&lt;p&gt;These rewriting rules demonstrate the power of regular expressions.  In the first rule, we look for a URL with the pattern  (\d{4})/(\d{2})/(\d{2})\.aspx. In plain English, this matches a string  that has four digits followed by a forward slash followed by two digits  followed by a forward slash, followed by two digits followed by .aspx.  The parenthesis around each digit grouping is vital—it allows us to  refer to the matched characters inside those parentheses in the  corresponding &lt;strong&gt;&amp;lt;SendTo&amp;gt;&lt;/strong&gt; property. Specifically, we can  refer back to the matched parenthetical groupings using $1, $2, and $3  for the first, second, and third parenthesis grouping, respectively.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;Since the Web.config file is XML-formatted,  characters like &amp;, &amp;lt;, and &amp;gt; in the text portion of an element  must be escaped. In the first rule's &lt;strong&gt;&amp;lt;SendTo&amp;gt;&lt;/strong&gt; element, &amp; is escaped to &amp;amp;amp;amp;. In the second rule's &lt;strong&gt;&amp;lt;SendTo&amp;gt;&lt;/strong&gt;, an alternative technique is used—by using a &lt;strong&gt;&amp;lt;![CDATA[...]]&amp;gt;&lt;/strong&gt; element, the contents inside do not need to be escaped. Either approach is acceptable and accomplishes the same end.&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Figures 5, 6, and 7 show the URL rewriting in action. The data is actually being pulled from my blog, &lt;a href="http://ScottOnWriting.NET"&gt;http://ScottOnWriting.NET&lt;/a&gt;.  In Figure 5, the posts for November 7, 2003 are shown; in Figure 6 all  posts for November 2003 are shown; Figure 7 shows all posts for 2003.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig05.gif" alt="5" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 5. Posts for November 7, 2003&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig06.gif" alt="5" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 6. All posts for November 2003&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/urlrewriting_fig07.gif" alt="6" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 7. All posts for 2003&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt; &lt;strong&gt;Note   &lt;/strong&gt;The URL rewriting engine expects a regular expression pattern in the &lt;strong&gt;&amp;lt;LookFor&amp;gt;&lt;/strong&gt; elements. If you are unfamiliar with regular expressions, consider reading an earlier article of mine, &lt;a href="http://www.4guysfromrolla.com/webtech/090199-1.shtml"&gt;An Introduction to Regular Expressions&lt;/a&gt;.  Also, a great place to get your hands on commonly used regular  expressions, as well as a repository for sharing your own crafted  regular expressions, is &lt;a href="http://regexlib.com/"&gt;RegExLib.com&lt;/a&gt;.&lt;/blockquote&gt;&lt;br /&gt;&lt;h3&gt;Building the Requisite Directory Structure&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;When a request comes in for /2004/03/19.aspx, IIS notes the .aspx  extension and routes the request to the ASP.NET engine. As the request  moves through the ASP.NET engine's pipeline, the URL will get rewritten  to ShowBlogContent.aspx?year=2004&amp;amp;month=03&amp;day=19 and the  visitor will see those blog entries for March 19, 2004. But what  happens when the user navigates to /2004/03/? Unless there is a  directory /2004/03/, IIS will return a 404 error. Furthermore, there  needs to be a Default.aspx page in this directory so that the request  is handed off to the ASP.NET engine.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So with this approach, you have to manually create a directory for  each year in which there are blog entries, with a Default.aspx page in  the directory. Additionally, in each year directory you need to  manually create twelve more directories—01, 02, …, 12—each with a  Default.aspx file. (Recall that we had to do the same thing—add a  /Products/ directory with a Default.aspx file—in the previous demo so  that visiting /Products/ correctly displayed ListCategories.aspx.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Clearly, adding such a directory structure can be a pain. A  workaround to this problem is to have all incoming IIS requests map to  the ASP.NET engine. This way, even if when visiting the URL /2004/03/,  IIS will faithfully hand off the request to the ASP.NET engine even if  there does not exist a /2004/03/ directory. Using this approach,  however, makes the ASP.NET engine responsible for handling all types of  incoming requests to the Web server, including images, CSS files,  external JavaScript files, Macromedia Flash files, and so on.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A thorough discussion of handling all file types is far beyond the  scope of this article. For an example of an ASP.NET Web application  that uses this technique, though, look into &lt;a href="http://www.gotdotnet.com/community/workspaces/default.aspx"&gt;.Text&lt;/a&gt;,  an open-source blog engine. .Text can be configured to have all  requests mapped to the ASP.NET engine. It can handle serving all file  types by using a custom HTTP handler that knows how to serve up typical  static file types (images, CSS files, and so on).&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic8"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;In this article we examined how to perform URL rewriting at the ASP.NET-level through the &lt;strong&gt;HttpContext&lt;/strong&gt; class's &lt;strong&gt;RewriteUrl()&lt;/strong&gt; method. As we saw, &lt;strong&gt;RewriteUrl()&lt;/strong&gt; updates the particular &lt;strong&gt;HttpContext's&lt;/strong&gt; &lt;strong&gt;Request&lt;/strong&gt; property, updating what file and path is being requested. The net  effect is that, from the user's perspective, they are visiting a  particular URL, but actually a different URL is being requested on the  Web server side.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;URLs can be rewritten either in an HTTP module or an HTTP handler.  In this article we examined using an HTTP module to perform the  rewriting, and looked at the consequences of performing the rewriting  at different stages in the pipeline.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Of course, with ASP.NET-level rewriting, the URL rewriting can only  happen if the request is successfully handed off from IIS to the  ASP.NET engine. This naturally occurs when the user requests a page  with a .aspx extension. However, if you want the person to be able to  enter a URL that might not actually exist, but would rather rewrite to  an existing ASP.NET page, you have to either create mock directories  and Default.aspx pages, or configure IIS so that all incoming requests  are blindly routed to the ASP.NET engine.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;a name="urlrewriting_topic10"&gt;&lt;/a&gt;Related Books&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=12237&amp;amp;prodId=734042"&gt;ASP.NET: Tips, Tutorials, and Code&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=4650&amp;prodId=1627168"&gt;Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET Team&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=12231&amp;amp;prodId=1528348"&gt;Essential ASP.NET with Examples in C#&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;h4&gt;Works consulted&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;URL rewriting is a topic that has received a lot of attention both  for ASP.NET and competing server-side Web technologies. The Apache Web  server, for instance, provides a module for URL rewriting called &lt;a href="http://httpd.apache.org/docs/mod/mod_rewrite.html"&gt;mod_rewrite&lt;/a&gt;.  mod_rewrite is a robust rewriting engine, providing rewriting rules  based on conditions such as HTTP headers and server variables, as well  as rewriting rules that utilize regular expressions. For more  information on mod_rewrite, check out &lt;a href="http://www.engelschall.com/pw/apache/rewriteguide/"&gt;A User's Guide to URL Rewriting with the Apache Web Server&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There are a number of articles on URL rewriting with ASP.NET. &lt;a href="http://www.15seconds.com/issue/030522.htm"&gt;Rewrite.NET - A URL Rewriting Engine for .NET&lt;/a&gt; examines creating a URL rewriting engine that mimics mod_rewrite's regular expression rules. &lt;a href="http://www.codeproject.com/aspnet/URLRewriter.asp"&gt;URL Rewriting With ASP.NET&lt;/a&gt; also gives a good overview of ASP.NET's URL rewriting capabilities. &lt;a href="http://www.interact-sw.co.uk/iangblog/"&gt;Ian Griffiths&lt;/a&gt; has a &lt;a href="http://www.interact-sw.co.uk/iangblog/2004/01/12/shinyurl"&gt;blog entry&lt;/a&gt; on some of the caveats associated with URL rewriting with ASP.NET, such as the postback issue discussed in this article. Both &lt;a href="http://weblogs.asp.net/fmarguerie/"&gt;Fabrice Marguerie&lt;/a&gt; (&lt;a href="http://weblogs.asp.net/fmarguerie/archive/2003/12/24/45712.aspx"&gt;read more&lt;/a&gt;) and &lt;a href="http://weblogs.asp.net/jasonsalas/"&gt;Jason Salas&lt;/a&gt; (&lt;a href="http://weblogs.asp.net/jasonsalas/archive/2003/12/14/43404.aspx"&gt;read more&lt;/a&gt;) have blog entires on using URL rewriting to boost search engine placement.&lt;/p&gt;&lt;br /&gt;&lt;hr noshade="noshade" size="1"&gt;&lt;br /&gt;&lt;strong&gt;About the author&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;Scott Mitchell, author of five books and founder of  4GuysFromRolla.com, has been working with Microsoft Web technologies  for the past five years. Scott works as an independent consultant,  trainer, and writer. He can be reached at &lt;a href="mailto:mitchell@4guysfromrolla.com"&gt;mitchell@4guysfromrolla.com&lt;/a&gt; or through his blog, which can be found at &lt;a href="http://ScottOnWriting.NET"&gt;http://ScottOnWriting.NET&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-114095356813291933?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095356813291933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095356813291933'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/02/url-rewriting-in-aspnet.html' title='URL Rewriting in ASP.NET'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-114095294382864840</id><published>2006-02-26T18:21:00.000+07:00</published><updated>2006-02-26T18:25:19.216+07:00</updated><title type='text'>A Matter of Context</title><content type='html'>A Matter of Context&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Susan Warren&lt;br /&gt;Microsoft Corporation&lt;br /&gt;&lt;br /&gt;January 14, 2002&lt;br /&gt;&lt;br /&gt;One of the most common problems with writing Web applications is letting your code know the context in which it's being executed. Let's look at a simple example—personalizing a page—that illustrates this problem:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Please sign in.&lt;br /&gt;&lt;br /&gt;vs.&lt;br /&gt;&lt;br /&gt;Welcome Susan!&lt;br /&gt;&lt;br /&gt;Seems simple enough, but even this tiny bit of Web UI requires a couple of bits of information that will vary each time the page is requested. I'll need to know:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   1. Is the user signed in?&lt;br /&gt;&lt;br /&gt;   2. What is the user's display name?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;More generally, what is the unique context each time the page is requested? And how can I write my code so that it takes this information into account?&lt;br /&gt;&lt;br /&gt;In fact, due to the stateless nature of HTTP, there are many different pieces of context a Web application might need to track. When a user interacts with a Web application, the browser sends a series of independent HTTP requests to the Web server. The application itself has to do the work of knitting these requests into a pleasing experience for the user and knowing the context of the request is critical.&lt;br /&gt;&lt;br /&gt;ASP introduced several intrinsic objects like Request and Application to help track the context for an HTTP request. ASP.NET takes the next step and bundles these objects, plus several additional context-related objects into an extremely handy intrinsic object called Context.&lt;br /&gt;&lt;br /&gt;Context is an object of type System.Web.HttpContext. It is exposed as a property of the ASP.NET Page class. It's also available from user controls and your business objects (more on that later). Here's a partial list of the objects rolled up by HttpContext:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Object&lt;br /&gt;    Description&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Application&lt;br /&gt;    A key/value pair collection of values that is accessible by every user of the application. Application is of type System.Web.HttpApplicationState.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ApplicationInstance&lt;br /&gt;    The actual running application, which exposes some request processing events. These events are handled in Global.asax, or an HttpHandler or HttpModule.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Cache&lt;br /&gt;    The ASP.NET Cache object, which provides programmatic access to the cache. Rob Howard's ASP.NET Caching column provides a good introduction to caching.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Error&lt;br /&gt;    The first error (if any) encountered while processing the page. See Rob's Exception to the Rule, Part 1 for more information.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Items&lt;br /&gt;    A key-value pair collection that you can use to pass information between all of the components that participate in the processing of a single request. Items is of type System.Collections.IDictionary.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Request&lt;br /&gt;    Information about the HTTP request, including browser information, cookies, and values passed in a form or on the query string. Request is of type System.Web.HttpRequest.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Response&lt;br /&gt;    Settings and content for creating the HTTP response. Request is of type System.Web.HttpResponse.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Server&lt;br /&gt;    Server is a utility class with several useful helper methods, including Server.Execute(), Server.MapPath(), and Server.HtmlEncode(). Server is an object of type System.Web.HttpServerUtility.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Session&lt;br /&gt;    A key/value pair collection of values that are accessible by a single user of the application. Application is of type System.Web.HttpSessionState.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Trace&lt;br /&gt;    The ASP.NET Trace object, which provides access to tracing functionality. See Rob's Tracing article for more information.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;User&lt;br /&gt;    The security context of the current user, if authenticated. Context.User.Identity is the user's name. User is an object of type System.Security.Principal.IPrincipal.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you're an ASP developer, some of the objects above will look quite familiar. There are a few enhancements, but for the most part, they work exactly the same in ASP.NET as in ASP.&lt;br /&gt;&lt;br /&gt;Context Basics&lt;br /&gt;&lt;br /&gt;Some of the objects in Context are also promoted as top-level objects on Page. For example, Page.Context.Response and Page.Response reference the same object so the following code is equivalent:&lt;br /&gt;&lt;br /&gt;[Visual Basic® Web Form]&lt;br /&gt;&lt;br /&gt;   Response.Write ("Hello ")&lt;br /&gt;Context.Response.Write ("There")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C# Web Form]&lt;br /&gt;&lt;br /&gt;   Response.Write ("Hello ");&lt;br /&gt;Context.Response.Write ("There");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can also use the Context object from your business objects. HttpContext.Current is a static property that conveniently returns the context for the current request. This is useful in all kinds of ways, but here's a simple example of retrieving an item from the cache in your business class:&lt;br /&gt;&lt;br /&gt;[Visual Basic]&lt;br /&gt;&lt;br /&gt;      ' get the request context&lt;br /&gt;Dim _context As HttpContext = HttpContext.Current&lt;br /&gt;&lt;br /&gt;' get dataset from the cache&lt;br /&gt;Dim _data As DataSet = _context.Cache("MyDataSet")&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C#]&lt;br /&gt;&lt;br /&gt;      // get the request context&lt;br /&gt;HttpContext _context = HttpContext.Current;&lt;br /&gt;&lt;br /&gt;// get dataset from cache&lt;br /&gt;DataSet _data = _context.Cache("MyDataSet");&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Context in Action&lt;br /&gt;&lt;br /&gt;The Context object provides The Answer to several common ASP.NET "How Do I ...?" questions. Perhaps the best way to communicate just how valuable this gem can be is to show it in action. Here are a few of the best Context tricks I know.&lt;br /&gt;&lt;br /&gt;How Do I Emit an ASP.NET Trace Statement From My Business Class?&lt;br /&gt;&lt;br /&gt;Answer: Easy! Use HttpContext.Current to get the Context object, then call Context.Trace.Write().&lt;br /&gt;&lt;br /&gt;[Visual Basic]&lt;br /&gt;&lt;br /&gt;Imports System&lt;br /&gt;Imports System.Web&lt;br /&gt;&lt;br /&gt;Namespace Context&lt;br /&gt;&lt;br /&gt;' Demonstrates emitting an ASP.NET trace statement from a&lt;br /&gt;' business class.&lt;br /&gt;&lt;br /&gt;Public Class TraceEmit&lt;br /&gt;&lt;br /&gt;Public Sub SomeMethod()&lt;br /&gt;&lt;br /&gt;   ' get the request context&lt;br /&gt;   Dim _context As HttpContext = HttpContext.Current&lt;br /&gt;&lt;br /&gt;   ' use context to write the trace statement&lt;br /&gt;   _context.Trace.Write("in TraceEmit.SomeMethod")&lt;br /&gt;&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;End Namespace&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C#]&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web;&lt;br /&gt;&lt;br /&gt;namespace Context&lt;br /&gt;{&lt;br /&gt;// Demonstrates emitting an ASP.NET trace statement from a&lt;br /&gt;// business class.&lt;br /&gt;&lt;br /&gt;public class TraceEmit&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  public void SomeMethod() {&lt;br /&gt;&lt;br /&gt;      // get the request context&lt;br /&gt;      HttpContext _context = HttpContext.Current;&lt;br /&gt;&lt;br /&gt;      // use context to write the trace statement&lt;br /&gt;      _context.Trace.Write("in TraceEmit.SomeMethod");&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How Can I Access a Session State Value From My Business Class?&lt;br /&gt;&lt;br /&gt;Answer: Easy! Use HttpContext.Current to get the Context object, then access Context.Session.&lt;br /&gt;&lt;br /&gt;[Visual Basic]&lt;br /&gt;&lt;br /&gt;Imports System&lt;br /&gt;Imports System.Web&lt;br /&gt;&lt;br /&gt;Namespace Context&lt;br /&gt;&lt;br /&gt;' Demonstrates accessing the ASP.NET Session intrinsic&lt;br /&gt;' from a business class.&lt;br /&gt;&lt;br /&gt;Public Class UseSession&lt;br /&gt;&lt;br /&gt;Public Sub SomeMethod()&lt;br /&gt;&lt;br /&gt;   ' get the request context&lt;br /&gt;   Dim _context As HttpContext = HttpContext.Current&lt;br /&gt;&lt;br /&gt;   ' access the Session intrinsic&lt;br /&gt;   Dim _value As Object = _context.Session("TheValue")&lt;br /&gt;&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;End Namespace&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C#]&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web;&lt;br /&gt;&lt;br /&gt;namespace Context&lt;br /&gt;{&lt;br /&gt;// Demonstrates accessing the ASP.NET Session intrinsic&lt;br /&gt;// from a business class.&lt;br /&gt;&lt;br /&gt;public class UseSession&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  public void SomeMethod() {&lt;br /&gt;&lt;br /&gt;      // get the request context&lt;br /&gt;      HttpContext _context = HttpContext.Current;&lt;br /&gt;&lt;br /&gt;      // access the Session intrinsic&lt;br /&gt;      object _value = _context.Session["TheValue"];&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How Can I Add a Standard Header and Footer to Every Page in My Application?&lt;br /&gt;&lt;br /&gt;Answer: Handle the application's BeginRequest and EndRequest events, and use Context.Response.Write to emit the HTML for the header and footer.&lt;br /&gt;&lt;br /&gt;Technically, you can handle the application events like BeginRequest in either an HttpModule or by using Global.asax. HttpModules are a bit harder to write, and aren't typically used for functionality that is used by a single application, as in this example. So, we'll use the application-scoped Global.asax file instead.&lt;br /&gt;&lt;br /&gt;As with an ASP page, several of the ASP.NET context intrinsics are promoted to be properties of the HttpApplication class, from which the class representing Global.asax inherits. We won't need to use HttpContext.Current to get a reference to the Context object; it's already available in Global.asax.&lt;br /&gt;&lt;br /&gt;In this example, I'm putting the and tags, plus a horizontal rule into the header section, and another horizontal rule plus the end tags for these into the footer section. The footer also contains a copyright message. The result looks like the figure below:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 1. Example of standard header and footer as rendered in the browser&lt;br /&gt;&lt;br /&gt;This is a trivial example, but you can easily extend this to include your standard header and navigation, or simply output the&lt;br /&gt;&lt;br /&gt;statements for these. One caveat—if you want the header or footer to include interactive content, you should consider using ASP.NET user controls instead.&lt;br /&gt;&lt;br /&gt;[SomePage.aspx source—sample content]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Normal Page Content&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[Visual Basic Global.asax]&lt;br /&gt;&lt;br /&gt;&lt;%@ Application Language="VB" %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C# Global.asax]&lt;br /&gt;&lt;br /&gt;&lt;%@ Application Language="C#" %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How Can I Show A Welcome Message When The User Is Authenticated?&lt;br /&gt;&lt;br /&gt;The Answer: Test the User context object to see if the user is authenticated. If so, get the user's name from the User object too. This is, of course, the example from the beginning of the article.&lt;br /&gt;&lt;br /&gt;[Visual Basic]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C#]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And Now for Something Really Wonderful: Context.Items&lt;br /&gt;&lt;br /&gt;I hope the examples above show how much easier it is to write your Web application with a little context information at hand. Wouldn't it be great to be able to access some context that is unique to your application in the same way?&lt;br /&gt;&lt;br /&gt;That's the purpose of the Context.Items collection. It holds your application's request-specific values in a way that is available to every part of your code that participates in the processing of a request. For example, the same piece of information can be used in Global.asax, in your ASPX page, in the user controls within the page, and by the business logic the page calls.&lt;br /&gt;&lt;br /&gt;Consider the IBuySpy Portal sample application. It uses a single main page—DesktopDefault.aspx—to display portal content. Which content is displayed depends on which tab is selected, as well as the roles of the user, if authenticated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Figure 2. IbuySpy home page&lt;br /&gt;&lt;br /&gt;The querystring includes the TabIndex and TabId parameters for the tab being requested. This information is used throughout the processing of the request to filter which data is displayed to the user. http://www.ibuyspy.com/portal/DesktopDefault.aspx?tabindex=1&amp;tabid=2&lt;br /&gt;&lt;br /&gt;To use a querystring value, you need to first make sure it's a valid value and, if not, do a little error handling. It's not a lot of code, but do you really want to duplicate it in every page and component that uses the value? Of course not! In the Portal sample it is even more involved since there is other information that can be preloaded once we know the TabId.&lt;br /&gt;&lt;br /&gt;The Portal uses the querystring values as parameters to construct a new "PortalSettings" object and add it to Context.Items in the BeginRequest event in Global.asax. Since the begin request is executed at the beginning of each request, this makes the tab-related values available to all of the pages and components in the application. When the request is complete, the object is automatically discarded—very tidy!&lt;br /&gt;&lt;br /&gt;[Visual Basic Global.asax]&lt;br /&gt;&lt;br /&gt;      Sub Application_BeginRequest(sender As [Object], e As EventArgs)&lt;br /&gt;&lt;br /&gt;   Dim tabIndex As Integer = 0&lt;br /&gt;   Dim tabId As Integer = 0&lt;br /&gt;&lt;br /&gt;   ' Get TabIndex from querystring&lt;br /&gt;   If Not (Request.Params("tabindex") Is Nothing) Then&lt;br /&gt;      tabIndex = Int32.Parse(Request.Params("tabindex"))&lt;br /&gt;   End If&lt;br /&gt;&lt;br /&gt;   ' Get TabID from querystring&lt;br /&gt;   If Not (Request.Params("tabid") Is Nothing) Then&lt;br /&gt;      tabId = Int32.Parse(Request.Params("tabid"))&lt;br /&gt;   End If&lt;br /&gt;&lt;br /&gt;   Context.Items.Add("PortalSettings", _&lt;br /&gt;New PortalSettings(tabIndex, tabId))&lt;br /&gt;&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[C# Global.asax]&lt;br /&gt;&lt;br /&gt;void Application_BeginRequest(Object sender, EventArgs e) {&lt;br /&gt;&lt;br /&gt;int tabIndex = 0;&lt;br /&gt;int tabId = 0;&lt;br /&gt;&lt;br /&gt;// Get TabIndex from querystring&lt;br /&gt;&lt;br /&gt;if (Request.Params["tabindex"] != null) {        &lt;br /&gt;  tabIndex = Int32.Parse(Request.Params["tabindex"]);&lt;br /&gt;}&lt;br /&gt;   &lt;br /&gt;// Get TabID from querystring&lt;br /&gt;&lt;br /&gt;if (Request.Params["tabid"] != null) {       &lt;br /&gt;  tabId = Int32.Parse(Request.Params["tabid"]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Context.Items.Add("PortalSettings",&lt;br /&gt;new PortalSettings(tabIndex, tabId));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The DesktopPortalBanner.ascx user control pulls the PortalSetting's object from Context to access the Portal's name and security settings. In fact, this one module is a great all-around example of Context in action. To illustrate the point, I've simplified the code a little, and marked all of the places either HTTP or application-specific Context is accessed in bold.&lt;br /&gt;&lt;br /&gt;[C# DesktopPortalBanner.ascx]&lt;br /&gt;&lt;br /&gt;&lt;%@ Import Namespace="ASPNetPortal" %&gt;&lt;br /&gt;&lt;%@ Import Namespace="System.Data.SqlClient" %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Request.ApplicationPath %&gt;"&gt;Portal Home&lt;br /&gt;|&lt;br /&gt;Request.ApplicationPath %&gt;/Docs/Docs.asp"&gt;&lt;br /&gt;Portal Documentation&lt;br /&gt;&lt;%= LogoffLink %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Request.ApplicationPath %&gt;&lt;br /&gt;/DesktopDefault.aspx?tabindex=&lt;%# Container.ItemIndex %&gt;&amp;tabid=&lt;br /&gt;&lt;%# ((TabStripDetails) Container.DataItem).TabId %&gt;'&gt;&lt;br /&gt;&lt;%# ((TabStripDetails) Container.DataItem).TabName %&gt;&lt;br /&gt;&amp;amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;%# ((TabStripDetails) Container.DataItem).TabName %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can browse and run the complete source for the IBuySpy portal online in both Visual Basic and C# at http://www.ibuyspy.com, or download it and run it yourself.&lt;br /&gt;&lt;br /&gt;Summary&lt;br /&gt;&lt;br /&gt;Context is another one of those "good things get even better in ASP.NET" features. It extends the already great context support of ASP to add both hooks into the new runtime features of ASP.NET. Plus it adds Context.Items as a new state mechanism for very short-lived values. But the ultimate benefit to you as a developer is more compact, easier to maintain code, and that's a context we can all get behind.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-114095294382864840?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095294382864840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095294382864840'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/02/matter-of-context.html' title='A Matter of Context'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-114095213356299640</id><published>2006-02-26T18:07:00.000+07:00</published><updated>2006-02-26T18:21:06.073+07:00</updated><title type='text'>A low-level Look at the ASP.NET Architecture</title><content type='html'>&lt;p&gt;By Rick Strahl&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.west-wind.com/"&gt;www.west-wind.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="mailto:rstrahl@west-wind.com"&gt;rstrahl@west-wind.com&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Last Update:&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; August 29, 2005&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;Other Links:&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;a href="http://www.west-wind.com/presentations/howaspnetworks/howaspnetworks.zip"&gt;Download Examples for this article&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://west-wind.com/weblog/posts/2595.aspx"&gt;Leave a Comment or  Question&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;ASP.NET is a powerful platform for building Web applications, that  provides a tremendous amount of flexibility and power for building just  about any kind of Web application. Most people are familiar only with  the high level frameworks like WebForms and WebServices  which sit at the very top level of the ASP.NET hierarchy. In this  article I’ll describe the lower level aspects of ASP.NET and explain  how requests move from Web Server to the ASP.NET runtime and then  through the ASP.NET Http Pipeline to process requests. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;To  me understanding the innards of a platform always provides certain  satisfaction and level of comfort, as well as insight that helps to  write better applications. Knowing what tools are available and how  they fit together as part of the whole complex framework makes it  easier to find the best solution to a problem and more importantly  helps in troubleshooting and debugging of problems when they occur. The  goal of this article is to look at ASP.NET from the System level and  help understand how requests flow into the ASP.NET processing pipeline.  As such we’ll look at the core engine and how Web requests end up  there. Much of this information is not something that you need to know  in your daily work, but it’s good to understand how the ASP.NET  architecture routes request into your application code that usually  sits at a much higher level. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Most people using ASP.NET are familiar with WebForms and WebServices.  These high level implementations are abstractions that make it easy to  build Web based application logic and ASP.NET is the driving engine  that provides the underlying interface to the Web Server and routing  mechanics to provide the base for these high level front end services  typically used for your applications. WebForms and WebServices are merely two very sophisticated implementations of HTTP Handlers built on top of the core ASP.NET framework.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;However,  ASP.NET provides much more flexibility from a lower level. The HTTP  Runtime and the request pipeline provide all the same power that went  into building the WebForms and WebService  implementations – these implementations were actually built with .NET  managed code. And all of that same functionality is available to you,  should you decide you need to build a custom platform that sits at a  level a little lower than WebForms.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;WebForms  are definitely the easiest way to build most Web interfaces, but if  you’re building custom content handlers, or have special needs for  processing the incoming or outgoing content, or you need to build a  custom application server interface to another application, using these  lower level handlers or modules can provide better performance and more  control over the actual request process. With all the power that the  high level implementations of WebForms and WebServices provide they also add quite a bit of overhead to requests that you can bypass by working at a lower level.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;What is ASP.NET&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Let’s start with a simple definition: What is ASP.NET? I like to define ASP.NET as follows:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;ASP.NET is a sophisticated engine using Managed Code for front to back processing of Web Requests.&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;It's much more than just WebForms and Web Services…&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;ASP.NET  is a request processing engine. It takes an incoming request and passes  it through its internal pipeline to an end point where you as a  developer can attach code to process that request. This engine is  actually completely separated from HTTP or the Web Server. In fact, the  HTTP Runtime is a component that you can host in your own applications  outside of IIS or any server side application altogether. For example,  you can host the ASP.NET runtime in a Windows form (check out &lt;a href="http://www.west-wind.com/presentations/aspnetruntime/aspnetruntime.asp"&gt;http://www.west-wind.com/presentations/aspnetruntime/aspnetruntime.asp&lt;/a&gt; for more detailed information on runtime hosting in Windows Forms apps).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The  runtime provides a complex yet very elegant mechanism for routing  requests through this pipeline. There are a number of interrelated  objects, most of which are extensible either via subclassing or through  event interfaces at almost every level of the process, so the framework  is highly extensible. Through this mechanism it’s possible to hook into  very low level interfaces such as the caching, authentication and  authorization. You can even filter content by pre or post processing  requests or simply route incoming requests that match a specific  signature directly to your code or another URL. There are a lot of  different ways to accomplish the same thing, but all of the approaches  are straightforward to implement, yet provide flexibility in finding  the best match for performance and ease of development.&lt;/p&gt;&lt;br /&gt;&lt;div color="navy -moz-use-text-color"&gt;&lt;br /&gt;&lt;p&gt; The entire ASP.NET engine was completely built in managed code and all  extensibility is provided via managed code extensions.&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The  entire ASP.NET engine was completely built in managed code and all of  the extensibility functionality is provided via managed code  extensions. This is a testament to the power of the .NET framework in  its ability to build sophisticated and very performance oriented  architectures. Above all though, the most impressive part of ASP.NET is  the thoughtful design that makes the architecture easy to work with,  yet provides hooks into just about any part of the request processing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;With  ASP.NET you can perform tasks that previously were the domain of ISAPI  extensions and filters on IIS – with some limitations, but it’s a lot  closer than say ASP was. ISAPI is a low level Win32 style API that had  a very meager interface and was very difficult to work for  sophisticated applications. Since ISAPI is very low level it also is  very fast, but fairly unmanageable for application level development.  So, ISAPI has been mainly relegated for some time to providing bridge  interfaces to other application or platforms. But ISAPI isn’t dead by  any means. In fact, ASP.NET on Microsoft platforms interfaces with IIS  through an ISAPI extension that hosts .NET and through it the ASP.NET  runtime. ISAPI provides the core interface from the Web Server and  ASP.NET uses the unmanaged ISAPI code to retrieve input and send output  back to the client. The content that ISAPI provides is available via  common objects like HttpRequest and HttpResponse that expose the unmanaged data as managed objects with a nice and accessible interface.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;From Browser to ASP.NET&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Let’s  start at the beginning of the lifetime of a typical ASP.NET Web  Request. A request starts on the browser where the user types in a URL,  clicks on a hyperlink or submits an HTML form (a POST request). Or a  client application might make call against an ASP.NET based Web  Service, which is also serviced by ASP.NET. On the server side the Web  Server – Internet Information Server 5 or 6 – picks up the request. At  the lowest level ASP.NET interfaces with IIS through an ISAPI  extension. With ASP.NET this request usually is routed to a page with an &lt;em&gt;.aspx&lt;/em&gt; extension, but how the process works depends entirely on the  implementation of the HTTP Handler that is set up to handle the  specified extension. In IIS .&lt;em&gt;aspx&lt;/em&gt; is mapped through an ‘Application Extension’ (aka. as a script map) that is mapped to the ASP.NET ISAPI dll - &lt;em&gt;aspnet_isapi.dll&lt;/em&gt;. Every request that fires ASP.NET must go through an extension that is registered and points at &lt;em&gt;aspnet_isapi.dll&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Depending  on the extension ASP.NET routes the request to an appropriate handler  that is responsible for picking up requests. For example, the &lt;em&gt;.asmx &lt;/em&gt;extension  for Web Services routes requests not to a page on disk but a specially  attributed class that identifies it as a Web Service implementation.  Many other handlers are installed with ASP.NET and you can also define  your own. All of these &lt;em&gt;HttpHandlers&lt;/em&gt; are mapped to point at the ASP.NET  ISAPI extension in IIS, and configured in web.config to get routed to a specific HTTP Handler implementation. Each handler,  is a .NET class that handles a specific extension which can range from  simple Hello World behavior with a couple of lines of code, to very  complex handlers like the ASP.NET Page or Web Service implementations.  For now, just understand that an extension is the basic mapping  mechanism that ASP.NET uses to receive a request from ISAPI and then  route it to a specific handler that processes the request.&lt;/p&gt;&lt;br /&gt;&lt;div color="navy -moz-use-text-color"&gt;&lt;br /&gt;&lt;p&gt;ISAPI is the first and highest performance entry point into IIS for custom Web Request handling.&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;The ISAPI Connection&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;ISAPI  is a low level unmanged Win32 API. The interfaces defined by the ISAPI  spec are very simplistic and optimized for performance. They are very  low level – dealing with raw pointers and function pointer tables for  callbacks - but they provide he lowest and most performance oriented  interface that developers and tool vendors can use to hook into IIS.  Because ISAPI is very low level it’s &lt;em&gt;not&lt;/em&gt; well suited for building application level code,  and ISAPI tends to be used primarily as a bridge interface to provide  Application Server type functionality to higher level tools. For  example, ASP and ASP.NET both are layered on top of ISAPI as is Cold  Fusion, most Perl, PHP and JSP implementations running on IIS as well  as many third party solutions such as my own Web Connection framework  for Visual FoxPro. ISAPI is an excellent tool to provide the high  performance plumbing interface to higher level applications, which can  then abstract the information that ISAPI provides. In ASP and ASP.NET,  the engines abstract the information provided by the ISAPI interface in  the form of objects like Request and Response that read their content  out of the ISAPI request information. Think of ISAPI as the plumbing.  For ASP.NET the ISAPI dll is very lean and  acts merely as a routing mechanism to pipe the inbound request into the  ASP.NET runtime. All the heavy lifting and processing, and even the  request thread management happens inside of the ASP.NET engine and your code.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As  a protocol ISAPI supports both ISAPI extensions and ISAPI Filters.  Extensions are a request handling interface and provide the logic to  handle input and output with the Web Server – it’s essentially a  transaction interface. ASP and ASP.NET are implemented as ISAPI  extensions. ISAPI filters are hook interfaces that allow the ability to  look at EVERY request that comes into IIS and to modify the content or  change the behavior of functionalities like Authentication.  Incidentally ASP.NET maps ISAPI-like functionality via two concepts:  Http Handlers (extensions) and Http Modules (filters). We’ll look at  these later in more detail. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;ISAPI  is the initial code point that marks the beginning of an ASP.NET  request. ASP.NET maps various extensions to its ISAPI extension which  lives in the .NET Framework directory:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&amp;lt;.NET FrameworkDir&amp;gt;\aspnet_isapi.dll&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You  can interactively see these mapping in the IIS Service manager as shown  in Figure 1. Look at the root of the Web Site and the Home Directory  tab, then Configuration | Mappings.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%201.png" alt="1" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;: IIS maps various extensions like .ASPX to the ASP.NET ISAPI extension. Through this mechanism requests are routed into ASP.NET's processing pipeline at the Web Server level.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You shouldn’t set these extensions manually as .NET requires a number of them. Instead use the &lt;strong&gt;aspnet_regiis.exe &lt;/strong&gt;utility to make sure that all the various scriptmaps get registered properly:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;cd&lt;/strong&gt;&lt;strong&gt; &amp;lt;.NetFrameworkDirectory&amp;gt;&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;aspnet_regiis&lt;/strong&gt;&lt;strong&gt; - i&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This will register the particular version of the ASP.NET runtime for the entire Web site by registering the scriptmaps and setting up the client side scripting libraries used by the various controls for uplevel browsers. Note that it registers the particular version of the CLR that is installed in the above directory. Options on aspnet_regiis let you configure virtual directories individually. Each version of the .NET framework has its own version of aspnet_regiis  and you need to run the appropriate one to register a site or virtual  directory for a specific version of the .NET framework. Starting with  ASP.NET 2.0, an IIS ASP.NET configuration page lets you pick the .NET  version interactively in the IIS management console. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;IIS 5 and 6 work differently&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;When  a request comes in, IIS checks for the script map and routes the  request to the aspnet_isapi.dll. The operation of the DLL and how it  gets to the ASP.NET runtime varies significantly between IIS 5 and 6.  Figure 2 shows a rough overview of the flow.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In  IIS 5 hosts aspnet_isapi.dll directly in the inetinfo.exe process or  one of its isolated worker processes if you have isolation set to  medium or high for the Web or virtual directory. When the first ASP.NET  request comes in the DLL will spawn a new process in another EXE – &lt;em&gt;aspnet_wp.exe&lt;/em&gt; – and route processing to this spawned process. This process in turn  loads and hosts the .NET runtime. Every request that comes into the  ISAPI DLL then routes to this worker process via Named Pipe calls.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%202.png" alt="2" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 2&lt;/strong&gt; – Request flow from IIS to the ASP.NET Runtime and through the request processing pipeline from a high level. IIS 5 and IIS 6 interface with ASP.NET in different ways but the overall process once it reaches the ASP.NET Pipeline is the same.&lt;/p&gt;&lt;br /&gt;&lt;div color="navy -moz-use-text-color"&gt;&lt;br /&gt;&lt;p&gt;IIS6, unlike previous servers,  is fully optimized for ASP.NET &lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;IIS 6 – Viva the Application Pool&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;IIS  6 changes the processing model significantly in that IIS no longer  hosts any foreign executable code like ISAPI extensions directly.  Instead IIS 6 &lt;strong&gt;always&lt;/strong&gt; creates a separate worker process – an &lt;em&gt;Application Pool&lt;/em&gt; – and all processing occurs inside of this process, including execution of the ISAPI dll.  Application Pools are a big improvement for IIS 6, as they allow very  granular control over what executes in a given process. Application  Pools can be configured for every virtual directory or the entire Web  site, so you can isolate every Web application easily into its own  process that will be completely isolated from any other Web application  running on the same machine. If one process dies it will not affect any  others at least from the Web processing perspective. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;In  addition, Application Pools are highly configurable. You can configure  their execution security environment by setting an execution  impersonation level for the pool which allows you to customize the  rights given to a Web application in that same granular fashion. One  big improvement for ASP.NET is that the Application Pool replaces most  of the ProcessModel entry in machine.config.  This entry was difficult to manage in IIS 5, because the settings were  global and could not be overridden in an application specific  web.config file. When running IIS 6, the ProcessModel  setting is mostly ignored and settings are instead read from the  Application Pool. I say mostly – some settings, like the size of the ThreadPool  and IO threads still are configured through this key since they have no  equivalent in the Application Pool settings of the server. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Because  Application Pools are external executables these executables can also  be easily monitored and managed. IIS 6 provides a number of health  checking, restarting and timeout options that can detect and in many  cases correct problems with an application. Finally IIS 6’s Application  Pools don’t rely on COM+ as IIS 5 isolation processes did which has  improved performance and stability especially for applications that  need to use COM objects internally. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Although IIS 6 application pools are separate EXEs,  they are highly optimized for HTTP operations by directly communicating  with a kernel mode HTTP.SYS driver. Incoming requests are directly  routed to the appropriate application pool. InetInfo  acts merely as an Administration and configuration service – most  interaction actually occurs directly between HTTP.SYS and the  Application Pools, all of which translates into a more stable and  higher performance environment over IIS 5. This is especially true for  static content and ASP.NET applications.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;An  IIS 6 application pool also has intrinsic knowledge of ASP.NET and  ASP.NET can communicate with new low level APIs that allow direct  access to the HTTP Cache APIs which can offload caching from the  ASP.NET level directly into the Web Server’s cache. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;In  IIS 6, ISAPI extensions run in the Application Pool worker process. The  .NET Runtime also runs in this same process, so communication between  the ISAPI extension and the .NET runtime happens  in-process which is inherently more efficient than the named pipe  interface that IIS 5 must use. Although the IIS hosting models are very  different the actual interfaces into managed code are very similar –  only the process in getting the request routed varies a bit. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The ISAPIRuntime.ProcessRequest() method is the first entry point into ASP.NET&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Getting into the .NET runtime&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The  actual entry points into the .NET Runtime occur through a number of  undocumented classes and interfaces. Little is known about these  interfaces outside of Microsoft, and Microsoft folks are not eager to  talk about the details, as they deem this an implementation detail that  has little effect on developers building applications with ASP.NET. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The  worker processes ASPNET_WP.EXE (IIS5) and W3WP.EXE (IIS6) host the .NET  runtime and the ISAPI DLL calls into small set of unmanged interfaces  via low level COM that eventually forward calls to an instance subclass  of the ISAPIRuntime class. The first entry point to the runtime is the  undocumented ISAPIRuntime class which exposes the IISAPIRuntime interface via COM to a caller. These COM interfaces low level IUnknown  based interfaces that are meant for internal calls from the ISAPI  extension into ASP.NET. Figure 3 shows the interface and call  signatures for the IISAPIRuntime  interface as shown in Lutz Roeder’s excellent &lt;a href="http://www.aisto.com/roeder/dotnet"&gt;.NET Reflector&lt;/a&gt; tool (&lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;http://www.aisto.com/roeder/dotnet/&lt;/a&gt;). Reflector an assembly viewer and disassembler that makes it very easy to look at medadata and disassembled code (in IL, C#, VB) as shown in Figure 3. It’s a great way to explore the bootstrapping process. &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%203.png" alt="3" border="0" height="429" width="677" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 3&lt;/strong&gt; – If you want to dig into the low level interfaces open up Reflector, and point at the System.Web.Hosting namespace. The entry point to ASP.NET occurs through a managed COM Interface called from the ISAPI dll, that  receives an unmanaged pointer to the ISAPI ECB. The ECB contains has  access to the full ISAPI interface to allow retrieving request data and  sending back to IIS.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The IISAPIRuntime  interface acts as the interface point between the unmanaged code coming  from the ISAPI extension (directly in IIS 6 and indirectly via the  Named Pipe handler in IIS 5). If you take a look at this class you’ll  find a ProcessRequest method with a signature like this:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[&lt;strong&gt;return&lt;/strong&gt;: MarshalAs(UnmanagedType.I4)]&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;int&lt;/strong&gt; ProcessRequest([In] IntPtr ecb, &lt;/p&gt;&lt;br /&gt;&lt;p&gt; [In, MarshalAs(UnmanagedType.I4)] &lt;strong&gt;int&lt;/strong&gt; useProcessModel);&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The ecb parameter is the ISAPI Extension Control Block (ECB) which is passed as an unmanaged resource to ProcessRequest.  The method then takes the ECB and uses it as the base input and output  interface used with the Request and Response objects. An ISAPI ECB  contains all low level request information including server variables,  an input stream for form variables as well as an output stream that is  used to write data back to the client. The single ecb reference basically provides access to all of the functionality an ISAPI request has access to and ProcessRequest is the entry and exit point where this resource initially makes contact with managed code.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The  ISAPI extension runs requests asynchronously. In this mode the ISAPI  extension immediately returns on the calling worker process or IIS  thread, but keeps the ECB for the current request alive. The ECB then  includes a mechanism for letting ISAPI know when the request is  complete (via ecb.ServerSupportFunction)  which then releases the ECB. This asynchronous processing releases the  ISAPI worker thread immediately, and offloads processing to a separate  thread that is managed by ASP.NET. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;ASP.NET receives this ecb  reference and uses it internally to retrieve information about the  current request such as server variables, POST data as well as  returning output back to the server. The ecb  stays alive until the request finishes or times out in IIS and ASP.NET  continues to communicate with it until the request is done. Output is  written into the ISAPI output stream (ecb.WriteClient())  and when the request is done, the ISAPI extension is notified of  request completion to let it know that the ECB can be freed. This  implementation is very efficient as the .NET classes essentially act as  a fairly thin wrapper around the high performance, unmanaged ISAPI ECB.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Loading .NET – somewhat of a mystery&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Let’s  back up one step here: I skipped over how the .NET runtime gets loaded.  Here’s where things get a bit fuzzy. I haven’t found any documentation  on this process and since we’re talking about native code there’s no  easy way to disassemble the ISAPI DLL and figure it out. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;My  best guess is that the worker process bootstraps the .NET runtime from  within the ISAPI extension on the first hit against an ASP.NET mapped  extension. Once the runtime exists, the unmanaged code can request an  instance of an ISAPIRuntime object for a given virtual path if one  doesn’t exist yet. Each virtual directory gets its own AppDomain and within that AppDomain  the ISAPIRuntime exists from which the bootstrapping process for an  individual application starts. Instantiation appears to occur over COM  as the interface methods are exposed as COM callable methods.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To create the ISAPIRuntime instance the System.Web.Hosting.AppDomainFactory.Create()  method is called when the first request for a specific virtual  directory is requested. This starts the ‘Application’ bootstrapping  process. The call receives parameters for type and module name and  virtual path information for the application which is used by ASP.NET  to create an AppDomain and launch the ASP.NET application for the given virtual directory. This HttpRuntime derived object is created in a new AppDomain. Each virtual directory or ASP.NET application is hosted in a separate AppDomain  and they get loaded only as requests hit the particular ASP.NET  Application. The ISAPI extension manages these instances of the HttpRuntime objects, and routes inbound requests to the right one based on the virtual path of the request. &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%204.png" alt="4" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 4&lt;/strong&gt; – The transfer of the ISAPI request into the HTTP Pipeline of ASP.NET  uses a number of undocumented classes and interfaces and requires  several factory method calls. Each Web Application/Virtual runs in its  own AppDomain with the caller holding a reference to an IISAPIRuntime interface that triggers the ASP.NET request processing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Back in the runtime&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;At  this point we have an instance of ISAPIRuntime active and callable from  the ISAPI extension. Once the runtime is up and running the ISAPI code  calls into the ISAPIRuntime.ProcessRequest() method which is the real entry point into the ASP.NET Pipeline. The flow from there is shown in Figure 4.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Remember ISAPI is multi-threaded so requests will come in on multiple threads through the reference that was returned by ApplicationDomainFactory.Create(). Listing 1 shows the disassembled code from the IsapiRuntime.ProcessRequest method that receives an ISAPI ecb object and server type as parameters. The method is thread safe, so multiple ISAPI threads can safely call this single returned object instance simultaneously.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Listing 1: The Process request method receives an ISAPI Ecb and passes it on to the Worker request&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;int&lt;/strong&gt; ProcessRequest(IntPtr ecb, &lt;strong&gt;int&lt;/strong&gt; iWRType)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; HttpWorkerRequest request1 = ISAPIWorkerRequest.CreateWorkerRequest(ecb, iWRType);&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;string&lt;/strong&gt; text1 = request1.GetAppPathTranslated();&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;string&lt;/strong&gt; text2 = HttpRuntime.AppDomainAppPathInternal;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (((text2 == &lt;strong&gt;null&lt;/strong&gt;) || text1.Equals(".")) || &lt;/p&gt;&lt;br /&gt;&lt;p&gt; (&lt;strong&gt;string&lt;/strong&gt;.Compare(text1, text2, &lt;strong&gt;true&lt;/strong&gt;, CultureInfo.InvariantCulture) == 0))&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;HttpRuntime.ProcessRequest(request1);&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;return&lt;/strong&gt; 0;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; HttpRuntime.ShutdownAppDomain("Physical application path changed from " + &lt;/p&gt;&lt;br /&gt;&lt;p&gt; text2 + " to " + text1);&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;return&lt;/strong&gt; 1;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The  actual code here is not important, and keep in mind that this is  disassembled internal framework code that you’ll never deal with  directly and that might change in the future. It’s meant to demonstrate  what’s happening behind the scenes. ProcessRequest receives the unmanaged ECB reference and passes it on to the ISAPIWorkerRequest object which is in charge of creating the Request Context for the current request as shown in Listing 2. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The System.Web.Hosting.ISAPIWorkerRequest class is an abstract subclass of HttpWorkerRequest,  whose job it is to create an abstracted view of the input and output  that serves as the input for the Web application. Notice another  factory method here: CreateWorkerRequest, which as a second parameter receives the type of worker request object to create. There are three different versions: ISAPIWorkerRequestInProc, ISAPIWorkerRequestInProcForIIS6, ISAPIWorkerRequestOutOfProc.  This object is created on each incoming hit and serves as the basis for  the Request and Response objects which will receive their data and  streams from the data provided by the WorkerRequest.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The abstract HttpWorkerRequest class is meant to provide a highlevel  abstraction around the low level interfaces so that regardless of where  the data comes from, whether it’s a CGI Web Server, the Web Browser  Control or some custom mechanism you use to feed the data to the HTTP  Runtime. The key is that ASP.NET can retrieve the information  consistently.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the case of IIS the abstraction is centered around an ISAPI ECB block. In our request processing, ISAPIWorkerRequest  hangs on to the ISAPI ECB and retrieves data from it as needed. Listing  2 shows how the query string value is retrieved for example.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Listing 2: An ISAPIWorkerRequest method that uses the unmanged &lt;/p&gt;&lt;br /&gt;&lt;p&gt;// *** Implemented in ISAPIWorkerRequest&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;override&lt;/strong&gt; &lt;strong&gt;byte&lt;/strong&gt;[] GetQueryStringRawBytes()&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;byte&lt;/strong&gt;[] buffer1 = &lt;strong&gt;new&lt;/strong&gt; &lt;strong&gt;byte&lt;/strong&gt;[&lt;strong&gt;this&lt;/strong&gt;._queryStringLength];&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (&lt;strong&gt;this&lt;/strong&gt;._queryStringLength &amp;gt; 0)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;int&lt;/strong&gt; num1 = &lt;strong&gt;this&lt;/strong&gt;.GetQueryStringRawBytesCore(buffer1, &lt;strong&gt;this&lt;/strong&gt;._queryStringLength);&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (num1 != 1)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;throw&lt;/strong&gt; &lt;strong&gt;new&lt;/strong&gt; HttpException( "Cannot_get_query_string_bytes");&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;return&lt;/strong&gt; buffer1;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;// *** Implemented in a specific implementation class ISAPIWorkerRequestInProcIIS6&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;internal&lt;/strong&gt; &lt;strong&gt;override&lt;/strong&gt; &lt;strong&gt;int&lt;/strong&gt; GetQueryStringCore(&lt;strong&gt;int&lt;/strong&gt; encode, StringBuilder buffer, &lt;strong&gt;int&lt;/strong&gt; size)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (&lt;strong&gt;this&lt;/strong&gt;._ecb == IntPtr.Zero)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;return&lt;/strong&gt; 0;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;return&lt;/strong&gt; UnsafeNativeMethods.EcbGetQueryString(&lt;strong&gt;this&lt;/strong&gt;._ecb, encode, buffer, size);&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;ISAPIWorkerRequest implements a high level wrapper method, that calls into lower level &lt;em&gt;Core&lt;/em&gt; methods, which are responsible for performing the actual access to the  unmanaged APIs – or the ‘service level implementation’. The &lt;em&gt;Core&lt;/em&gt; methods are implemented in the specific ISAPIWorkerRequest  instance subclasses and thus provide the specific implementation for  the environment that it’s hosted in. This makes for an easily pluggable  environment where additional implementation classes can be provided  later as newer Web Server interfaces or other platforms are targeted by  ASP.NET. There’s also a helper class System.Web.UnsafeNativeMethods. Many of these methods operate on the ISAPI ECB structure performing unmanaged calls into the ISAPI extension. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;HttpRuntime, HttpContext, and HttpApplication – Oh my&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;When a request hits, it is routed to the ISAPIRuntime.ProcessRequest() method. This method in turn calls HttpRuntime.ProcessRequest that does several important things (look at System.Web.HttpRuntime.ProcessRequestInternal with Reflector):&lt;/p&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;Create      a new HttpContext instance for the request&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Retrieves      an HttpApplication Instance&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Calls HttpApplication.Init() to set up Pipeline Events&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Init()      fires HttpApplication.ResumeProcessing() which      starts the ASP.NET pipeline processing&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;First a new &lt;em&gt;HttpContext&lt;/em&gt; object is created and it is passed the ISAPIWorkerRequest  that wrappers the ISAPI ECB. The Context is available throughout the  lifetime of the request and ALWAYS accessible via the static &lt;em&gt;HttpContext.Current&lt;/em&gt; property. As the name implies, the HttpContext  object  represents the context of the currently active request as it contains  references to all of the vital objects you typically access during the  request lifetime: Request, Response, Application, Server, Cache. At any  time during request processing HttpContext.Current gives you access to all of these object. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The HttpContext  object also contains a very useful Items collection that you can use to  store data that is request specific. The context object gets created at  the begging of the request cycle and released when the request  finishes, so data stored there in the Items collection is specific only  to the current request. A good example use is a request logging  mechanism where you want to track start and end times of a request by  hooking the Application_BeginRequest and Application_EndRequest methods in Global.asax as shown in Listing 3. HttpContext is your friend – you’ll use it liberally if you need data in different parts of the request or page processing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Listing 3 – Using the HttpContext.Items collection lets you save data between pipeline events&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;protected&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; Application_BeginRequest(Object sender, EventArgs e)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; //*** Request Logging&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (App.Configuration.LogWebRequests)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;Context.Items.Add("WebLog_StartTime",DateTime.Now);&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;protected&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; Application_EndRequest(Object sender, EventArgs e)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; // *** Request Logging&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;if&lt;/strong&gt; (App.Configuration.LogWebRequests) &lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;try&lt;/strong&gt; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; { &lt;/p&gt;&lt;br /&gt;&lt;p&gt; TimeSpan Span = DateTime.Now.Subtract( &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;(DateTime) Context.Items["WebLog_StartTime"]&lt;/strong&gt; );&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;int&lt;/strong&gt; MiliSecs = Span.TotalMilliseconds;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; // do your logging&lt;/p&gt;&lt;br /&gt;&lt;p&gt; WebRequestLog.Log(App.Configuration.ConnectionString,&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt; true&lt;/strong&gt;,MilliSecs);&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once  the Context has been set up, ASP.NET needs to route your incoming  request to the appropriate application/virtual directory by way of an HttpApplication  object. Every ASP.NET application must be set up as a Virtual (or Web  Root) directory and each of these ‘applications’ are handled  independently. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The HttpApplication is like a master of ceremonies – it is where the processing action starts&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Master of your domain: HttpApplication&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Each request is routed to an HttpApplication object. The HttpApplicationFactory class creates a pool of HttpApplication  objects for your ASP.NET application depending on the load on the  application and hands out references for each incoming request. The  size of the pool is limited to the setting of the MaxWorkerThreads setting in machine.config’s ProcessModel Key, which by default is 20. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;The pool starts out with a smaller number though; usually one and it then grows as multiple simulataneous  requests need to be processed. The Pool is monitored so under load it  may grow to its max number of instances, which is later scaled back to  a smaller number as the load drops. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;HttpApplication is the outer container for your specific Web application and it maps to the class that is defined in Global.asax.  It’s the first entry point into the HTTP Runtime that you actually see  on a regular basis in your applications. If you look in Global.asax (or the code behind class) you’ll find that this class derives directly from HttpApplication:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;class&lt;/strong&gt; Global : System.Web.HttpApplication&lt;/p&gt;&lt;br /&gt;&lt;p&gt;HttpApplication’s  primary purpose is to act as the event controller of the Http Pipeline  and so its interface consists primarily of events. The event hooks are  extensive and include:&lt;/p&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;BeginRequest&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AuthenticateRequest&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AuthorizeRequest&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ResolveRequestCache&lt;/li&gt;&lt;br /&gt;&lt;li&gt;AquireRequestState&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PreRequestHandlerExecute&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;…Handler      Execution…&lt;/strong&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PostRequestHandlerExecute&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ReleaseRequestState&lt;/li&gt;&lt;br /&gt;&lt;li&gt;UpdateRequestCache&lt;/li&gt;&lt;br /&gt;&lt;li&gt;EndRequest&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Each of these events are also implemented in the Global.asax file via empty methods that start with an Application_ prefix. For example, Application_BeginRequest(), Application_AuthorizeRequest().  These handlers are provided for convenience since they are frequently  used in applications and make it so that you don’t have to explicitly  create the event handler delegates.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It’s important to understand that each ASP.NET virtual application runs in its own AppDomain and that there inside of the AppDomain multiple HttpApplication  instances running simultaneously, fed out of a pool that ASP.NET  manages. This is so that multiple requests can process at the same time  without interfering with each other. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;To see the relationship between the AppDomain, Threads and the HttpApplication check out the code in Listing 4.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Listing 4 – Showing the relation between AppDomain, Threads and HttpApplication instances&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;private&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; Page_Load(&lt;strong&gt;object&lt;/strong&gt; sender, System.EventArgs e)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; // Put user code to initialize the page here&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;this&lt;/strong&gt;.ApplicationId = ((HowAspNetWorks.Global) &lt;/p&gt;&lt;br /&gt;&lt;p&gt; HttpContext.Current.ApplicationInstance).ApplicationId ; &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;this&lt;/strong&gt;.ThreadId = AppDomain.GetCurrentThreadId();&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;this&lt;/strong&gt;.DomainId = AppDomain.CurrentDomain.FriendlyName;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;this&lt;/strong&gt;.ThreadInfo = "ThreadPool Thread: " + &lt;/p&gt;&lt;br /&gt;&lt;p&gt; System.Threading.Thread.CurrentThread.IsThreadPoolThread.ToString() +&lt;/p&gt;&lt;br /&gt;&lt;p&gt; "&lt;br /&gt;&lt;br /&gt;Thread Apartment: " + &lt;/p&gt;&lt;br /&gt;&lt;p&gt; System.Threading.Thread.CurrentThread.ApartmentState.ToString();&lt;/p&gt;&lt;br /&gt;&lt;p&gt; // *** Simulate a slow request so we can see multiple&lt;/p&gt;&lt;br /&gt;&lt;p&gt; //     requests side by side.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; System.Threading.Thread.Sleep(3000);&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This  is part of a demo is provided with your samples and the running form is  shown in Figure 5. To check this out run two instances of a browser and  hit this sample page and watch the various Ids. &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%205.png" alt="5" border="0" height="517" width="684" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 5&lt;/strong&gt; – You can easily check out how AppDomains,  Application Pool instances, and Request Threads interact with each  other by running a couple of browser instances simultaneously. When  multiple requests fire you’ll see the thread and Application ids  change, but the AppDomain staying the same.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You’ll notice that the AppDomain ID stays steady while thread and HttpApplication Ids change on most requests, although they likely will repeat. HttpApplications  are running out of a collection and are reused for subsequent requests  so the ids repeat at times. Note though that Application instance are  not tied to a specific thread – rather they are assigned to the active  executing thread of the current request.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Threads are served from the .NET ThreadPool  and by default are Multithreaded Apartment (MTA) style threads. You can  override this apartment state in ASP.NET pages with the  ASPCOMPAT="true" attribute in the @Page directive. ASPCOMPAT is meant  to provide COM components a safe environment to run in and ASPCOMPAT  uses special Single Threaded Apartment (STA) threads to service those  requests. STA threads are set aside and pooled separately as they  require special handling.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The fact that these HttpApplication objects are all running in the same AppDomain  is very important. This is how ASP.NET can guarantee that changes to  web.config or individual ASP.NET pages get recognized throughout the AppDomain. Making a change to a value in web.config causes the AppDomain to be shut down and restarted. This makes sure that all instances of HttpApplication see the changes made because when the AppDomain reloads the changes from ASP.NET are re-read at startup. Any static references are also reloaded when the AppDomain so if the application reads values from App Configuration settings these values also get refreshed. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;To see this in the sample, hit the ApplicationPoolsAndThreads.aspx page and note the AppDomain Id. Then go in and make a change in web.config (add a space and save). Then reload the page. You’ll l find that a new AppDomain has been created.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In  essence the Web Application/Virtual completely ‘restarts’ when this  happens. Any requests that are already in the pipeline processing will  continue running through the existing pipeline, while any new requests  coming in are routed to the new AppDomain. In order to deal with ‘hung requests’ ASP.NET forcefully shuts down the AppDomain after the request timeout period is up even if requests are still pending. So it’s actually possible that two AppDomains exist for the same HttpApplication at a given point in time as the old one’s shutting down and the new one is ramping up. Both AppDomains continue to serve their clients until the old one has run out its pending requests and shuts down leaving just the new AppDomain running.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Flowing through the ASP.NET Pipeline&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The HttpApplication  is responsible for the request flow by firing events that signal your  application that things are happening. This occurs as part of the HttpApplication.Init() method (look at System.Web.HttpApplication.InitInternal and HttpApplication.ResumeSteps()  with Reflector) which sets up and starts a series of events in  succession including the call to execute any handlers. The event  handlers map to the events that are automatically set up in global.asax, and they also map any attached &lt;em&gt;HTTPModules&lt;/em&gt;, which are essentially an externalized event sink for the events that HttpApplication publishes.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Both &lt;em&gt;HttpModules&lt;/em&gt; and &lt;em&gt;HttpHandlers&lt;/em&gt;are loaded dynamically via entries in Web.config and attached to the event chain. HttpModules are actual event handlers that hook specific HttpApplication events, while HttpHandlers are an end point that gets called to handle ‘application level request processing’. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Both Modules and Handlers are loaded and attached to the call chain as part of the HttpApplication.Init() method call. Figure 6 shows the various events and when they happen and which parts of the pipeline they affect.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%206.png" alt="56" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure 6&lt;/strong&gt; – Events flowing through the ASP.NET HTTP Pipeline. The HttpApplication  object’s events drive requests through the pipeline. Http Modules can  intercept these events and override or enhance existing functionality. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;HttpContext, HttpModules and HttpHandlers&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The HttpApplication  itself knows nothing about the data being sent to the application – it  is a merely messaging object that communicates via events. It fires  events and passes information via the HttpContext object to the called methods. The actual state data for the current request is maintained in the HttpContext  object mentioned earlier. It provides all the request specific data and  follows each request from beginning to end through the pipeline. Figure  7 shows the flow through ASP.NET pipeline. Notice the Context object  which is your compadre from beginning to  end of the request and can be used to store information in one event  method and retrieve it in a later event method.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once the pipeline is started, HttpApplication  starts firing events one by one as shown in Figure 6. Each of the event  handlers is fired and if events are hooked up those handlers execute  and perform their tasks. The main purpose of this process is to  eventually call the HttpHandler hooked up  to a specific request. Handlers are the core processing mechanism for  ASP.NET requests and usually the place where any application level code  is executed. Remember that the ASP.NET Page and Web Service frameworks  are implemented as HTTPHandlers and that’s where all the  core processing of the request is handled. Modules tend to be of a more  core nature used to prepare or post process the Context that is  delivered to the handler. Typical default handlers in ASP.NET are  Authentication, Caching for pre-processing and various encoding  mechanisms on post processing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There’s plenty of information available on HttpHandlers and HttpModules so to keep this article a reasonable length I’m going to provide only a brief overview of handlers. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;HttpModules&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As requests move through the pipeline a number of events fire on the HttpApplication object. We’ve already seen that these events are published as event methods in Global.asax. This approach is application specific though which is not always what you want. If you want to build generic HttpApplication event hooks that can be plugged into any Web applications you can use HttpModules which are reusable and don’t require application specific code except for an entry in web.config.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Modules  are in essence filters – similar in functionality to ISAPI filters at  the ASP.NET request level. Modules allow hooking events for EVERY  request that pass through the ASP.NET HttpApplication  object. These modules are stored as classes in external assemblies that  are configured in web.config and loaded when the Application starts. By  implementing specific interfaces and methods the module then gets  hooked up to the HttpApplication event chain. Multiple HttpModules  can hook the same event and event ordering is determined by the order  they are declared in Web.config. Here’s what a handler definition looks  like in Web.config:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;lt;configuration&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &amp;lt;system.web&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &amp;lt;httpModules&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &amp;lt;add name= "BasicAuthModule" &lt;/p&gt;&lt;br /&gt;&lt;p&gt; type="HttpHandlers.BasicAuth,WebStore" /&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;br /&gt;httpModules&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;br /&gt;system.web&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;br /&gt;configuration&amp;gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Note that you need to specify a full typename and an assembly name without the DLL extension.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Modules  allow you look at each incoming Web request and perform an action based  on the events that fire. Modules are great to modify request or  response content, to provide custom authentication or otherwise provide  pre or post processing to every request that occurs against ASP.NET in  a particular application. Many of ASP.NET’s features like the Authentication and Session engines are implemented as HTTP Modules.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;While HttpModules feel similar to ISAPI Filters in that they look at &lt;em&gt;every&lt;/em&gt; request in that comes through an ASP.NET Application, they are limited  to looking at requests mapped to a single specific ASP.NET application  or virtual directory and then only against requests that are mapped to  ASP.NET. Thus you can look at all ASPX pages or any of the other custom  extensions that are mapped to this application. You cannot however look  at standard .HTM or image files unless you explicitly map the extension  to the ASP.NET ISAPI dll by adding an  extension as shown in Figure 1. A common use for a module might be to  filter content to JPG images in a special folder and display a ‘SAMPLE’  overlay ontop of every image by drawing ontop of the returned bitmap with GDI+. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Implementing an HTTP Module is very easy: You must implement the IHttpModule interface which contains only two methods Init() and Dispose(). The event parameters passed include a reference to the HTTPApplication object, which in turn gives you access to the HttpContext object. In these methods you hook up to HttpApplication events. For example, if you want to hook the AuthenticateRequest event with a module you would do what’s shown in Listing 5. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Listing 5: The basics of an HTTP Module are very simple to implement&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;class&lt;/strong&gt; BasicAuthCustomModule : IHttpModule&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; Init(HttpApplication application)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; // *** Hook up any HttpApplication events&lt;/p&gt;&lt;br /&gt;&lt;p&gt; application.AuthenticateRequest += &lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;new&lt;/strong&gt; EventHandler(&lt;strong&gt;this&lt;/strong&gt;.OnAuthenticateRequest);&lt;/p&gt;&lt;br /&gt;&lt;p&gt; }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; Dispose() { }&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; OnAuthenticateRequest(&lt;strong&gt;object&lt;/strong&gt; source, EventArgs eventArgs)&lt;/p&gt;&lt;br /&gt;&lt;p&gt; {&lt;/p&gt;&lt;br /&gt;&lt;p&gt; HttpApplication app = (HttpApplication) source;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; HttpContext Context = HttpContext.Current;&lt;/p&gt;&lt;br /&gt;&lt;p&gt; … &lt;strong&gt;do&lt;/strong&gt; what you have to &lt;strong&gt;do&lt;/strong&gt;…                                         } &lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Remember that your Module has access the HttpContext  object and from there to all the other intrinsic ASP.NET pipeline  objects like Response and Request, so you can retrieve input etc. But  keep in mind that certain things may not be available until later in  the chain. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can hook multiple events in the Init()  method so your module can manage multiple functionally different  operations in one module. However, it’s probably cleaner to separate  differing logic out into separate classes to make sure the module is  modular.  In many cases functionality that you implement may  require that you hook multiple events – for example a logging filter  might log the start time of a request in Begin Request and then write  the request completion into the log in EndRequest.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Watch out for one important gotcha with HttpModules and HttpApplication events: Response.End() or HttpApplication.CompleteRequest() will shortcut the HttpApplication and Module event chain. See the sidebar “Watch out for Response.End() “ for more info.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;HttpHandlers&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Modules are fairly low level and fire against &lt;em&gt;every&lt;/em&gt; inbound request to the ASP.NET application. Http Handlers are more  focused and operate on a specific request mapping, usually a page  extension that is mapped to the handler.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Http Handler implementations are very basic in their requirements, but through access of the HttpContext object a lot of power is available. Http Handlers are implemented through a very simple IHttpHandler interface (or its asynchronous cousin, IHttpAsyncHandler) which consists of merely a single method – ProcessRequest() – and a single property IsReusable. The key is ProcessRequest() which gets passed an instance of the HttpContext object. This single method is responsible for handling a Web request start to finish.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Single, simple method? Must be too simple, right? Well, simple interface, but not simplistic in what’s possible! Remember that WebForms and WebServices  are both implemented as Http Handlers, so there’s a lot of power  wrapped up in this seemingly simplistic interface. The key is the fact  that by the time an Http Handler is reached all of ASP.NET’s internal objects are set up and configured to start processing of requests. The key is the HttpContext object, which provides all of the relevant request functionality to retireve input and send output back to the Web Server. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;For an HTTP Handler all action occurs through this single call to ProcessRequest(). This can be as simple as:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;public&lt;/strong&gt; &lt;strong&gt;void&lt;/strong&gt; ProcessRequest(HttpContext context)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;{&lt;/p&gt;&lt;br /&gt;&lt;p&gt; context.Response.Write("Hello World");&lt;/p&gt;&lt;br /&gt;&lt;p&gt;}&lt;/p&gt;&lt;br /&gt;&lt;p&gt;to a full implementation like the WebForms  Page engine that can render complex forms from HTML templates. The  point is that it’s up to you to decide of what you want to do with this  simple, but powerful interface!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Because  the Context object is available to you, you get access to the Request,  Response, Session and Cache objects, so you have all the key features  of an ASP.NET request at your disposal to figure out what users  submitted and return content you generate back to the client. Remember  the Context object – it’s your friend throughout the lifetime of an  ASP.NET request!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The key operation of the handler should be eventually write output into the Respone object or more specifically the Response object’s OutputStream. This output is what actually gets sent back to the client. Behind the scenes the ISAPIWorkerRequest manages sending the OutputStream back into the ISAPI ecb.WriteClient method that actually performs the IIS output generation.&lt;/p&gt;&lt;br /&gt;&lt;p&gt; &lt;img src="http://www.west-wind.com/presentations/howaspnetworks/Figure%207.png" alt="6" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Figure &lt;/strong&gt;&lt;strong&gt;7&lt;/strong&gt; – The ASP.NET Request pipeline flows  requests through a set of event interfaces that provide much  flexibility. The Application acts as the hosting container that loads  up the Web application and fires events as requests come in and pass  through the pipeline. Each request follows a common path through the  Http Filters and Modules configured. Filters can examine each request  going through the pipeline and Handlers allow implementation of  application logic or application level interfaces like Web Forms and  Web Services. To provide Input and Output for the application the  Context object provides request specific information throughout the  entire process.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;WebForms implements an Http Handler with a much more high level interface on top of this very basic framework, but eventually a WebForm’s Render() method simply ends up using an HtmlTextWriter object to write its final final output to the context.Response.OutputStream. So while very fancy, ultimately even a high level tool like Web forms is just a high level abstraction ontop of the Request and Response object.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You might wonder at this point whether you need to deal with Http Handlers at all. After all WebForms  provides an easily accessible Http Handler implementation, so why  bother with something a lot more low level and give up that  flexibility? &lt;/p&gt;&lt;br /&gt;&lt;p&gt;WebForms  are great for generating complex HTML pages and business level logic  that requires graphical layout tools and template backed pages. But the  WebForms engine performs a lot of tasks  that are overhead intensive. If all you want to do is read a file from  the system and return it back through code it’s much more efficient to  bypass the Web Forms Page framework and directly feed the file back. If  you do things like Image Serving from a Database there’s no need to go  into the Page framework – you don’t need templates and there surely is  no Web UI that requires you to capture events off an Image served.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There’s  no reason to set up a page object and session and hook up Page level  events – all of that stuff requires execution of code that has nothing  to do with your task at hand.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So handlers are more efficient. Handlers also can do things that aren’t possible with WebForms such as the ability to process requests without the need to have a physical file on disk, which is known as a virtual Url. To do this make sure you turn off ‘Check that file exists’ checkbox in the Application Extension dialog shown in Figure 1.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This is common for content providers, such as dynamic image processing, XML servers, URL Redirectors providing vanity Urls, download managers and the like, none of which would benefit from the WebForm engine. &lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Have I stooped low enough for you?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Phew  – we’ve come full circle here for the processing cycle of requests.  That’s a lot of low level information and I haven’t even gone into  great detail about how HTTP Modules and HTTP Handlers work. It took  some time to dig up this information and I hope this gives you some of  the same satisfaction it gave me in understanding how ASP.NET works  under the covers.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Before I’m done let’s do the quick review of the event sequences I’ve discussed in this article from IIS to handler:&lt;/p&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;IIS      gets the request&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Looks      up a script map extension and maps to aspnet_isapi.dll&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Code      hits the worker process (aspnet_wp.exe in IIS5 or w3wp.exe in IIS6)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;.NET      runtime is loaded&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IsapiRuntime.ProcessRequest() called by non-managed      code&lt;/li&gt;&lt;br /&gt;&lt;li&gt;IsapiWorkerRequest created once per request&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HttpRuntime.ProcessRequest() called with Worker      Request&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HttpContext Object created by passing Worker Request      as input&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HttpApplication.GetApplicationInstance() called with      Context to retrieve instance from pool&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HttpApplication.Init() called to start pipeline event sequence      and hook up modules and handlers&lt;/li&gt;&lt;br /&gt;&lt;li&gt;HttpApplicaton.ProcessRequest called to start      processing&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pipeline      events fire&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Handlers      are called and ProcessRequest method are fired&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Control      returns to pipeline and post request events fire&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;It’s  a lot easier to remember how all of the pieces fit together with this  simple list handy. I look at it from time to time to remember. So now,  get back to work and do something non-abstract… &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Although  what I discuss here is based on ASP.NET 1.1, it looks that the  underlying processes described here haven’t changed in ASP.NET 2.0.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-114095213356299640?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095213356299640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114095213356299640'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/02/low-level-look-at-aspnet-architecture.html' title='A low-level Look at the ASP.NET Architecture'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-114076478062575539</id><published>2006-02-24T14:04:00.000+07:00</published><updated>2006-02-24T14:07:36.066+07:00</updated><title type='text'>Working with Complex Data Types in an XML Web Service</title><content type='html'>XML Web Services enable the exchange of complex data types, serialized as XML. Complex data types, such as ADO.NET DataSets and custom classes can be serialized as XML and either sent to the XML Web Service as an input argument, or returned from the XML Web Service as the result. In this article we will build the beginning of an XML Web Service, which we will finish in next week's article, when we will also build a consumer Web application. The XML Web Service will have WebMethods for returning a DataSet and custom classes serialized as XML. For the DataSet, the .NET Framework will handle the formatting of the XML document that represents the DataSet; for the custom classes we will use classes from the System.Xml.Serialization namespace to define the XML format. The information page for the XML Web Service&lt;br /&gt;&lt;br /&gt;Working with DataSets&lt;br /&gt;&lt;br /&gt;A DataSet can be used with an XML Web Service, and the .NET Framework will automatically handle serializing it as XML. Listing 4.1 shows a serialized DataSet (DataSetName="Northwind") that has one DataTable (TableName="Categories"). The DataTable has two columns, CategoryID (int) and CategoryName (string). The DataTable lists all of the categories in the Northwind Categories table.&lt;br /&gt;&lt;br /&gt;Listing 4.1&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1&lt;br /&gt;Beverages&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2&lt;br /&gt;Condiments&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3&lt;br /&gt;Confections&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4&lt;br /&gt;Dairy Products&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5&lt;br /&gt;Grains/Cereals&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;6&lt;br /&gt;Meat/Poultry&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7&lt;br /&gt;Produce&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;8&lt;br /&gt;Seafood&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;In Listing 4.1 we see how the .NET Framework serializes a DataSet when it is used with an XML Web Service. We can see that the DataSet uses the XML namespace (xmlns) http://www.dotnetjunkies.com. This is used to help uniquely identify this DataSet - the XML namespace is defined in the XML Web Service. When the DataSet is serialized, the XML namespace of the XML Web Service is assigned to the DataSet.&lt;br /&gt;&lt;br /&gt;In the XML Schema in Listing 4.1 the DataTable is defined and each column is defined, with its data type. Each record in the DataTable is serialized to a element, with child elements for each of the columns.&lt;br /&gt;&lt;br /&gt;To generate the XML document shown in Listing 4.1, we create an XML Web Service that returns the defined DataSet. This is shown in Listing 4.2.&lt;br /&gt;&lt;br /&gt;Listing 4.2&lt;br /&gt;[ProductServices.asmx]&lt;br /&gt;&lt;%@ WebService Class="XMLWebServices.C04.ProductServices" %&gt;&lt;br /&gt;&lt;br /&gt;[ProductServices.asmx.cs]&lt;br /&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Web.Services;&lt;br /&gt;&lt;br /&gt;namespace XMLWebServices.C04&lt;br /&gt;{&lt;br /&gt;[WebService( Namespace="http://www.dotnetjunkies.com" )]&lt;br /&gt;public class ProductServices : WebService&lt;br /&gt;{&lt;br /&gt;[WebMethod(Description="Returns a DataSet with one DataTable (Categories) of all Categories and CategoryIDs in the Northwind Categories table.")]&lt;br /&gt;public DataSet GetCategories()&lt;br /&gt;{&lt;br /&gt;XMLWebServices.Data.NorthwindDB _nwdDB = new XMLWebServices.Data.NorthwindDB();&lt;br /&gt;return _nwdDB.getCategories();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In Listing 4.2 we create the beginning of the ProductServices XML Web Service. In the [WebService()] attribute we define the namespace for the XML Web Service. This namespace is used as the xmlns attribute of the DataSet when it is serialized as XML.&lt;br /&gt;&lt;br /&gt;So far we only have one WebMethod, the GetCategories() method. This method returns the DataSet shown in Listing 4.1. Invoking a method on the NorthwindDB data access class does this. The NorthwindDB class is shown in Listing 4.3.&lt;br /&gt;&lt;br /&gt;Listing 4.3&lt;br /&gt;[NorthwindDB.cs]&lt;br /&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Configuration;&lt;br /&gt;&lt;br /&gt;namespace XMLWebServices.Data&lt;br /&gt;{&lt;br /&gt;///&lt;br /&gt;/// Data Access Layer for Northwind Database&lt;br /&gt;///&lt;br /&gt;public class NorthwindDB&lt;br /&gt;{&lt;br /&gt;public NorthwindDB(){}&lt;br /&gt;&lt;br /&gt;// Create a class-level private connection string object&lt;br /&gt;private String _conString = ConfigurationSettings.AppSettings["NWDConString"];&lt;br /&gt;&lt;br /&gt;public DataSet getCategories()&lt;br /&gt;{&lt;br /&gt;// Build the SQL statement&lt;br /&gt;StringBuilder _sql = new StringBuilder();&lt;br /&gt;_sql.Append ( "SELECT CategoryID, CategoryName " );&lt;br /&gt;_sql.Append ( "FROM Categories " );&lt;br /&gt;_sql.Append ( "ORDER BY CategoryName" );&lt;br /&gt;// Create the DataSet to return&lt;br /&gt;DataSet _ds = new DataSet ( "Northwind" );&lt;br /&gt;// Create a Data Adapter to fill the DataSet&lt;br /&gt;SqlDataAdapter _sda = new SqlDataAdapter ( _sql.ToString(), _conString );&lt;br /&gt;// Fill the DataSet and Return it&lt;br /&gt;_sda.Fill ( _ds, "Categories" );&lt;br /&gt;return _ds;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In the NorthwindDB data access class we expose a method, getCategories(), which connects to our SQL Server database and returns a DataSet with one DataTable populated with the CategoryID and CategoryName of all the records in the Categories table in the Northwind database.&lt;br /&gt;&lt;br /&gt;The DataSet is passed back to the calling component, the ProductServices class, in the GetCategories() WebMethod, which in turn passes it back to the XML Web Service consumer, serialized as XML. We didn't have to do anything to serialize the DataSet as XML - the .NET Framework does that for us.&lt;br /&gt;&lt;br /&gt;Unfortunately, there is no way for us to override how the DataSet is serialized. To create custom XML output we can use the System.Xml.Serialization namespace, and serialize custom classes.&lt;br /&gt;&lt;br /&gt;Serializing Custom Classes&lt;br /&gt;&lt;br /&gt;We can create a custom class to represent our data, and serialize it as XML to be returned to the XML Web Service consumer. We do this using attribute classes from the System.Xml.Serialization namespace. Some of the XML attribute classes are:&lt;br /&gt;&lt;br /&gt;    * XmlElementAttribute - Indicates that a public field or property represents an XML element - when the XmlSerializer serializes or deserializes the containing object.&lt;br /&gt;    * XmlAttributeAttribute - Specifies that the XmlSerializer should serialize the class member as an XML attribute.&lt;br /&gt;    * XmlTextAttribute - Indicates to the XmlSerializer that the member should be treated as XML text when the containing class is serialized or deserialized.&lt;br /&gt;    * XmlArrayAttribute - Specifies that the XmlSerializer should serialize a particular class member as an array of XML elements.&lt;br /&gt;&lt;br /&gt;      Descriptions of all of the XML attribute classes can be found in the .NET Framework SDK documentation at&lt;br /&gt;      ms-help://MS.NETFrameworkSDK/cpref/html/frlrfSystemXmlSerialization.htm&lt;br /&gt;&lt;br /&gt;The XML attribute classes are used to control how the XmlSerializer serializes and deserializes an object. We can apply these classes to a public field or property, and that informs the XmlSerializer what to do with the object's member.&lt;br /&gt;&lt;br /&gt;Using the XML Attribute Classes&lt;br /&gt;&lt;br /&gt;We can create a custom class to represent our data - for example a Product class to represent a single product - and use the XML attribute classes to define how a class instance should be serialized as XML.&lt;br /&gt;&lt;br /&gt;Lets create a Product class. We will use this in an XML Web Service that will return an instance of the Product class. We will define the XML output to look like the XML document shown in Listing 4.4.&lt;br /&gt;&lt;br /&gt;Listing 4.4&lt;br /&gt;&lt;br /&gt;&lt;Product xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd=http://www.w3.org/2001/XMLSchema&lt;br /&gt;xmlns="http://www.dotnetjunkies.com"&gt;&lt;br /&gt;&lt;productname id="1"&gt;ChaiProductName&gt;&lt;br /&gt;&lt;productstockinformation cost="18" quantityperunit="10 boxes x 20 bags"&gt;&lt;br /&gt;&lt;instock&gt;39InStock&gt;&lt;br /&gt;&lt;onorder&gt;0OnOrder&gt;&lt;br /&gt;&lt;reorderlevel&gt;10ReorderLevel&gt;&lt;br /&gt;ProductStockInformation&gt;&lt;br /&gt;Product&gt;&lt;br /&gt;&lt;br /&gt;In Listing 4.4 is the XML representation of a product from the Northwind database. The parent element has two child elements, and .&lt;br /&gt;&lt;br /&gt;In the element there is an ID attribute that holds the ProductID value from the Products table - the ProductName value is the text value of the element.&lt;br /&gt;&lt;br /&gt;The element has two attributes, Cost and QuantityPerUnit, which are UnitCost and QuantityPerUnit from the Products table, respectively. The element has three child elements, (UnitsInStock), (UnitsOnOrder), and (ReorderLevel).&lt;br /&gt;&lt;br /&gt;Listing 4.5 shows the code for the Product, ProductInfo, and StockInfo classes.&lt;br /&gt;&lt;br /&gt;Listing 4.5&lt;br /&gt;[Product.cs]&lt;br /&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;using System.Xml.Serialization;&lt;br /&gt;&lt;br /&gt;namespace XMLWebServices.C04&lt;br /&gt;{&lt;br /&gt;///&lt;br /&gt;/// Represents a single product from the Northwind Database&lt;br /&gt;///&lt;br /&gt;public class Product&lt;br /&gt;{&lt;br /&gt;[XmlElement(ElementName="ProductName")]&lt;br /&gt;public ProductInfo ProductInformation = new ProductInfo();&lt;br /&gt;[XmlElement(ElementName="ProductStockInformation")]&lt;br /&gt;public StockInfo ProductStockInformation = new StockInfo();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ProductInfo&lt;br /&gt;{&lt;br /&gt;[XmlAttribute(DataType="int", AttributeName="ID")]&lt;br /&gt;public Int32 ProductID;&lt;br /&gt;[XmlText()]&lt;br /&gt;public String ProductName;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class StockInfo&lt;br /&gt;{&lt;br /&gt;[XmlElement(DataType="short", ElementName="InStock")]&lt;br /&gt;public Int16 UnitsInStock;&lt;br /&gt;[XmlAttribute(DataType="decimal", AttributeName="Cost")]&lt;br /&gt;public Decimal UnitPrice;&lt;br /&gt;[XmlAttribute(DataType="string", AttributeName="QuantityPerUnit")]&lt;br /&gt;public String QuantityPerUnit;&lt;br /&gt;[XmlElement(DataType="short", ElementName="OnOrder")]&lt;br /&gt;public Int16 UnitsOnOrder;&lt;br /&gt;[XmlElement(DataType="short", ElementName="ReorderLevel")]&lt;br /&gt;public Int16 ReorderLevel;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In Listing 4.5 we create the Product class. The Product class has two public fields, ProductInformation - which uses the ProductInfo data type - and ProductStockInformation - which uses the StockInfo data type.&lt;br /&gt;&lt;br /&gt;Each of the Product public fields have the [XmlElement()] modifier applied to them (the Attribute portion of the XmlWhateverAttribute name is optional). This indicates to the XmlSerializer that these fields should be serialized as XML elements. Since each field uses a custom data type, we can go on to define how the public fields and properties in those classes are serialized. With each [XmlElement()] modifier we define what the name of the element should be when it is serialized. The ProductInformation field will be serialized as ; the ProductStockInformation field will be serialized using the same name as the field. In the case of the ProductStockInformation field, we do not have to define the Name property of the [XmlElement()] modifier, but I did so to be very explicit.&lt;br /&gt;&lt;br /&gt;In the ProductInfo class we define two public fields, ProductID (Int32) and ProductName (String). We apply the [XmlAttribute()] class to the ProductID field, indicting this should be serialized as an attribute of the element, using the name "ID" and it should be serialized as an int XML data type. The ProductName field uses the [XmlText()] modifier. This indicates that the value of this field should be serialized as the text of the element.&lt;br /&gt;&lt;br /&gt;Based on the settings of the Product.ProductInformation field, and the ProductInfo class, we have defined the following XML elements:&lt;br /&gt;&lt;product&gt;&lt;br /&gt;&lt;productname id="1"&gt;ChaiProductName&gt;&lt;br /&gt;Product&gt;&lt;br /&gt;&lt;br /&gt;We use the [XmlElement()] and [XmlAttribute()] modifiers in the same manner to create the XML output for the StockInfo class. The resulting XML is:&lt;br /&gt;&lt;product&gt;&lt;br /&gt;&lt;productstockinformation cost="18" quantityperunit="10 boxes x 20 bags"&gt;&lt;br /&gt;&lt;instock&gt;39InStock&gt;&lt;br /&gt;&lt;onorder&gt;0OnOrder&gt;&lt;br /&gt;&lt;reorderlevel&gt;10ReorderLevel&gt;&lt;br /&gt;ProductStockInformation&gt;&lt;br /&gt;Product&gt;&lt;br /&gt;&lt;br /&gt;We can create a WebMethod to return a Product class instance - this is shown in Listing 4.6 (this should be added to the ProductServices XML Web Service).&lt;br /&gt;&lt;br /&gt;Listing 4.6&lt;br /&gt;[WebMethod(Description="Returns a custom class, Product, which represents a single Product from the Northwind Products table.")]&lt;br /&gt;public Product GetProductByID ( Int32 ProductID )&lt;br /&gt;{&lt;br /&gt;XMLWebServices.Data.NorthwindDB _nwdDB = new XMLWebServices.Data.NorthwindDB();&lt;br /&gt;return _nwdDB.getProductByID ( ProductID );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The GetProductByID() WebMethod takes in a ProductID and returns an instance of the Product class that represents the specified product. The Product class instance is created in the NortwindDB data access component, as shown in Listing 4.7 (this method should be added to the NorthwindDB class).&lt;br /&gt;&lt;br /&gt;Listing 4.7&lt;br /&gt;public XMLWebServices.C04.Product getProductByID ( Int32 _productID )&lt;br /&gt;{&lt;br /&gt;// Build the SQL statement&lt;br /&gt;StringBuilder _sql = new StringBuilder();&lt;br /&gt;_sql.Append ( "SELECT ProductName, UnitsInStock, UnitPrice, " );&lt;br /&gt;_sql.Append ( "QuantityPerUnit, UnitsOnOrder, ReorderLevel " );&lt;br /&gt;_sql.Append ( "FROM Products " );&lt;br /&gt;_sql.Append ( "WHERE ProductID=" );&lt;br /&gt;_sql.Append ( _productID.ToString() );&lt;br /&gt;// Create the SqlConnection and SqlCommand objects&lt;br /&gt;SqlConnection _con = new SqlConnection ( _conString );&lt;br /&gt;SqlCommand _cmd = new SqlCommand ( _sql.ToString(), _con );&lt;br /&gt;// Create a Product object&lt;br /&gt;XMLWebServices.C04.Product _product = new XMLWebServices.C04.Product();&lt;br /&gt;// Open the connection and return the IDataReader object&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;_con.Open();&lt;br /&gt;// Use a data reader to return the result set&lt;br /&gt;SqlDataReader _rdr = _cmd.ExecuteReader();&lt;br /&gt;// Open the reader to the first record&lt;br /&gt;_rdr.Read();&lt;br /&gt;// Assign the product properties&lt;br /&gt;_product.ProductInformation.ProductID = _productID;&lt;br /&gt;_product.ProductInformation.ProductName = _rdr.GetString(0);&lt;br /&gt;_product.ProductStockInformation.UnitsInStock = (Int16)_rdr.GetValue(1);&lt;br /&gt;_product.ProductStockInformation.UnitPrice = (Decimal)_rdr.GetValue(2);&lt;br /&gt;_product.ProductStockInformation.QuantityPerUnit = _rdr.GetString(3);&lt;br /&gt;_product.ProductStockInformation.UnitsOnOrder = (Int16)_rdr.GetValue(4);&lt;br /&gt;_product.ProductStockInformation.ReorderLevel = (Int16)_rdr.GetValue(5);&lt;br /&gt;// Close the data reader and the connection&lt;br /&gt;_rdr.Close();&lt;br /&gt;_con.Close();&lt;br /&gt;//Return the product object&lt;br /&gt;return _product;&lt;br /&gt;}&lt;br /&gt;catch&lt;br /&gt;{&lt;br /&gt;// If there is an error, return null&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;In Listing 4.7 we create the getProductByID() method of the data access class. This method takes in a ProductID, which it uses to retrieve a record from the Northwind database, Products table. We create an instance of the Product class and set its public field values using the column values in the returned record. The result is a Product class instance that we return to the calling object - the ProductServices XML Web Service's GetProductByID() method - which in turn returns it to the consumer, serialized as XML.&lt;br /&gt;&lt;br /&gt;Summary&lt;br /&gt;&lt;br /&gt;In next weeks article I will show you how to use the XmlArrayAtribute class by creating a Category class and exposing a property that is an array of Product objects. We will also build a consumer application for the ProductServices XML Web Service and look at how we can consume the XML serialized object that we have created.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-114076478062575539?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114076478062575539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/114076478062575539'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/02/working-with-complex-data-types-in-xml.html' title='Working with Complex Data Types in an XML Web Service'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-113757474496000848</id><published>2006-01-18T15:49:00.000+07:00</published><updated>2006-01-18T15:59:04.986+07:00</updated><title type='text'>Rich Internet Applications - RIA everywhere</title><content type='html'>Rich Internet Applications and AJAX - Selecting the best product&lt;br /&gt;&lt;br /&gt;There are hundreds of criteria for evaluating RIA and AJAX products. So many that it’s easy to lose focus and misjudge priorities. This essay proposes a decision tree that leads through an evaluation process. It asks for the most distinctive requirements and product features in a top-down sequence, discussing the essential differences between technology options.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure1.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure1.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Figure 1: Decision Tree&lt;br /&gt;&lt;br /&gt;The focus is entirely on questions you should answer when evaluating RIA products. There is no assessment of specific products, because the individual features of products tend to obscure fundamental issues. Notice that RIA and AJAX are sometimes used as synonyms. This is not entirely correct: AJAX is short for “Asynchronous JavaScript And XML”, which essentially limits the term to the set of RIA solutions based on JavaScript. I will adhere to this latter definition, although I fully agree with authors who argue that the concepts proposed by AJAX are by no means limited to JavaScript [1].&lt;br /&gt;Simple User Interface?&lt;br /&gt;&lt;br /&gt;The first and most important question to ask is whether the user interface (UI) of your application is simple enough for HTML. If the answer is yes, then HTML is your best option because it enables ubiquitous end user access via browser.&lt;br /&gt;&lt;br /&gt;Simple enough for HTML means that the UI has modest interactivity requirements. However, if any of the following features improves your UI, you should consider RIA technology:&lt;br /&gt;&lt;br /&gt;  * Partial screen updates&lt;br /&gt;  * Asynchronous communication&lt;br /&gt;  * Server push&lt;br /&gt;  * Widgets supporting direct manipulation&lt;br /&gt;  * Multiple coordinated windows&lt;br /&gt;  * Modal dialogs&lt;br /&gt;  * Menus&lt;br /&gt;  * Keyboard navigation&lt;br /&gt;&lt;br /&gt;RIA technology provides rich client capabilities in a web infrastructure. The goal is to combine the advantages of desktop applications with those of web applications. There are three fundamentally different technology options to achieve this: JavaScript, Java, and Flash. Their respective core advantages lead to the next level of the decision tree.&lt;br /&gt;Ubiquity, Industrial Strength, or Fancy Animations?&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure2.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure2.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 2: RIA Technology Subtree&lt;br /&gt;&lt;br /&gt;The question that differentiates RIA technology is whether unconditional end user access via browser (ubiquity), industrial strength, or fancy animations are most important. If ubiquity is the answer, a JavaScript/AJAX based solution will be the favorite, because JavaScript is available “out-of-the-box” in every popular browser. If industrial strength characteristics like maintainability, reliability, availability, scalability, performance and security are the top requirements, a Java solution is likely to be the front-runner. Java is unquestionably superior to the scripting alternatives in these areas. Last but not least, if fancy animations are your primary requirement, the attractiveness of Flash may outweigh the arguments speaking for the alternatives. The following sections look closer at these three technology options and present questions you should ask when assessing corresponding products.&lt;br /&gt;Ubiquity: JavaScript/AJAX&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure3.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure3.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 3: JavaScript/AJAX Branch&lt;br /&gt;&lt;br /&gt;AJAX is neither a product nor a new technology but a new branding for RIA technology that is based on JavaScript, XML, and other technologies. Since most JavaScript based products have adopted the AJAX terminology, it’s reasonable to put them in a single category. JavaScript/AJAX products are appropriate in situations where the user expects an application to work unconditionally in browsers. When buying a DVD or booking a flight, for instance, nobody will want to install a plug-in.&lt;br /&gt;&lt;br /&gt;Plain HTML remains the best solution for simple UI requirements. Yet, DVD stores or travel booking applications with simple UIs are often vexing or even useless. Anyone who has tried to book an itinerary with multiple flights, hotels, and rental cars will agree that current websites are painful to use. JavaScript/AJAX could help here. Unfortunately, there’s only a handful of “killer” applications that show what’s possible: Google Suggest and Google Maps are among them. Cited as the key examples by Jesse James Garrett in his defining article on AJAX [2], they are arguably the most popular JavaScript based RIAs on the web.&lt;br /&gt;&lt;br /&gt;Selecting RIA products based on JavaScript/AJAX is challenging. The issue is that JavaScript is hard to deal with. It’s no coincidence that it took the skills and funds of Google to come up with “killer” applications. Internet giants like Amazon or Ebay are not leveraging the potential of JavaScript/AJAX, although the technology has been around for years and would potentially improve their websites substantially. Just imagine how their sites would profit by “search as you type”, scrolling lists, partial screen updates, or browseable category trees.&lt;br /&gt;&lt;br /&gt;The following questions will help in deciding whether an RIA product based on JavaScript/AJAX is suitable for your needs.&lt;br /&gt;Browsers and OS supported?&lt;br /&gt;&lt;br /&gt;JavaScript implementations are not standardized across browsers and operating systems. This means that programs must be aware of the browser, the operating system, and their respective versions. Programs must execute different code depending on specific combinations thereof, which is a developer’s nightmare. The most essential characteristic of a JavaScript/AJAX product is, therefore, how well it handles these combinations and shields the developer from the complexity of managing them in application code. The combinations supported by the Google applications may serve as a benchmark for evaluation. Google Maps and Google Suggest support:&lt;br /&gt;&lt;br /&gt;  * IE 6.0+ on Windows&lt;br /&gt;  * Firefox 0.8+ on Windows, Mac, Linux&lt;br /&gt;  * Safari 1.2.4+ on Mac (Google Suggest 1.2.2 or newer)&lt;br /&gt;  * Netscape 7.1+ on Windows, Mac, Linux&lt;br /&gt;  * Mozilla 1.4+ on Windows, Mac, Linux&lt;br /&gt;  * Opera 8+ on Windows, Mac, Linux (Google Suggest 7.5.4+)&lt;br /&gt;&lt;br /&gt;RIA Functions?&lt;br /&gt;&lt;br /&gt;JavaScript was designed for scripting rather than full-fledged rich client development. For this reason, a JavaScript/AJAX product may not necessarily support all RIA functions mentioned. Partial screen updates, asynchronous communication, modal dialogs and menus will probably be available. But other RIA goodies may be severely limited in functionality or missing altogether. Typically, the set of rich UI widgets that supports direct manipulation will be poor compared to those we find in toolkits for desktop applications. Important questions to ask include:&lt;br /&gt;&lt;br /&gt;  * how does the widget set compare to standard sets like those of Java Swing?&lt;br /&gt;  * is the look&amp;feel adaptable?&lt;br /&gt;  * is there an API for the development of new widgets?&lt;br /&gt;  * is it possible to integrate third-party widgets?&lt;br /&gt;  * what is the market for third-party widgets?&lt;br /&gt;  * is there support for Accessibility?&lt;br /&gt;&lt;br /&gt;How Strong?&lt;br /&gt;&lt;br /&gt;Industrial strength characteristics like maintainability, reliability, availability, scalability, performance and security are a challenge for JavaScript/AJAX products because they have to rely on a scripting language and must work in a heterogeneous set of execution environments. It is unrealistic to expect the kind of industrial strength that can be found in a homogeneous Java product. Yet, there is a wide range of options regarding the amount of code that needs to be executed in the shaky JavaScript environment. The complete range of architectures shown in Figure 4 is feasible.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure4.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure4.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 4: RIA Architecture Options&lt;br /&gt;&lt;br /&gt;JavaScript code can be limited to an application-independent presentation engine that comes with the product, as illustrated by the rightmost option in Figure 4. This pure thin-client approach has several advantages: applications can be written entirely in Java, with a single programming environment. Moreover, there is a homogeneous server-side programming model, and no need to distribute the application code between client and server, nor between different programming languages. This simplifies both development and testing substantially. Finally, the application code will execute primarily in the robust server-side environment.&lt;br /&gt;&lt;br /&gt;Note that pure thin-client architectures are rare in JavaScript based UIs. The typical approach is to split the functionality between client and server individually for each application as shown by the three left-hand options in Figure 4: either within the presentation logic, within the business logic, or between business logic and data. The leftmost option represents a pure fat-client architecture where the entire application code is written in JavaScript. Fat-client or hybrid approaches may be appropriate for certain scenarios. But for industrial strength characteristics, a pure thin-client architecture is preferable. Crucial questions are, therefore:&lt;br /&gt;&lt;br /&gt;  * what architecture is supported or enforced: thin, fat, or hybrid?&lt;br /&gt;  * is the programming model server-side or distributed?&lt;br /&gt;  * is application code written purely in Java or in a heterogeneous mixture of languages including JavaScript, Java, and proprietary XML languages?&lt;br /&gt;  * how much of the product’s code is JavaScript?&lt;br /&gt;  * how can security be handled?&lt;br /&gt;&lt;br /&gt;Industrial Strength: Java&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure5.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure5.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 5: Java Branch&lt;br /&gt;&lt;br /&gt;RIA products that are based entirely on Java have the best foundation for industrial strength. Java’s solid standards base, homogeneous technology, broad choice in high-quality tooling, and bright perspective regarding future enhancements ensure that a well-designed product can be maintained cost effectively and for any length of time in the foreseeable future. Reliability, availability, scalability and security are given on a wide array of platforms.&lt;br /&gt;&lt;br /&gt;Designed for full-fledged productivity applications, Java’s UI technology leaves nothing to be desired regarding rich-client functions. There are comprehensive, customizable widget toolkits for desktops as well as mobile devices, and numerous third-party libraries.&lt;br /&gt;&lt;br /&gt;In contrast to many JavaScript products, Java RIA offerings typically follow a thin-client approach as shown by the rightmost picture in Figure 4: the client is an application independent presentation engine that can be executed either as an applet in a browser, or as a Java program on the desktop, or even on a PDA.&lt;br /&gt;&lt;br /&gt;The questions that distinguish Java RIAs ask for the JREs (Java Runtime Environment) supported, the UI libraries employed, and leverage of Java standards.&lt;br /&gt;JRE Versions Supported?&lt;br /&gt;&lt;br /&gt;Compared to the execution environments for JavaScript, JRE implementations are more standardized. Programs written with a specific JDK (Java Developer’s Kit) will usually run in the corresponding JRE, irrespective of whether this JRE is running within a browser, on a desktop operating system, or on a device like a PDA. The version issue is primarily raised on the level of the JRE and the target environments that support that JRE.&lt;br /&gt;&lt;br /&gt;Most RIA products support multiple JRE versions. Some are based on JDK 1.1 with its AWT widget library and will run on JRE 1.1 or later. Others are using Swing and will run on JRE 1.2 or later. The respective pros and cons of earlier or later versions must be evaluated carefully, because the earliest version supported defines the “least common denominator”. A low “denominator” product based on the low-level AWT will often run on more JREs because later Java versions are fairly downward compatible. A high “denominator” product based on the higher-level Swing will be able to leverage the improvements of new Java versions. The most important questions are:&lt;br /&gt;&lt;br /&gt;  * what are the target devices/environments for the end users?&lt;br /&gt;  * which JREs are available and easily installable on the targets?&lt;br /&gt;  * on which JREs does the product run?&lt;br /&gt;  * which JRE is the “least common denominator” of the product?&lt;br /&gt;  * does the product leverage improvements of later JDK/JRE versions?&lt;br /&gt;&lt;br /&gt;UI Libraries Employed?&lt;br /&gt;&lt;br /&gt;Java’s client-side UI technology has evolved substantially. The initial low-level library AWT has been complemented with the high-level Swing library, and the latter has substantially improved over the years. The Eclipse project has come up with its own low-level and high-level UI libraries SWT and JFace, respectively. RIA products offer the functionality of high-level libraries. Yet, some of them have chosen to implement the high-level functions themselves and use low-level libraries on the client. This has pros and cons. On the upside, a low-level approach can support multiple UI libraries on the client, under the condition that the functionality is limited to the “common denominator” of these libraries. On the downside, the low-level approach will lead to a layer of proprietary software that needs to be maintained. With a high-level library, the proprietary depth of a product can be reduced to a minimum. Even the API can be taken from the standard library, as described by Bernhard Wagner in his article on “Server-Side Swing” [3]. Such an RIA product will have a minimal proprietary footprint and will profit from enhancements of the standard Swing library as it evolves. Essential drill-down questions on the UI libraries are:&lt;br /&gt;&lt;br /&gt;  * is the product based on low-level libraries (AWT, SWT) or high-level libraries (Swing, JFace)?&lt;br /&gt;        o low: does it support multiple UI libraries on the client?&lt;br /&gt;        o high: is the API proprietary or a server-side proxy approach?&lt;br /&gt;  * what is the proprietary footprint of the UI technology?&lt;br /&gt;  * is there an extension API for the development of new widgets?&lt;br /&gt;  * is it possible to integrate third-party widgets?&lt;br /&gt;  * can the look&amp;feel be customized?&lt;br /&gt;  * is there support for Accessibility?&lt;br /&gt;&lt;br /&gt;Standards Leverage?&lt;br /&gt;&lt;br /&gt;Java standards are a key driver for reducing the proprietary share in a software stack. We have seen that the proprietary footprint of an RIA product’s client-side UI technology can vary considerably. Similar assessments can be made for the server-side part of RIA products, and the communication between client and server. J2EE defines standards that limit client/server communication, for instance, to request/reply protocols and specific transports such as HTTP(S) or RMI/IIOP. Moreover, EJBs disallow multi-threading that is not managed by the container, thereby ensuring that scaling measures like clustering can be handled by the J2EE infrastructure. RIA products that come with their own servers/proxies or allow bi-directional communication violate these standards and will need proprietary software that replaces the corresponding functions of the standard infrastructure. In general, a product that fully leverages the Java standards should have no function of its own if that same function can be delegated to the standard infrastructure. The following questions help in assessing standards leverage:&lt;br /&gt;&lt;br /&gt;  * is session handling delegated to the J2EE container or does the product come with a proprietary server/proxy?&lt;br /&gt;  * is clustering supported and delegated to the J2EE platform?&lt;br /&gt;  * is communication handled by J2EE compliant protocols?&lt;br /&gt;  * is deployment configurable and possible both in a servlet container and an EJB container?&lt;br /&gt;  * is deployment as a portlet possible, according to the JSR 168 standard?&lt;br /&gt;  * can the client part and server part be run in a single process for stand-alone deployment, leveraging the Java VM standards?&lt;br /&gt;&lt;br /&gt;Fancy Animations: Flash&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/figure6.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/figure6.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Figure 6: Flash Branch&lt;br /&gt;&lt;br /&gt;Flash has its main strength in animations. This is not surprising, because it was created to animate websites. The core Flash technology includes an execution environment (the Flash player), a binary file format for movies (SWF), and a scripting language (ActionScript). Comfortable end-user tools that generate SWF and support ActionScript programming are available for designing movies and websites. Flash-based RIA products for application development are comparatively new. As a consequence, both the core technology and RIA tools are evolving. This emphasizes the importance of the version issue, not only for the execution environment, but the programming model and programming tools as well.&lt;br /&gt;&lt;br /&gt;From an architectural perspective, the Flash-based approaches are close to those relying on JavaScript/AJAX. There is a scripting language that allows code to be sent to the client at run-time. Products can provide an array of architectural options, ranging from fat client to thin client as shown in Figure 4. The relevant questions are, therefore, close to those you should ask for JavaScript/AJAX.&lt;br /&gt;Flash Versions Supported?&lt;br /&gt;&lt;br /&gt;The core Flash technology is proprietary and tightly controlled by the vendor. Programs written for a specific version will run in the browsers and on the operating systems that are supported. The version issue is raised on the level of the Flash player, ActionScript, and the SWF format generated by an RIA product. The questions you need to ask are equivalent to those for the Java products:&lt;br /&gt;&lt;br /&gt;  * what are the target devices/environments for the end users?&lt;br /&gt;  * which Flash players are available and easily installable on the targets?&lt;br /&gt;  * on which players does the product run?&lt;br /&gt;  * which player is the “least common denominator” of the product?&lt;br /&gt;  * does the product leverage improvements of later ActionScript/SWF/player versions?&lt;br /&gt;&lt;br /&gt;RIA Functions?&lt;br /&gt;&lt;br /&gt;ActionScript, SWF and the Flash player were originally not designed for full-fledged rich client development. For this reason, you should ask the same questions as for JavaScript/AJAX products:&lt;br /&gt;&lt;br /&gt;  * how does the widget set compare to standard sets like those of Java Swing?&lt;br /&gt;  * is the look&amp;amp;feel adaptable?&lt;br /&gt;  * is there an API for the development of new widgets?&lt;br /&gt;  * is it possible to integrate third-party widgets?&lt;br /&gt;  * what is the market for third-party widgets?&lt;br /&gt;  * is there support for Accessibility?&lt;br /&gt;&lt;br /&gt;How strong?&lt;br /&gt;&lt;br /&gt;Relying on a scripting language like the JavaScript/AJAX approaches, Flash-based products have a similar range of options regarding the execution of code in the client-side environment. ActionScript can be limited to an application independent presentation engine that comes with the product, enforcing a pure thin-client architecture as shown in the rightmost picture of Figure 4. Alternatively, the developer can be given the option to write arbitrary application code with ActionScript, allowing for hybrid or fat client architectures. In general, a thin-client architecture will lead to superior industrial strength, as discussed above.&lt;br /&gt;&lt;br /&gt;Current Flash-based RIA products don’t support a pure thin-client architecture. They provide a heterogeneous programming model and require a hybrid set of tools for the various programming languages that need to be combined. This can be acceptable for industrial strength if their scope is limited to creating animations rather than transferring substantial parts of the application code to the client. Useful questions for an evaluation are:&lt;br /&gt;&lt;br /&gt;  * what architecture is supported or enforced: thin, fat, or hybrid?&lt;br /&gt;  * is the programming model server-side or distributed?&lt;br /&gt;  * is application code written purely in Java or in a heterogeneous mixture of languages including ActionScript, Java, and proprietary XML languages?&lt;br /&gt;  * how large, powerful and proprietary is the set of tools required?&lt;br /&gt;  * is usage of ActionScript and proprietary tools limited to the presentation layer of applications?&lt;br /&gt;  * how can security be handled?&lt;br /&gt;&lt;br /&gt;Conclusion&lt;br /&gt;&lt;br /&gt;RIA and AJAX are new terms for a technology that has been around for years. Given the hype for these terms, it is difficult to differentiate between products. They vary substantially in their technical foundation and their suitability for specific requirements. Careful product evaluation is essential. The decision tree presented in this essay helps asking the right questions and leads through the most important decisions.&lt;br /&gt;References&lt;br /&gt;&lt;br /&gt;[1] Coach K. Wey: AJAX: Asynchronous Java + XML?&lt;br /&gt;http://www.developer.com/design/article.php/3526681&lt;br /&gt;[2] Jesse James Garrett: AJAX: A New Approach to Web Applications,&lt;br /&gt;http://www.adaptivepath.com/publications/essays/archives/000385.php&lt;br /&gt;[3] Bernhard Wagner: Server-Side Swing for Rich Internet Applications,&lt;br /&gt;http://javadesktop.org/articles/canoo/index.html&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-113757474496000848?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113757474496000848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113757474496000848'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2006/01/rich-internet-applications-ria.html' title='Rich Internet Applications - RIA everywhere'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-113092059863193804</id><published>2005-11-03T06:25:00.000+07:00</published><updated>2005-11-02T15:46:12.100+07:00</updated><title type='text'>What is CMM (SEI Capability Maturity Model)?</title><content type='html'>According to the Carnegie Mellon University Software Engineering Institute, CMM is a common-sense application of software or business process management and quality improvement concepts to software development and maintenance. Its a community-developed guide for evolving towards a culture of engineering excellence, model for organizational improvement. The underlying structure for reliable and consistent software process assessments and software capability evaluations. &lt;p align="justify"&gt;The &lt;b&gt;Capability Maturity Model for Software&lt;/b&gt; (&lt;b&gt;CMM&lt;/b&gt;) is a framework that describes the key elements of an effective software process. There are CMMs for non software processes as well, such as &lt;b&gt; &lt;a title="Business Process Management Tutorial" href="http://bpmtutorial.com/bpm/BPM.aspx"&gt;Business Process Management (BPM)&lt;/a&gt;&lt;/b&gt;. The CMM describes an evolutionary improvement path from an ad hoc, immature process to a mature, disciplined process. The CMM covers practices for planning, engineering, and managing software development and maintenance. When followed, these key practices improve the ability of organizations to meet goals for cost, schedule, functionality, and product quality. The &lt;i&gt;CMM&lt;/i&gt; establishes a yardstick against which it is possible to judge, in a repeatable way, the maturity of an organization's software process and compare it to the state of the practice of the industry. The CMM can also be used by an organization to plan improvements to its software process. It also reflects the needs of individuals performing software process, improvement, software process assessments, or software capability evaluations; is documented; and is publicly available.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;The Five Maturity Levels described by the Capability Maturity Model can be characterized as per their primary process changes made at each level as follows:&lt;/p&gt;&lt;br /&gt;1) Initial The software process is characterized as ad hoc, and occasionally even chaotic. Few processes are defined, and success depends on individual effort and heroics.&lt;br /&gt;2) Repeatable Basic project management processes are established to track cost, schedule, and functionality. The necessary process discipline is in place to repeat earlier successes on projects with similar applications.&lt;br /&gt;3) Defined The software process for both management and engineering activities is documented, standardized, and integrated into a standard software process for the organization. All projects use an approved, tailored version of the organization's standard software process for developing and maintaining software.&lt;br /&gt;4) Managed Detailed measures of the software process and product quality are collected. Both the software process and products are quantitatively understood and controlled.&lt;br /&gt;5) Optimizing Continuous process improvement is enabled by quantitative feedback from the process and from piloting innovative ideas and technologies.&lt;br /&gt;&lt;br /&gt;The structure of the Capability Maturity model is as shown below:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/cmmstructure.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/320/cmmstructure.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;At the Optimizing Level or the CMM level5, the entire organization is focused on continuous Quantitative feedback from previous projects is used to improve the project management, usually using pilot projects, using the skills shown in level 4. The focus is on continuous process improvement.&lt;/p&gt; Software project teams in SEI CMM Level 5 organizations analyze defects to determine their causes. Software processes are evaluated to prevent known types of defects from recurring, and lessons learned are disseminated to other projects. The software process capability of Level 5 organizations can be characterized as continuously improving because Level 5 organizations are continuously striving to improve the range of their process capability, thereby improving the process performance of their projects. Improvement occurs both by incremental advancements in the existing process and by innovations using new technologies and methods.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Previously known as  Key Process Area (KPA)&lt;/h3&gt;      &lt;p&gt;A process area (PA) contains the goals that must be reached in order to improve a software process. A PA is said to be satisfied when procedures are in place to reach the corresponding goals. A software organization has achieved a specific maturity level once all the corresponding PAs are satisfied. The process areas (PA's) have the following features:&lt;/p&gt; 1) Identify a cluster of related activities that, when performed collectively, achieve a set of goals considered important for enhancing process capability. &lt;p&gt;2) Defined to reside at a single maturity level.&lt;/p&gt;  3) Identify the issues that must be addressed to achieve a maturity level.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/kpa.gif"&gt;&lt;img style="cursor: pointer;" src="http://photos1.blogger.com/blogger/5079/872/400/kpa.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/kpa.gif"&gt; The different maturity levels have different  process areas pre-defined as  shown in the figure above. The SEI CMMI Level 5 has 3 PA's defined: &lt;/a&gt; &lt;ul&gt; &lt;li&gt;Process change management: To identify the causes of defects and prevent    them from recurring.&lt;/li&gt;&lt;li&gt;Technology change management: To identify beneficial new technology and    transfer them in an orderly manner&lt;/li&gt;&lt;li&gt;Defect prevention: To continually improve the process to improve quality,    increase productivity, and decrease development time. &lt;/li&gt; &lt;/ul&gt;    &lt;p&gt;&lt;br /&gt;The purpose of Process Change Management is to continually improve the software  processes used in the organization with the intent of improving software  quality, increasing productivity, and decreasing the cycle time for product  development. When software process improvements are approved for normal practice, the  organization's standard software process and the projects' defined software  processes are revised as suited. &lt;/p&gt;    &lt;p&gt;&lt;br /&gt;The goals sought to achieve are as follows:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;Continuous process improvement is planned. &lt;/li&gt;&lt;li&gt;Participation in the organization's software process improvement    activities is organization wide. &lt;/li&gt;&lt;li&gt;The organization's standard software process and the projects defined    software processes are improved continuously. &lt;/li&gt; &lt;/ul&gt;    &lt;p&gt;&lt;br /&gt;These defined standards give the organization a commitment to perform because:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;The organization follows a written policy for implementing software    process improvements.&lt;/li&gt;&lt;li&gt;Senior management sponsors the organization's activities for software    process improvement.&lt;/li&gt; &lt;/ul&gt;    &lt;p&gt; &lt;/p&gt;    &lt;p&gt;The ability of the organization to perform transpires because:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;Adequate resources and funding are provided for software process    improvement activities.&lt;/li&gt;&lt;li&gt;Software managers receive required training in software process    improvement.&lt;/li&gt;&lt;li&gt;The managers and technical staff of the software engineering group and    other software-related groups receive required training in software process    improvement.&lt;/li&gt;&lt;li&gt;Senior management receives required training in software process    improvement.&lt;/li&gt; &lt;/ul&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/5079/872/1600/kpa.gif"&gt;&lt;br /&gt;&lt;/a&gt; &lt;h1&gt;Capability Maturity Model (CMM)  Process Area (PA) Activities&lt;/h1&gt;&lt;br /&gt;&lt;p&gt; The &lt;b&gt;Process Area Activities&lt;/b&gt; performed include:&lt;br /&gt;* A software process improvement program is established which empowers the    members of the organization to improve the processes of the organization.&lt;br /&gt;* The group responsible for the organization's software process activities    coordinates the software process improvement activities.&lt;br /&gt;* The organization develops and maintains a plan for software process    improvement according to a documented procedure.&lt;br /&gt;* The software process improvement activities are performed in accordance    with the software process improvement plan.&lt;br /&gt;* Software process improvement proposals are handled according to a    documented procedure.&lt;br /&gt;* Members of the organization actively participate in teams to develop    software process improvements for assigned process areas.&lt;br /&gt;* Where appropriate, the software process improvements are installed on a    pilot basis to determine their benefits and effectiveness before they are    introduced into normal practice.&lt;br /&gt;* When the decision is made to transfer a software process improvement into    normal practice, the improvement is implemented according to a documented    procedure.&lt;br /&gt;* Records of software process improvement activities are maintained.&lt;br /&gt;* Software managers and technical staff receive feedback on the status and    results of the software process improvement activities on an event-driven    basis.   &lt;/p&gt;  &lt;p&gt;The primary purpose of periodic reviews by senior management is to provide  awareness of, and insight into, software process activities at an appropriate  level of abstraction and in a timely manner. The time between reviews should  meet the needs of the organization and may be lengthy, as long as adequate  mechanisms for exception reporting are available. &lt;/p&gt;    &lt;p&gt;The &lt;i&gt;Capability Maturity Model&lt;/i&gt; has been criticized in that, that it does not  describe how to create an effective software development organization. The  traits it measures are in practice very hard to develop in an organization, even  though they are very easy to recognize. However, it cannot be denied that the  Capability Maturity Model reliably assesses an organization's sophistication  about software development.&lt;/p&gt;    &lt;p&gt;The CMM was invented to give military officers a quick way to assess and  describe contractors' abilities to provide correct software on time. It has been  a roaring success in this role. So much so that it caused panic-stricken  salespeople to clamor for their engineering organizations to "implement CMM"  with CMM level 5 being the ultimate.&lt;br /&gt;&lt;/p&gt; &lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-113092059863193804?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113092059863193804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113092059863193804'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/11/what-is-cmm-sei-capability-maturity.html' title='What is CMM (SEI Capability Maturity Model)?'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-113091697616984511</id><published>2005-11-02T14:32:00.000+07:00</published><updated>2005-11-02T14:36:16.193+07:00</updated><title type='text'>Capability Maturity Model aka (CMM)</title><content type='html'>The &lt;b&gt;Capability Maturity Model&lt;/b&gt; (CMM) is a method for evaluating and measuring the maturity of the &lt;a href="http://en.wikipedia.org/wiki/Software_development_process" title="Software development process"&gt;software development process&lt;/a&gt; of organizations on a scale of 1 to 5. The CMM was developed by the &lt;a href="http://en.wikipedia.org/wiki/Software_Engineering_Institute" title="Software Engineering Institute"&gt;Software Engineering Institute&lt;/a&gt; (SEI) at &lt;a href="http://en.wikipedia.org/wiki/Carnegie_Mellon_University" title="Carnegie Mellon University"&gt;Carnegie Mellon University&lt;/a&gt; in &lt;a href="http://en.wikipedia.org/wiki/Pittsburgh" title="Pittsburgh"&gt;Pittsburgh&lt;/a&gt;. It has been used extensively for &lt;a href="http://en.wikipedia.org/wiki/Avionics_software" title="Avionics software"&gt;avionics software&lt;/a&gt; and for government projects since it was created in the mid-1980s. The &lt;a href="http://en.wikipedia.org/wiki/Software_Engineering_Institute" title="Software Engineering Institute"&gt;Software Engineering Institute&lt;/a&gt; has subsequently released a revised version known as the &lt;b&gt;Capability Maturity Model Integration&lt;/b&gt; (CMMI). &lt;p&gt;The purpose of CMM Integration is to provide guidance for improving your organization’s processes and your ability to manage the development, acquisition, and maintenance of products or services.&lt;br /&gt;&lt;/p&gt; &lt;h2&gt;Levels of the CMM&lt;br /&gt;&lt;/h2&gt; &lt;p&gt;(See chapter 2 of (&lt;a href="http://www.sei.cmu.edu/pub/documents/02.reports/pdf/02tr012.pdf" class="external text" title="http://www.sei.cmu.edu/pub/documents/02.reports/pdf/02tr012.pdf"&gt;March 2002 edition of CMMI&lt;sup&gt;SM&lt;/sup&gt; from SEI&lt;/a&gt;), page 11.)&lt;/p&gt;  &lt;p&gt;There are five levels of the CMM. According to the SEI, "Predictability, effectiveness, and control of an organization's software processes are believed to improve as the organization moves up these five levels. While not rigorous, the empirical evidence to date supports this belief."&lt;/p&gt;  &lt;dl&gt; &lt;dt&gt;&lt;i&gt;1 - Initial&lt;/i&gt; &lt;/dt&gt; &lt;/dl&gt;  &lt;ul&gt; &lt;li&gt;At maturity level 1, processes are usually ad hoc and chaotic. The organization usually does not provide a stable environment. Success in these organizations depends on the competence and heroics of the people in the organization and not on the use of proven processes. In spite of this ad hoc, chaotic environment, maturity level 1 organizations often produce products and services that work; however, they frequently exceed the budget and schedule of their projects.&lt;/li&gt;&lt;li&gt;Maturity level 1 organizations are characterized by a tendency to over commit, abandon processes in the time of crisis, and not be able to repeat their past successes.&lt;/li&gt; &lt;/ul&gt;  &lt;dl&gt; &lt;dt&gt;&lt;i&gt;2 - Repeatable&lt;/i&gt; &lt;/dt&gt; &lt;/dl&gt;  &lt;ul&gt; &lt;li&gt;At maturity level 2, Software development successes are repeatable. The organization may use some basic &lt;a href="http://en.wikipedia.org/wiki/Project_management" title="Project management"&gt;project management&lt;/a&gt; to track cost and schedule.&lt;/li&gt;&lt;li&gt;Process discipline helps ensure that existing practices are retained during times of stress. When these practices are in place, projects are performed and managed according to their documented plans.&lt;/li&gt;&lt;li&gt;Project status and the delivery of services are visible to management at defined points (for example, at major milestones and at the completion of major tasks).&lt;/li&gt; &lt;/ul&gt;  &lt;dl&gt; &lt;dt&gt;&lt;i&gt;3 - Defined&lt;/i&gt; &lt;/dt&gt; &lt;/dl&gt;  &lt;ul&gt; &lt;li&gt;At maturity level 3, processes are well characterized and understood, and are described in standards, procedures, tools, and methods.&lt;/li&gt;&lt;li&gt;The organization’s set of standard processes, which is the basis for level 3, is established and improved over time. These standard processes are used to establish consistency across the organization. Projects establish their defined processes by tailoring the organization’s set of standard processes according to tailoring guidelines.&lt;/li&gt;&lt;li&gt;The organization’s management establishes process objectives based on the organization’s set of standard processes and ensures that these objectives are appropriately addressed.&lt;/li&gt;&lt;li&gt;A critical distinction between level 2 and level 3 is the scope of standards, process descriptions, and procedures. At level 2, the standards, process descriptions, and procedures may be quite different in each specific instance of the process (for example, on a particular project). At level 3, the standards, process descriptions, and procedures for a project are tailored from the organization’s set of standard processes to suit a particular project or organizational unit.&lt;/li&gt; &lt;/ul&gt;  &lt;dl&gt; &lt;dt&gt;&lt;i&gt;4 - Managed&lt;/i&gt; &lt;/dt&gt; &lt;/dl&gt;  &lt;ul&gt; &lt;li&gt;Using precise measurements, management can effectively control the software development effort. In particular, management can identify ways to adjust and adapt the process to particular projects without measurable losses of quality or deviations from specifications.&lt;/li&gt;&lt;li&gt;Subprocesses are selected that significantly contribute to overall process performance. These selected subprocesses are controlled using statistical and other quantitative techniques.&lt;/li&gt;&lt;li&gt;A critical distinction between maturity level 3 and maturity level 4 is the predictability of process performance. At maturity level 4, the performance of processes is controlled using statistical and other quantitative techniques, and is quantitatively predictable. At maturity level 3, processes are only qualitatively predictable.&lt;/li&gt; &lt;/ul&gt;  &lt;dl&gt; &lt;dt&gt;&lt;i&gt;5 - Optimizing&lt;/i&gt; &lt;/dt&gt; &lt;/dl&gt;  &lt;ul&gt; &lt;li&gt;Maturity level 5 focuses on continually improving process performance through both incremental and innovative technological improvements. Quantitative process-improvement objectives for the organization are established, continually revised to reflect changing business objectives, and used as criteria in managing process improvement. The effects of deployed process improvements are measured and evaluated against the quantitative process-improvement objectives. Both the defined processes and the organization’s set of standard processes are targets of measurable improvement activities.&lt;/li&gt;&lt;li&gt;Process improvements to address common causes of process variation and measurably improve the organization’s processes are identified, evaluated, and deployed.&lt;/li&gt;&lt;li&gt;Optimizing processes that are agile and innovative depends on the participation of an empowered workforce aligned with the business values and objectives of the organization. The organization’s ability to rapidly respond to changes and opportunities is enhanced by finding ways to accelerate and share learning.&lt;/li&gt;&lt;li&gt;A critical distinction between maturity level 4 and maturity level 5 is the type of process variation addressed. At maturity level 4, processes are concerned with addressing special causes of process variation and providing statistical predictability of the results. Though processes may produce predictable results, the results may be insufficient to achieve the established objectives. At maturity level 5, processes are concerned with addressing common causes of process variation and changing the process (that is, shifting the mean of the process performance) to improve process performance (while maintaining statistical probability) to achieve the established quantitative process-improvement objectives.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;br /&gt;&lt;/p&gt;  &lt;hr /&gt; &lt;p&gt;Recent versions of CMMI from SEI indicate a "level 0", characterized as "Incomplete". Many observers leave this level out as redundant or unimportant, but Pressman and others make note of it. See page 18 of the &lt;a href="http://www.sei.cmu.edu/pub/documents/02.reports/pdf/02tr011.pdf" class="external text" title="http://www.sei.cmu.edu/pub/documents/02.reports/pdf/02tr011.pdf"&gt;August 2002 edition of CMMI from SEI&lt;/a&gt; (Note: PDF file).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/w/index.php?title=Anthony_Finkelstein&amp;action=edit" class="new" title="Anthony Finkelstein"&gt;Anthony Finkelstein&lt;/a&gt; extrapolated that negative levels, or the &lt;i&gt;&lt;a href="http://www.stsc.hill.af.mil/crosstalk/1996/11/xt96d11h.asp" class="external text" title="http://www.stsc.hill.af.mil/crosstalk/1996/11/xt96d11h.asp"&gt;Capability Immaturity Model&lt;/a&gt;&lt;/i&gt;, are necessary to represent environments that are not only indifferent, but actively counterproductive, and this was refined by Tom Schorsch:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;CMM level 0 (&lt;i&gt;negligent&lt;/i&gt;)&lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt; &lt;li&gt;CMM level -1 (&lt;i&gt;obstructive&lt;/i&gt;)&lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt; &lt;li&gt;CMM level -2 (&lt;i&gt;contemptuous&lt;/i&gt;)&lt;/li&gt; &lt;/ul&gt;  &lt;ul&gt; &lt;li&gt;CMM level -3 (&lt;i&gt;undermining&lt;/i&gt;)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Do not completely agree.&lt;br /&gt;&lt;/p&gt; &lt;h2&gt;Some praise of the CMM&lt;/h2&gt;  &lt;ol&gt; &lt;li&gt;The CMM was developed to give Defense organizations a yardstick to assess and describe the capability of software contractors to provide software on time, within budget, and to acceptable standards. It has arguably been successful in this role, even reputedly causing some software salespeople to clamour for their organizations' software engineers/developers to "implement CMM."&lt;/li&gt;&lt;li&gt;The CMM is intended to enable an assessment of an organization's maturity for software development. It is an important tool for outsourcing and exporting software development work. Economic development agencies in India, Ireland, Egypt, and elsewhere have praised the CMM for enabling them to be able to compete for US outsourcing contracts on an even footing. Whilst this may have been very positive for the employment of software engineers in emerging or Third World economies - notably in India during the early 2000s - it is regarded as having adversely affected the potential employment opportunities for software engineers in the developed economies - notably the USA and Europe. This outsourcing is a form of labor arbitrage which is similar to the movement of manufacturing of (for example) fashion clothing or Nike shoes to Third World economies with relatively cheap labor rates.&lt;/li&gt;&lt;li&gt;It is reputed that IBM, Motorola, Logica, BT, and others have discovered the following: &lt;ul&gt;&lt;li&gt;It takes 18 months on average to move up one SEI level, but it has been done in 8 (refer XXX? to substantiate this).&lt;/li&gt;&lt;li&gt;Defect rates can be lowered from 1 per 1,000 lines of code (said to be typical of Microsoft and its peers) down to 1 per 1,000,000 lines - this is roughly &lt;a href="http://en.wikipedia.org/wiki/Six_Sigma" title="Six Sigma"&gt;Six Sigma&lt;/a&gt; quality; refer also relevant &lt;a href="http://en.wikipedia.org/wiki/W._Edwards_Deming" title="W. Edwards Deming"&gt;Deming&lt;/a&gt; references (NB: Deming was not a proponent of Six Sigma per se, and advised against the use of any slogans for process quality improvement).(refer XXX? to substantiate this)&lt;/li&gt;&lt;li&gt;There is no specific evidence for shortening "time to market", but there is (refer XXX? to substantiate this) for increasing the accuracy of estimating completion date from 75% overruns on average at level 1, to plus or minus 2% at level 5.&lt;/li&gt;&lt;li&gt;Data on productivity increases is more variable, but it is at least (refer XXX? to substantiate this) a doubling of productivity.&lt;/li&gt;&lt;/ul&gt; &lt;/li&gt; &lt;/ol&gt; &lt;h2&gt;Some criticism of the CMM&lt;/h2&gt;  &lt;ol&gt; &lt;li&gt;CMM has failed to take off the world over. It's hard to tell exactly how wide spread it is as the SEI only publishes the names and achieved levels of compliance of companies that have requested this information to be listed (&lt;a href="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#RATE03" class="external free" title="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#RATE03"&gt;http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#RATE03&lt;/a&gt;). The most current Maturity Profile for CMMI is available at &lt;a href="http://www.sei.cmu.edu/appraisal-program/profile/pdf/CMMI/2005marCMMI.pdf" class="external free" title="http://www.sei.cmu.edu/appraisal-program/profile/pdf/CMMI/2005marCMMI.pdf"&gt;http://www.sei.cmu.edu/appraisal-program/profile/pdf/CMMI/2005marCMMI.pdf&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;No external body actually certifies a software development center as being CMM compliant. It is supposed to be an honest self-assessment. &lt;a href="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR04" class="external free" title="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR04"&gt;http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR04&lt;/a&gt; and &lt;a href="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR05" class="external free" title="http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR05"&gt;http://www.sei.cmu.edu/cmmi/faq/ares-faq.html#APR05&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The CMM does not describe how to create an effective software development organization. The CMM contains behaviors or best practices that successful projects have demonstrated. Being CMM compliant is not a guarantee that a project will be successful, however being compliant &lt;i&gt;can&lt;/i&gt; increase a project's chances of being successful.&lt;/li&gt;&lt;li&gt;The CMM can seem to be overly bureaucratic, promoting process over substance. For example, for emphasizing predictability over service provided to end users. More commercially successful methodologies (for example, the &lt;a href="http://en.wikipedia.org/wiki/Rational_Unified_Process" title="Rational Unified Process"&gt;Rational Unified Process&lt;/a&gt;) have focused not on the capability of the organization to produce software to satisfy some other organization or a collectively-produced specification, but on the capability of organizations to satisfy specific end user "&lt;a href="http://en.wikipedia.org/wiki/Use_cases" title="Use cases"&gt;use cases&lt;/a&gt;" as per the Object Management Group's UML (&lt;a href="http://en.wikipedia.org/wiki/Unified_Modeling_Language" title="Unified Modeling Language"&gt;Unified Modeling Language&lt;/a&gt;) approach. &lt;a href="http://www.sei.cmu.edu/publications/documents/93.reports/93.tr.024.html" class="external autonumber" title="http://www.sei.cmu.edu/publications/documents/93.reports/93.tr.024.html"&gt;[1]&lt;/a&gt;.cccc&lt;/li&gt; &lt;/ol&gt; &lt;h2&gt;The most beneficial elements of CMM Level 2 and Level 3&lt;/h2&gt;  &lt;ol&gt; &lt;li&gt;Creation of Software Specifications, stating what it is that is going to be developed, combined with formal sign off, an executive sponsor and approval mechanism. This is NOT a living document, but additions are placed in a deferred or out of scope section for later incorporation into the next cycle of software development.&lt;/li&gt;&lt;li&gt;A Technical Specification, stating how precisely the thing specified in the Software Specifications is to be developed will be used. This is a living document.&lt;/li&gt;&lt;li&gt;Peer Review of Code (Code Review) with metrics that allow developers to walk through an implementation, and to suggest improvements or changes. Note - This is problematic because the code has already been developed and a bad design can not be fixed by "tweaking", the Code Review gives complete code a formal approval mechanism.&lt;/li&gt;&lt;li&gt;Version Control - a very large number of organizations have no formal revision control mechanism or release mechanism in place.&lt;/li&gt;&lt;li&gt;The idea that there is a "right way" to build software, that it is a scientific process involving engineering design and that groups of developers are not there to simply work on the problem du jour.&lt;/li&gt; &lt;/ol&gt; References:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;&lt;a href="http://www.sei.cmu.edu/cmmi/" class="external text" title="http://www.sei.cmu.edu/cmmi/"&gt;CMMI Official Web Site&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.digite.com/resources/download_whitepaper.htm?download/cmmi.htm" class="external text" title="http://www.digite.com/resources/download whitepaper.htm?download/cmmi.htm"&gt;A Whitepaper on CMMi Implementation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.digite.com/4.0/products/digite_cmmi.htm" class="external text" title="http://www.digite.com/4.0/products/digite cmmi.htm"&gt;CMMi Automation Software&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.tc.umn.edu/%7Ehause011/article/Capability_maturity_models.html" class="external text" title="http://www.tc.umn.edu/~hause011/article/Capability maturity models.html"&gt;A critical look at implementing CMM Level 2&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.cio.com/archive/030104/cmm.html" class="external free" title="http://www.cio.com/archive/030104/cmm.html"&gt;http://www.cio.com/archive/030104/cmm.html&lt;/a&gt; [CIO Article, Beware the CMM Hype]&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-113091697616984511?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113091697616984511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/113091697616984511'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/11/capability-maturity-model-aka-cmm.html' title='Capability Maturity Model aka (CMM)'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112583744006529244</id><published>2005-09-04T19:36:00.000+07:00</published><updated>2005-09-04T19:37:20.076+07:00</updated><title type='text'>The Case for Nullable Types</title><content type='html'>&lt;div class="PageTitle"&gt;Nullable Types&lt;/div&gt;                       by &lt;a class="TagLine" href="http://www.asptoday.com/Authors.aspx?ID=721"&gt;Kamran Qamar&lt;/a&gt;&lt;span id="Homepage1_lblBody"&gt;&lt;p&gt;&lt;br /&gt;Imagine some part of your code stores an amount of money. Now software is driven by strict rules of mathematics, and there's normally a need to quantify each variable we use. That is why, in .NET, each type has default value. Value-type variables always have predefined values e.g. &lt;span class="codeintext"&gt;int&lt;/span&gt;  has default value of 0 and  &lt;span class="codeintext"&gt;bool&lt;/span&gt;  has default value of  &lt;span class="codeintext"&gt;false&lt;/span&gt; . So far so good, but a problem arises when we try to apply our strict mathematical rules to the real world, in which you might not have all the data available. For example, how does a value of 0 distinguish that a user has no money from the case where they have not entered any value for your software to store. This problem becomes clearer when you start working with relational databases. Relational databases have a concept of a &lt;span class="codeintext"&gt;NULL&lt;/span&gt; value, which indicates that no data is present, and, for value types, does not yield an appropriate value in .NET programming languages.&lt;/p&gt; &lt;h2 class="redhead0"&gt;Achieving Nullable Values - Current Techniques&lt;/h2&gt; &lt;p&gt;Over the years developers have adopted a number of workarounds for this problem, some of which I'll briefly discuss:&lt;/p&gt; &lt;h3 class="redhead1"&gt;Special Values&lt;/h3&gt; &lt;p&gt;One of the most notable solutions is to use some special unused value of the given data type as the null value e.g. if you are dealing with an age, you define it as &lt;span class="codeintext"&gt;int&lt;/span&gt; and use -1 as the null value. This solution is workable only when you can identify value which is definitely unused and won't therefore be mistaken for a real value, e.g. if you are working with dollar ($) amount, -1 may indicate a loss of 1$ and is not therefore suitable to represent a null value if this value might occur.&lt;/p&gt; &lt;p&gt;This solution is simple to implement, but generally frowned upon because of the potential for subtle runtime bugs, especially if the application requirements subsequently change so that the value previously used as the null value becomes a legitimate value.&lt;/p&gt; &lt;h3 class="redhead1"&gt;Using a Flag&lt;/h3&gt; &lt;p&gt;One solution that I have used frequently is to define a flag in the object that contains the possibly null field, which is used to determine if the value is null or not. Incidentally system classes also use this approach e.g. &lt;span class="codeintext"&gt;SqlDataReader&lt;/span&gt;  has a property  &lt;span class="codeintext"&gt;IsDbNull&lt;/span&gt;  that identifies if value returned from a database record is null or not.&lt;/p&gt; &lt;p&gt;Here's an example of this approach:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;public class Person&lt;br /&gt;{&lt;br /&gt;  private string _fullName;&lt;br /&gt;  private int _age;&lt;br /&gt;  private bool _hasAge;&lt;br /&gt;  public string FullName&lt;br /&gt;  {&lt;br /&gt;     get{return _fullName;}&lt;br /&gt;     set{_fullName = value;}&lt;br /&gt;  }&lt;br /&gt;  public int Age&lt;br /&gt;  {&lt;br /&gt;     get&lt;br /&gt;     {&lt;br /&gt;        if(!_hasAge)&lt;br /&gt;           throw new InvalidOperationException("Value not set");&lt;br /&gt;        return _age;&lt;br /&gt;     }&lt;br /&gt;     set&lt;br /&gt;     {&lt;br /&gt;        _age = value;&lt;br /&gt;        _hasAge = true;&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;  public bool HasAge&lt;br /&gt;  {&lt;br /&gt;     get{return _hasAge;}&lt;br /&gt;  }&lt;br /&gt;  public void Load(SqlDataReader dr)&lt;br /&gt;  {&lt;br /&gt;     if(dr["FullName"].IsDbNull)&lt;br /&gt;        _fullName = "";&lt;br /&gt;     else&lt;br /&gt;        _fullName = dr["FullName"].ToString();&lt;br /&gt;     _hasAge = dr["Age"].IsDbNull;&lt;br /&gt;     if(!_hasAge)&lt;br /&gt;        _age = (int)dr["Age"];&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;The above code is an example of using flag to identify a value as null. Here the code is using the  &lt;span class="codeintext"&gt;HasAge&lt;/span&gt;  property to determine if you have an  &lt;span class="codeintext"&gt;Age&lt;/span&gt;  value or not. The class sets this flag to  &lt;span class="codeintext"&gt;true&lt;/span&gt; , whenever the  &lt;span class="codeintext"&gt;Age&lt;/span&gt;  property is set. In client code, you always need to check  &lt;span class="codeintext"&gt;HasAge&lt;/span&gt;  value before using the  &lt;span class="codeintext"&gt;Age&lt;/span&gt;  property.&lt;/p&gt; &lt;h3 class="redhead1"&gt;Defining a Nullable Type&lt;/h3&gt; &lt;p&gt;Some developers go even a step further and define their own value types e.g. consider the following code:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;public struct NullableInt&lt;br /&gt;{&lt;br /&gt;  bool isNull;&lt;br /&gt;  public bool IsNull { get { return isNull;}}&lt;br /&gt;  bool value;&lt;br /&gt;  public int Value {&lt;br /&gt;     get { return value;}&lt;br /&gt;     set { @value=value;isNull=false;}&lt;br /&gt;  }&lt;br /&gt;  public NullableInt()&lt;br /&gt;  {&lt;br /&gt;     isNull = true;&lt;br /&gt;  }&lt;br /&gt;// etc.&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;By using this  &lt;span class="codeintext"&gt;NullableInt&lt;/span&gt;  type instead of standard system  &lt;span class="codeintext"&gt;int&lt;/span&gt;  type, we obtain more control over our data.&lt;/p&gt; &lt;p class="BackgroundNote"&gt;Editors Note: ASP Today readers might be interested to know that the ASP Today codebase makes extensive use of this solution for dates. Most of the dates you see displayed on the site come to you courtesy of a custom-coded &lt;span class="codeintext"&gt;Date&lt;/span&gt;  struct, whose main raison d'etre is to wrap  &lt;span class="codeintext"&gt;System.DateTime&lt;/span&gt;  to make it nullable!&lt;/p&gt; &lt;p&gt;One advantage of this approach is you can if you wish also define a  &lt;span class="codeintext"&gt;DefaultValue&lt;/span&gt; field, something that is available in value types, though lost in the above code. If you do define such a field, you'll need to decide what the most reasonable behaviour is for example constructing instances - eg. you might want a value to default to its default value, but be settable to &lt;span class="codeintext"&gt;null&lt;/span&gt;  if the client code requires it.&lt;/p&gt; &lt;p&gt;This approach can work really well, and has the advantage of encapsulating the nullable-ness so client code doesn't have to worry as much about null values. But what happens when you add - say - two &lt;span class="codeintext"&gt;NullableInt&lt;/span&gt; s? Yes you can do that, all you have to do is upgrade the  &lt;span class="codeintext"&gt;NullableInt&lt;/span&gt;  struct with some operator overloads. And what about casting a double to  &lt;span class="codeintext"&gt;NullableInt&lt;/span&gt; , that's less trivial, but you can achieve the same result by providing a constructor at the cost of some easy syntax. (You could instead use an operator overload, but I'll illustrate the principle here with a constructor):&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;public NullableInt(double d)&lt;br /&gt;{&lt;br /&gt;  Value = d;&lt;br /&gt;}&lt;br /&gt;…&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;The client code that uses this might look as follows:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;NullableInt i;&lt;br /&gt;double d = 2.5;&lt;br /&gt;i = new NullableInt(d);&lt;br /&gt;Console.WriteLine(i.ToString()); //will print 2&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;Where traditionally you would have simply written code like this:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int i;&lt;br /&gt;double d = 2.5;&lt;br /&gt;i = d;&lt;br /&gt;Console.WriteLine(i.ToString()); //will print 2&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;This approach is extremely powerful but in some cases can be over kill, because not only that all the values do not require to be null able at all the time, it also requires custom data types and special coding discipline on part of all the developers involved.&lt;/p&gt; &lt;h2 class="redhead0"&gt;Introducing .NET2.0 Nullable Types&lt;/h2&gt; &lt;p&gt;Now that I have scared you with the limitation of the third approach, let me give you the good news. The C# 2.0 language solves this long standing problem by proving complete and integrated support for a nullable version of all value types, based on a clever application of generics along with some neat supporting syntax.&lt;/p&gt; &lt;p&gt;A variable of a nullable type can represent all the values of its underlying type, plus an additional null value. The way to define any valuetype as a nullable type is to define the generic &lt;span class="codeintext"&gt;System.Nullable&lt;t&gt;&lt;/span&gt;  type. Therefore the syntax to define a nullable integer is:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;System.Nullable&lt;int&gt; i;&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;This is kind of tedious, that is why C# team did a favor to us by providing a clean syntax for the nullable type in the form of &lt;span class="codeintext"&gt;[Value-Type]? &lt;/span&gt; hence  &lt;span class="codeintext"&gt;System.Nullable&lt;t&gt;&lt;/span&gt;  and  &lt;span class="codeintext"&gt;T?&lt;/span&gt;  are interchangeable, and the statements below are equivalent and will both result in declaring a nullable  &lt;span class="codeintext"&gt;int&lt;/span&gt;  variable.&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;System.Nullable&lt;int&gt; i;&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;Or&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int? i;&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;Using this syntax you can define any value-type as nullable type. You'll see more examples in the rest of this column piece.&lt;/p&gt; &lt;h3 class="redhead1"&gt;Understanding the System.Nullable&lt;t&gt; type&lt;/h3&gt; &lt;p&gt;Before I dig deeper into the different features and benefits of the nullable types, it will be beneficial to understand how the nullable behavior is achieved in .NET. As I mentioned, at the heart of this behavior is generics. For more information about generics see the excellent article from Juval Lowy at &lt;a target="_new" class="redlink" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/csharp_generics.asp"&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/csharp_generics.asp&lt;/a&gt; .&lt;/p&gt; &lt;p&gt;&lt;span class="codeintext"&gt;The System.Nullable&lt;t&gt;&lt;/span&gt; is the generic type that makes the magic of nullable types possible. You can define any value type as nullable. Examples of nullable types are:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int? i = -1;&lt;br /&gt;bool? flag = null;&lt;br /&gt;char? chr = 'z';&lt;br /&gt;int?[] MyArray = new int?[10];&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;Remember,  &lt;span class="codeintext"&gt;T&lt;/span&gt;  in  &lt;span class="codeintext"&gt;System.Nullable&lt;t&gt;&lt;/span&gt; is always a value-type. Hence the following lines of codes are incorrect and will result in compile time warnings (you might expect errors but in practice I found it was simply giving warnings):&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;string? Message = "Hello, World!";       // Compiler warning&lt;br /&gt;SomeClass? someClass { };          // Compiler warning&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;&lt;span class="codeintext"&gt;System.Nullable&lt;t&gt;&lt;/span&gt;  has two public properties:  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt;  of type  &lt;span class="codeintext"&gt;bool&lt;/span&gt;  and  &lt;span class="codeintext"&gt;Value&lt;/span&gt; , which is of the same type as the nullable type's underlying type. The  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt;  property is always true for any non-null instance and false for null instances. When  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt;  is true, the  &lt;span class="codeintext"&gt;Value&lt;/span&gt;  property returns the contained value. When the  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt;  is false, an attempt to access the  &lt;span class="codeintext"&gt;Value&lt;/span&gt;  property will result in  &lt;span class="codeintext"&gt;InvalidOperationException&lt;/span&gt;  exception. This follows what you'd probably regard as expected behaviour for a nullable type.&lt;/p&gt; &lt;h3 class="redhead1"&gt;Using a Nullable Type&lt;/h3&gt; &lt;p&gt;The following code shows how you would use a nullable integer&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int? i;    // declaration&lt;br /&gt;Console.WriteLine(i.HasValue);     // will print false&lt;br /&gt;Console.WriteLine(i.Value);        // through InvalidOperationException&lt;br /&gt;i = 18;                            //initialization&lt;br /&gt;Console.WriteLine(i.HasValue);     //true&lt;br /&gt;Console.WriteLine(i.Value);        //print 18&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;h3 class="redhead1"&gt;Checking for Null Values&lt;/h3&gt; &lt;p&gt;As you can see in above code, when the new instance of a nullable type is created, its  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt;  property return false, which means, as indicated before, that any attempt to access its value will result in  &lt;span class="codeintext"&gt;InvalidOperationException&lt;/span&gt; .  Does this mean, we always have to use the  &lt;span class="codeintext"&gt;HasValue&lt;/span&gt; property to determine if a nullable type variable is null or not? Absolutely not, C# allows you to can check if a nullable object is null or not by comparing it against &lt;span class="codeintext"&gt;null&lt;/span&gt;  keyword just as we do for reference-type objects. Hence, following syntax is valid:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;if (i == null)&lt;br /&gt;   Console.WriteLine("i is null");&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;In client code, you would most commonly check if the object is null or not, if it is not null you would use the value, otherwise you'll need to make some decision based on the situation. (Assuming of course that you are not in a situation where the algorithm you have been coding guarantees that a non-null value has been placed in the variable concerned). For example in the following code, I have defined i as a nullable int and x as a normal int. Next I check if i is null or not, if it is, I get the default value of i. This by the way demonstrates the new &lt;span class="codeintext"&gt;default&lt;/span&gt;  keyword in C#2.0. Next, if i is not null, I set x with the value of i.&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int? i = 18;&lt;br /&gt;int x;&lt;br /&gt;if(i == null)&lt;br /&gt;  x = default(int);&lt;br /&gt;else&lt;br /&gt;  x = i.Value;&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;This is quite a lengthy code isn't it? The C#2.0 introduce new operator  &lt;span class="codeintext"&gt;??&lt;/span&gt;  that does exactly this for us. See the code below:&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;int? i = 18;&lt;br /&gt;int x;&lt;br /&gt;x = i?? default(int); //getting default value&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;p&gt;or&lt;/p&gt; &lt;!-- @@START --&gt; &lt;pre class="CodeForeground"&gt;x = i ?? 18; //defining my own value&lt;br /&gt;&lt;/pre&gt;&lt;!-- @@END --&gt; &lt;h2 class="redhead0"&gt;Conclusion&lt;/h2&gt; &lt;p&gt;Remember how difficult it was to initialize or compare an  &lt;span class="codeintext"&gt;enum&lt;/span&gt;  or  &lt;span class="codeintext"&gt;struct&lt;/span&gt; type for a null value with .NET 1.0 - you typically had to write special code to check if the value of is valid or not. Now with C# 2.0, you can employ the power and elegance of the nullable type and the associated special syntax to check for null just like when using a reference-type.&lt;/p&gt; &lt;p&gt;Nullable types equip us with a powerful mechanism to handle special situations including database null values or other data types that contain fields that may not be assigned a value. Since this functionality is built right into the infrastructure using generics, it does not introduce any drastic performance penalty. However, converting an ordinary value type to nullable value type does introduce additional work for the infrastructure; hence nullable types should be used cautiously. Their use also dictates special consideration while assigning to ordinary value types and operating with them&lt;/p&gt; &lt;p&gt;That was a quick overview of null able types in .NET 2.0. for more information you can consult the .NET2.0 documentation.&lt;/p&gt; &lt;p&gt;Happy Programming!&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-112583744006529244?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112583744006529244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112583744006529244'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/09/case-for-nullable-types.html' title='The Case for Nullable Types'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112577486175287071</id><published>2005-09-04T02:06:00.000+07:00</published><updated>2005-09-04T02:14:21.776+07:00</updated><title type='text'>On the Way to Mastering ASP.NET: Introducing Custom Entity Classes</title><content type='html'>&lt;p&gt;Karl Seguin&lt;/p&gt;   &lt;p&gt;March 2005&lt;/p&gt;   &lt;p&gt;&lt;b&gt;Summary:&lt;/b&gt; There are situations for which untyped &lt;b&gt;DataSets&lt;/b&gt; may not be the best solution for data manipulation. The goal of this guide is to explore an alternative to &lt;b&gt;DataSets:&lt;/b&gt; custom entities and collections. (32 printed pages)&lt;/p&gt;   &lt;h4 class="dtH1"&gt;Contents&lt;/h4&gt;   &lt;p&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic1" target="_self"&gt;Introduction&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic2" target="_self"&gt;Problems with Datasets&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic3" target="_self"&gt;Custom Entity Classes&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic4" target="_self"&gt;Object-Relational Mapping&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic5" target="_self"&gt;Custom Collections&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic6" target="_self"&gt;Managing Relationships&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic7" target="_self"&gt;Beyond the Basics&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/CustEntCls.asp#custentcls_topic8" target="_self"&gt;Conclusion&lt;/a&gt;&lt;/p&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic1"&gt;&lt;/a&gt;Introduction&lt;/h2&gt;   &lt;p&gt;The days of &lt;b&gt;ADODB.RecordSet&lt;/b&gt; and the oft-forgotten &lt;b&gt;MoveNext&lt;/b&gt; are gone, replaced by the powerful and flexible capabilities of Microsoft ADO.NET. Our new arsenal is the &lt;b&gt;System.Data&lt;/b&gt; namespace, featuring lightning-fast &lt;b&gt;DataReaders,&lt;/b&gt; feature-rich &lt;b&gt;DataSets,&lt;/b&gt; and packaged in a capable object-oriented model. It's no surprise that we have such tools at our disposal. Any 3-tier architecture relies on a solid Data Access Layer (DAL) to elegantly connect the data layer to the business layer. A quality DAL helps promote code reuse, is key to good performance, and is totally transparent.&lt;/p&gt;   &lt;p&gt;As our tools have evolved, so too have our development patterns. Saying goodbye to &lt;b&gt;MoveNext&lt;/b&gt; was more than ridding ourselves of cumbersome syntax; it opened our minds to disconnected data, which in turn had a profound impact on how we built applications. &lt;/p&gt;   &lt;p&gt;While &lt;b&gt;DataReaders&lt;/b&gt; might have been familiar (they behave a lot like &lt;b&gt;RecordSets&lt;/b&gt;), it didn't take long for us to venture forward and explore &lt;b&gt;DataAdapters,&lt;/b&gt; &lt;b&gt;DataSets,&lt;/b&gt; &lt;b&gt;DataTables,&lt;/b&gt; and &lt;b&gt;DataViews&lt;/b&gt;. It was our growing skills at exploiting these new objects that changed how we developed. Disconnected data allowed us to utilize new caching techniques, and thus greatly improve the performance of our applications. The capability of these classes allowed us to write smarter and more powerful functions, while at the same time reducing, sometimes considerably, the amount of code required for common activities.&lt;/p&gt;   &lt;p&gt;There are a number of situations for which &lt;b&gt;DataSets&lt;/b&gt; are particularly well suited, such as prototyping, small systems, and support utilities. However, using them in enterprise systems, where ease of maintenance is more important than time to market, may not be the best solution. The goal of this guide is to explore an alternative to &lt;b&gt;DataSets&lt;/b&gt; that is geared towards this type of work: custom entities and collections. Other alternatives exist, but none provide the same capability or have more backing. Our first task will be to look at the shortcomings of &lt;b&gt;DataSets&lt;/b&gt; in order to understand the problem we are trying to solve.  &lt;/p&gt;   &lt;p&gt;Keep in mind that every solution has its own advantages and disadvantages, so it's possible that the drawbacks of &lt;b&gt;DataSets&lt;/b&gt; are going to be more palatable to you than those of custom entities (which we'll also discuss). You and your team must decide which solution is better suited to your project. Remember to consider the total cost of a solution, including the nature of requirements to change and the likelihood that you'll spend more time in post-production than actually developing code. Finally, note that when I refer to &lt;b&gt;DataSets&lt;/b&gt;, I don't mean typed-&lt;b&gt;DataSets,&lt;/b&gt; which indeed solve some of the shortcomings associated with untyped-&lt;b&gt;DataSets&lt;/b&gt;.&lt;/p&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic2"&gt;&lt;/a&gt;Problems with Datasets&lt;/h2&gt;   &lt;h3 class="dtH1"&gt;Lack of Abstraction&lt;/h3&gt;   &lt;p&gt;The first and most obvious reason to consider alternatives is the &lt;b&gt;DataSet&lt;/b&gt;'s inability to decouple your code from the database structure. &lt;b&gt;DataAdapters&lt;/b&gt; do a great job of making your code blind to the underlying database vendor (Microsoft, Oracle, IBM, …) but fail to abstract away the core component of a database: tables, columns, and relationships. These core database components are also the core components of the &lt;b&gt;DataSet.&lt;/b&gt; &lt;b&gt;DataSets&lt;/b&gt; and databases share more than just common components; unfortunately, they also share their schema. Given the following select statement:&lt;/p&gt;   &lt;pre class="code"&gt;SELECT UserId, FirstName, LastName&lt;br /&gt;  FROM Users&lt;/pre&gt;   &lt;p&gt;We know that values will be available from the &lt;b&gt;UserId,&lt;/b&gt; &lt;b&gt;FirstName,&lt;/b&gt; and &lt;b&gt;LastName&lt;/b&gt; &lt;b&gt;DataColumns&lt;/b&gt; within our &lt;b&gt;DataSet.&lt;/b&gt; &lt;/p&gt;   &lt;p&gt;Why is this so bad? Let's look at a basic everyday example. First we have a simple DAL function:  &lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function GetAllUsers() As DataSet&lt;br /&gt;Dim connection As New SqlConnection(CONNECTION_STRING)&lt;br /&gt;Dim command As SqlCommand = New SqlCommand("GetUsers", connection)&lt;br /&gt;command.CommandType = CommandType.StoredProcedure&lt;br /&gt;Dim da As SqlDataAdapter = New SqlDataAdapter(command)&lt;br /&gt;Try&lt;br /&gt; Dim ds As DataSet = New DataSet&lt;br /&gt; da.Fill(ds)&lt;br /&gt; Return ds&lt;br /&gt;Finally&lt;br /&gt; connection.Dispose()&lt;br /&gt; command.Dispose()&lt;br /&gt; da.Dispose()&lt;br /&gt;End Try&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public DataSet GetAllUsers() {&lt;br /&gt;SqlConnection connection = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;SqlCommand command = new SqlCommand("GetUsers", connection);&lt;br /&gt;command.CommandType = CommandType.StoredProcedure;&lt;br /&gt;SqlDataAdapter da = new SqlDataAdapter(command);&lt;br /&gt;try {&lt;br /&gt; DataSet ds = new DataSet();&lt;br /&gt; da.Fill(ds);&lt;br /&gt; return ds;&lt;br /&gt;}finally {&lt;br /&gt; connection.Dispose();&lt;br /&gt; command.Dispose();&lt;br /&gt; da.Dispose();&lt;br /&gt;}           &lt;br /&gt;}&lt;/pre&gt;   &lt;p&gt;Next we have a page with a repeater displaying all the users:&lt;/p&gt;   &lt;pre class="code"&gt;&lt;html&gt;&lt;br /&gt;&lt;body&gt;&lt;br /&gt;  &lt;form id="Form1" method="post" runat="server"&gt;&lt;br /&gt;    &lt;asp:repeater id="users" runat="server"&gt;&lt;br /&gt;       &lt;itemtemplate&gt;&lt;br /&gt;          &lt;%# DataBinder.Eval(Container.DataItem, "FirstName") %&gt;&lt;br /&gt;          &lt;br /&gt;&lt;br /&gt;       &lt;/itemtemplate&gt;&lt;br /&gt;    &lt;/asp:Repeater&gt;&lt;br /&gt;  &lt;/form&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;script runat="server"&gt;&lt;br /&gt; public sub page_load&lt;br /&gt;    users.DataSource = GetAllUsers()&lt;br /&gt;    users.DataBind()&lt;br /&gt; end sub&lt;br /&gt;&lt;/script&gt;&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;As we can see, our ASPX page makes use of the DAL function &lt;b&gt;GetAllUsers&lt;/b&gt; for the &lt;b&gt;DataSource&lt;/b&gt; of the repeater. If the database schema changes, for whatever reason (demoralization for performance, normalization for clarity, change in requirements), the change trickles all the way to the ASPX, namely the &lt;b&gt;Databinder.Eval&lt;/b&gt; line, which makes use of the "FirstName" column name. This should immediately raise a red flag in your mind: a database schema change trickling all the way to ASPX code? Doesn't sound very N-Tier, does it?&lt;/p&gt;   &lt;p&gt;If all we are doing is a simple column renaming, making changes in this example isn't complicated. But what if &lt;b&gt;GetAllUsers&lt;/b&gt; is used in numerous places or, worse yet, exposed as a Web service, feeding countless consumers? How easily or safely can the change be propagated? For this basic example, the stored procedure itself serves as a layer of abstraction, which would probably suffice; but relying on stored procedures for anything but the most basic protection against this will likely cause greater problems down the road. Think of this as a form of hard-coding; in essence, when using &lt;b&gt;DataSets,&lt;/b&gt; you are likely going to create a rigid connection between your database schema (regardless of whether you use column names or ordinal positions) and your application/business layers. Hopefully past experience (or logic) has taught you the impact hard-coding has on maintenance and future development.&lt;/p&gt;   &lt;p&gt;Another way &lt;b&gt;DataSets&lt;/b&gt; fail to provide proper abstraction is by requiring developers to know the underlying schema. We aren't talking about basic knowledge, either, but full knowledge of column names, types, and relationships. Not only does removing this requirement make your code less likely to break as we just saw, but it also makes it easier to write and maintain. Simply put:&lt;/p&gt;   &lt;pre class="code"&gt;Convert.ToInt32(ds.Tables[0].Rows[i]["userId"]);&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;is both hard to read and requires intimate knowledge of column names and their type. Ideally, your business layer knows nothing about the underlying database, the database schema, or SQL. If you are using &lt;b&gt;DataSets&lt;/b&gt; as it is expressed in the previous code string (using &lt;b&gt;CodeBehind&lt;/b&gt; doesn't make anything better), you likely have a very thin business layer.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Weakly-Typed&lt;/h3&gt;   &lt;p&gt;&lt;b&gt;DataSets&lt;/b&gt; are weakly-typed, which makes them error prone and likely to impact your development effort. What this means is that whenever you retrieve a value from a &lt;b&gt;DataSet,&lt;/b&gt; it comes in the form of a &lt;b&gt;System.Object,&lt;/b&gt; which you have to convert. The risk you run is that a conversion will fail. Unfortunately, this failure won't happen at compile time, but rather at runtime. Additionally, tools such as Microsoft Visual Studio.NET (VS.NET) aren't very good at assisting your developers when it comes to weakly-typed objects. When we previously talked about requiring an in-depth knowledge of the schema, this is what was meant. Again, we'll look at a very common example:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic.NET&lt;br /&gt;Dim userId As Integer =&lt;br /&gt;?      Convert.ToInt32(ds.Tables(0).Rows(0)("UserId"))&lt;br /&gt;Dim userId As Integer = CInt(ds.Tables(0).Rows(0)("UserId"))&lt;br /&gt;Dim userId As Integer = CInt(ds.Tables(0).Rows(0)(0))&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;int userId = Convert.ToInt32(ds.Tables[0].Rows[0]("UserId"));&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;This code represents possible ways of retrieving a value from a &lt;b&gt;DataSet&lt;/b&gt;—chances are your code has this all over the place (if it doesn't do a conversion and you are using Visual Basic .NET, you might have Option Strict off, in which case you're in even deeper trouble).&lt;/p&gt;   &lt;p&gt;Unfortunately, each of those lines has the potential to generate numerous runtime errors:  &lt;/p&gt; &lt;ol&gt; &lt;li&gt;The conversion can fail because: &lt;ul type="disc"&gt;&lt;li&gt;The value could be null.&lt;/li&gt;&lt;li&gt;The developer might be wrong about the underlying data type (again, intimate knowledge of the database schema is required).&lt;/li&gt;&lt;li&gt;If you are using ordinal values, who knows what column is actually at position X.&lt;/li&gt;&lt;/ul&gt; &lt;/li&gt;&lt;li&gt;&lt;b&gt;ds.Tables(0)&lt;/b&gt; might return a null reference (if any part of the DAL method or the stored procedure failed).&lt;/li&gt;&lt;li&gt;"UserId" might not be a valid column name because: &lt;ul type="disc"&gt;&lt;li&gt;It might have changed names.&lt;/li&gt;&lt;li&gt;It might not be returned by the stored procedure.&lt;/li&gt;&lt;li&gt;It might have a typo.&lt;/li&gt;&lt;/ul&gt; &lt;/li&gt; &lt;/ol&gt;   &lt;p&gt;We could modify the code and write it more defensively, namely by adding checks for &lt;b&gt;null/nothing&lt;/b&gt; and adding &lt;b&gt;try/catch&lt;/b&gt; around the conversion, but this does nothing to help the developer.&lt;/p&gt;   &lt;p&gt;Worst of all is that, as we've discussed, this isn't abstracted. The significance of this is that, every time you want to get the &lt;b&gt;userId&lt;/b&gt; out of the &lt;b&gt;DataSet,&lt;/b&gt; you'll run the risks listed previously, or you'll need to reprogram the same defensive steps (granted, a utility function would help alleviate this). Weakly-typed objects moves errors from design time or compile time, where they are always automatically detected and easily fixed, to the run time, where they risk being exposed in production and are harder to pinpoint.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Not Object-Oriented&lt;/h3&gt;   &lt;p&gt;Just because &lt;b&gt;DataSets&lt;/b&gt; are objects and C# and Visual Basic .NET are object-oriented (OO) languages doesn't automatically make your usage of them object-oriented. The "hello world" of OO programming is typically a &lt;b&gt;Person&lt;/b&gt; class that is sub-classed by an &lt;b&gt;Employee&lt;/b&gt; class. &lt;b&gt;DataSets,&lt;/b&gt; however, don't make this type of inheritance, or most other OO techniques, possible (or at least natural/intuitive). Scott Hanselman, an outspoken proponent of class entities, explains it best:&lt;/p&gt;   &lt;blockquote class="dtBlock"&gt; "A DataSet is an object, right? But it's not a Domain Object, it's not an 'Apple' or 'Orange'—it's an object of type 'DataSet.' &lt;b&gt;A DataSet is a bowl&lt;/b&gt; (one that knows about the backing Data Store). A DataSet is an object that knows how to HOLD Rows and Columns. It's an object that knows a LOT about the Database. But I don't want to return bowls. I want to return Domain Objects, like 'Apples.'"&lt;sup&gt;1&lt;/sup&gt;&lt;/blockquote&gt;   &lt;p&gt;&lt;b&gt;DataSets&lt;/b&gt; keep your data in a relational format, making them powerful and easy to use with relational databases. Unfortunately, this means you lose out on all the benefits of OO. &lt;/p&gt;   &lt;p&gt;Since &lt;b&gt;DataSets&lt;/b&gt; can't act as domain objects, it's impossible to add functionality to them. Typically, objects have fields, properties, and methods, which behave against an instance of the class. For example, you might have &lt;b&gt;Promote&lt;/b&gt; or &lt;b&gt;CalcuateOvertimePay&lt;/b&gt; functions associated with a &lt;b&gt;User&lt;/b&gt; object, which can be cleanly called through &lt;b&gt;someUser.Promote()&lt;/b&gt; or &lt;b&gt;someUser.CalculateOverTimePay().&lt;/b&gt; Since methods can't be added to a &lt;b&gt;DataSet&lt;/b&gt; you'll need to use utility functions, deal with weakly-typed objects, and have more instances of hard-coded values spread throughout your code. You basically end up with procedural code where you either continuously keep getting data out of the &lt;b&gt;DataSet,&lt;/b&gt; or cumbersomely store them in local variables and pass them around. Both methods have their disadvantages and neither has advantages.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;The Case Against DataSet&lt;/h3&gt;   &lt;p&gt;If your idea of a Data Access Layer is to return a &lt;b&gt;DataSet,&lt;/b&gt; you are likely missing out on some significant benefits. One reason for this is that you may be using a thin or non-existent business layer that, amongst other things, limits your ability to abstract. Additionally, it's difficult to take advantage of OO techniques, since you are using a generic pre-built solution. Finally, tools such as Visual Studio.NET can't easily empower developers with weakly-typed objects, such as &lt;b&gt;DataSets,&lt;/b&gt; which reduces productivity while increasing the likelihood of bugs.&lt;/p&gt;   &lt;p&gt;All of these factors have a direct impact on the maintainability of your code in one way or another. The lack of abstraction makes feature changes and bug fixes more involved and risky. You aren't able to take full advantage of the code reuse or the boost in readability offered by OO. And, of course, your developers, whether they work on the business logic or the presentation logic, must have intimate knowledge of your underlying data structure.&lt;/p&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic3"&gt;&lt;/a&gt;Custom Entity Classes&lt;/h2&gt;   &lt;p&gt;Most of the problems associated with &lt;b&gt;DataSets&lt;/b&gt; can be solved by taking advantage of the rich capabilities of OO programming within a well-defined business layer. In essence we want to take relationally organized data (database) and have it available as objects (code). The idea being that instead of having a &lt;b&gt;DataTable&lt;/b&gt; that holds information about cars, you actually have car objects (called custom entities or domain objects). &lt;/p&gt;   &lt;p&gt;Before we look at custom entities we'll first look at the challenges that we'll face. The most obvious is the amount of code required. Instead of simply getting the data and automatically filling a &lt;b&gt;DataSet&lt;/b&gt;, we get the data and manually map it to the custom entities that must first be created. Seeing as this is a repetitive task, we can mitigate it using code generation tools or O/R mappers (more on this later). The bigger problem is the actual process of mapping data from the relational to the object world. For simple systems the mapping is mostly straightforward, but as the complexity grows the differences between the two worlds can become problematic. For example, a key technique to help code-reuse, as well as maintainability, in the object world is inheritance. Unfortunately, inheritance is a foreign concept to relational databases. Another example is the difference in dealing with relations, with the object world maintaining a reference to a separate object and the relational world making use of foreign keys.&lt;/p&gt;   &lt;p&gt;It might sound as if this approach isn't well suited for more complex systems as the amount of code along with the disparity between the relational data and objects grows, but the opposite is true. Complex systems gain from this approach by having their difficulties isolated in a single layer—the mapping process (which, again, can be automated). Additionally, this approach is already quite popular, which means a number of design patterns exist to cleanly deal with added complexity. Magnify the shortcomings of &lt;b&gt;DataSets&lt;/b&gt; previously discussed with that of a complex system and you'll end up with a system whose difficulty to build is only surpassed with its inability to change.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;What Are Custom Entities?&lt;/h3&gt;   &lt;p&gt;Custom entities are objects that represent your business domain; as such, they are the foundation of a business layer. If you have a user authentication component (the example we'll be using throughout this guide), you'll likely have &lt;b&gt;User&lt;/b&gt; and &lt;b&gt;Role&lt;/b&gt; objects. An e-commerce system would likely have &lt;b&gt;Supplier&lt;/b&gt; and &lt;b&gt;Merchandise&lt;/b&gt; objects and a real estate company might have &lt;b&gt;Houses,&lt;/b&gt; &lt;b&gt;Rooms,&lt;/b&gt; and &lt;b&gt;Addresses&lt;/b&gt;. Within your code, custom entities are simply classes (there's a fairly tight correlation between an entity and a &lt;i&gt;class, &lt;/i&gt;as it's used in OO programming). A typical &lt;b&gt;User&lt;/b&gt; class might look like:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Class User&lt;br /&gt;#Region "Fields and Properties"&lt;br /&gt;Private _userId As Integer&lt;br /&gt;Private _userName As String&lt;br /&gt;Private _password As String&lt;br /&gt;Public Property UserId() As Integer&lt;br /&gt; Get&lt;br /&gt;  Return _userId&lt;br /&gt; End Get&lt;br /&gt; Set(ByVal Value As Integer)&lt;br /&gt;   _userId = Value&lt;br /&gt; End Set&lt;br /&gt;End Property&lt;br /&gt;Public Property UserName() As String&lt;br /&gt; Get&lt;br /&gt;  Return _userName&lt;br /&gt; End Get&lt;br /&gt; Set(ByVal Value As String)&lt;br /&gt;  _userName = Value&lt;br /&gt; End Set&lt;br /&gt;End Property&lt;br /&gt;Public Property Password() As String&lt;br /&gt; Get&lt;br /&gt;  Return _password&lt;br /&gt; End Get&lt;br /&gt; Set(ByVal Value As String)&lt;br /&gt;  _password = Value&lt;br /&gt; End Set&lt;br /&gt;End Property&lt;br /&gt;#End Region&lt;br /&gt;#Region "Constructors"&lt;br /&gt;Public Sub New()&lt;br /&gt;End Sub&lt;br /&gt;Public Sub New(id As Integer, name As String, password As String)&lt;br /&gt; Me.UserId = id&lt;br /&gt; Me.UserName = name&lt;br /&gt; Me.Password = password&lt;br /&gt;End Sub&lt;br /&gt;#End Region&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public class User {&lt;br /&gt;#region "Fields and Properties"&lt;br /&gt;private int userId;&lt;br /&gt;private string userName;&lt;br /&gt;private string password;&lt;br /&gt;public int UserId {&lt;br /&gt; get { return userId; }&lt;br /&gt; set { userId = value; }&lt;br /&gt; }&lt;br /&gt;public string UserName {&lt;br /&gt; get { return userName; }&lt;br /&gt; set { userName = value; }&lt;br /&gt;}&lt;br /&gt;public string Password {&lt;br /&gt; get { return password; }&lt;br /&gt; set { password = value; }&lt;br /&gt;}&lt;br /&gt;#endregion&lt;br /&gt;#region "Constructors"&lt;br /&gt;public User() {}&lt;br /&gt;public User(int id, string name, string password) {&lt;br /&gt; this.UserId = id;&lt;br /&gt; this.UserName = name;&lt;br /&gt; this.Password = password;&lt;br /&gt;}&lt;br /&gt;#endregion&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;h3 class="dtH1"&gt;Why Are They Beneficial?&lt;/h3&gt;   &lt;p&gt;The primary benefit gained from using custom entities comes from the simple fact that they are objects fully in your control. Namely, they allow you to: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Take advantage of OO techniques such as inheritance and encapsulation.&lt;/li&gt;&lt;li&gt;Add custom behavior.&lt;/li&gt; &lt;/ul&gt;   &lt;p&gt;For example, our &lt;b&gt;User&lt;/b&gt; class could benefit from having an &lt;b&gt;UpdatePassword&lt;/b&gt; function added to it (this is something we could do with datasets using external/utility functions, but at a readability/maintenance cost). Additionally, they are strongly-typed, meaning we get IntelliSense support:&lt;/p&gt;   &lt;p class="fig"&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/entity_fig01.gif" alt="" border="0" /&gt;&lt;/p&gt;   &lt;p class="label"&gt;&lt;b&gt;Figure 1. IntelliSense with the User class&lt;/b&gt;&lt;/p&gt;   &lt;p&gt;Finally, since custom entities are strongly-typed, they require less error-prone casts:&lt;/p&gt;   &lt;pre class="code"&gt;Dim userId As Integer = user.UserId&lt;br /&gt;'versus&lt;br /&gt;Dim userId As Integer =&lt;br /&gt;?         Convert.ToInt32(ds.Tables("users").Rows(0)("UserId"))&lt;br /&gt;&lt;/pre&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic4"&gt;&lt;/a&gt;Object-Relational Mapping&lt;/h2&gt;   &lt;p&gt;As discussed earlier, one of the main challenges of this approach is dealing with the differences between relational data and objects. Since our data is persistently stored in a relational database we have no choice but to bridge the two worlds. For the previous &lt;b&gt;User&lt;/b&gt; example we could expect to have a user table in our database that looks a lot like:&lt;/p&gt;   &lt;p class="fig"&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/entity_fig02.gif" alt="" border="0" /&gt;&lt;/p&gt;   &lt;p class="label"&gt;&lt;b&gt;Figure 2. Data view of the User&lt;/b&gt;&lt;/p&gt;   &lt;p&gt;Mapping from this relational schema to our custom entity is a simple enough matter:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function GetUser(ByVal userId As Integer) As User&lt;br /&gt;Dim connection As New SqlConnection(CONNECTION_STRING)&lt;br /&gt;Dim command As New SqlCommand("GetUserById", connection)&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId&lt;br /&gt;Dim dr As SqlDataReader = Nothing&lt;br /&gt;Try&lt;br /&gt; connection.Open()&lt;br /&gt; dr = command.ExecuteReader(CommandBehavior.SingleRow)&lt;br /&gt; If dr.Read Then&lt;br /&gt;  Dim user As New User&lt;br /&gt;  user.UserId = Convert.ToInt32(dr("UserId"))&lt;br /&gt;  user.UserName = Convert.ToString(dr("UserName"))&lt;br /&gt;  user.Password = Convert.ToString(dr("Password"))&lt;br /&gt;  Return user&lt;br /&gt; End If&lt;br /&gt; Return Nothing&lt;br /&gt;Finally&lt;br /&gt; If Not dr is Nothing AndAlso Not dr.IsClosed Then&lt;br /&gt;  dr.Close()&lt;br /&gt; End If&lt;br /&gt; connection.Dispose()&lt;br /&gt; command.Dispose()&lt;br /&gt; End Try&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public User GetUser(int userId) {&lt;br /&gt;SqlConnection connection = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;SqlCommand command = new SqlCommand("GetUserById", connection);&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId;&lt;br /&gt;SqlDataReader dr = null;&lt;br /&gt;try{&lt;br /&gt; connection.Open();&lt;br /&gt; dr = command.ExecuteReader(CommandBehavior.SingleRow);&lt;br /&gt; if (dr.Read()){&lt;br /&gt;  User user = new User();&lt;br /&gt;  user.UserId = Convert.ToInt32(dr["UserId"]);&lt;br /&gt;  user.UserName = Convert.ToString(dr["UserName"]);&lt;br /&gt;  user.Password = Convert.ToString(dr["Password"]);&lt;br /&gt;  return user;           &lt;br /&gt; }&lt;br /&gt; return null;&lt;br /&gt;}finally{&lt;br /&gt; if (dr != null &amp;&amp;amp; !dr.IsClosed){&lt;br /&gt;  dr.Close();&lt;br /&gt; }&lt;br /&gt; connection.Dispose();&lt;br /&gt; command.Dispose();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;We still set up our connection and command objects like we normally would, but then we create a new instance of our &lt;b&gt;User&lt;/b&gt; class and populate it from our &lt;b&gt;DataReader.&lt;/b&gt; You could still use a &lt;b&gt;DataSet&lt;/b&gt; within this function and map it to your custom entity, but the primary benefit of &lt;b&gt;DataSets&lt;/b&gt; over &lt;b&gt;DataReader&lt;/b&gt; is that they provide a disconnected view of the data. In this case the &lt;b&gt;User&lt;/b&gt; instance provides that disconnected view, letting us take advantage of the &lt;b&gt;DataReader&lt;/b&gt;'s speed.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Wait a Minute! You Didn't Solve Anything!&lt;/h3&gt;   &lt;p&gt;Observant readers might notice that one of the problems I pointed out with &lt;b&gt;DataSets&lt;/b&gt; is that they aren't strongly-typed, which leads to a loss of productivity and an increase in the potential for runtime errors. They also require developers to have an in-depth knowledge of the underlying data structure. Looking at the previous code you might notice the exact same pitfalls lurking. Consider, however, that we have encapsulated these problems within a very isolated area of the code; meaning consumers of your class entities (web interface, web service consumer, windows form) remain totally unaware of these problems. Conversely, using &lt;b&gt;DataSets&lt;/b&gt; spreads these problems throughout the code.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Enhancement&lt;/h3&gt;   &lt;p&gt;The previous code was useful to show the basic idea behind mapping, but two key enhancements can be done to improve it. First we want to extract the populate code into its own function, as it'll likely be reused:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function PopulateUser(ByVal dr As IDataRecord) As User&lt;br /&gt;Dim user As New User&lt;br /&gt;user.UserId = Convert.ToInt32(dr("UserId"))&lt;br /&gt;'example of checking for NULL&lt;br /&gt;If Not dr("UserName") Is DBNull.Value Then&lt;br /&gt; user.UserName = Convert.ToString(dr("UserName"))&lt;br /&gt;End If&lt;br /&gt;user.Password = Convert.ToString(dr("Password"))&lt;br /&gt;Return user&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public User PopulateUser(IDataRecord dr) {&lt;br /&gt;User user = new User();&lt;br /&gt;user.UserId = Convert.ToInt32(dr["UserId"]);&lt;br /&gt;//example of checking for NULL&lt;br /&gt;if (dr["UserName"] != DBNull.Value){&lt;br /&gt; user.UserName = Convert.ToString(dr["UserName"]);  &lt;br /&gt;}&lt;br /&gt;user.Password = Convert.ToString(dr["Password"]);&lt;br /&gt;return user;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;The second thing to notice is that instead of using a &lt;b&gt;SqlDataReader&lt;/b&gt; for our mapping function, we use an &lt;b&gt;IDataRecord.&lt;/b&gt; This is an interface that all &lt;b&gt;DataReaders&lt;/b&gt; implement. Using &lt;b&gt;IDataRecord&lt;/b&gt; makes our mapping process vendor-independent. In other words, we can use the previous function to map a &lt;b&gt;User&lt;/b&gt; from an Access database, even if it uses an &lt;b&gt;OleDbDataReader.&lt;/b&gt; If you combine this specific approach with the Provider Model Design Pattern (&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnet/html/asp02182004.asp"&gt;link 1&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspnet/html/asp04212004.asp"&gt;link 2&lt;/a&gt;), you'll have code that can be easily used for different database vendors.&lt;/p&gt;   &lt;p&gt;Finally, the above code demonstrates how powerful encapsulation is. Dealing with &lt;b&gt;NULLs&lt;/b&gt; in &lt;b&gt;DataSets&lt;/b&gt; isn't the easiest thing—that's because every time you pull a value you need to check if it's &lt;b&gt;NULL.&lt;/b&gt; With the above population method we've conveniently taken care of this in a single place, and spared our consumers from having to deal with it.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Where to Map?&lt;/h3&gt;   &lt;p&gt;There is some debate about where such data access and mapping function belongs—as part of a separate class or as part of the appropriate custom entity. There's certainly a nice elegance to having all user-related tasks (fetching data, updating, and mapping) as part of the &lt;b&gt;User&lt;/b&gt; custom entity. This tends to work well when the database schema closely resembles the custom entity (as in this example). As your system grows in complexity and the differences between the two worlds start to appear, having a clear separation between your data layer and business layer can greatly help simplify maintenance (I like to call this the Data Access Layer). A side-effect from having the access and mapping code inside its own layer, the DAL, is that it provides us with a nice rule for ensuring a clear separation of our layers:&lt;/p&gt;   &lt;blockquote class="dtBlock"&gt; &lt;b&gt;"Never return a class from the System.Data or child namespace from the DAL"&lt;/b&gt;&lt;/blockquote&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic5"&gt;&lt;/a&gt;Custom Collections&lt;/h2&gt;   &lt;p&gt;So far we've only looked at dealing with individual entities; however, you'll often need to deal with more than a single object. A simple solution would be to store multiple values inside a generic collection, such as an &lt;b&gt;Arraylist.&lt;/b&gt; This is a less than ideal solution, as it reintroduces some of the problems we had with &lt;b&gt;DataSets&lt;/b&gt;, namely:  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;They aren't strongly-typed, and&lt;/li&gt;&lt;li&gt;Custom behavior can't be added. &lt;/li&gt; &lt;/ul&gt;   &lt;p&gt;The solution that best fits our needs is to create our own custom collection. Thankfully the Microsoft .NET Framework provides a class specifically meant to be inherited for this purpose: &lt;b&gt;CollectionBase.&lt;/b&gt; &lt;b&gt;CollectionBase&lt;/b&gt; works by storing any type of object inside private &lt;b&gt;Arraylists&lt;/b&gt;, but exposing access to these private collections through methods that only take a specific type, such as a &lt;b&gt;User&lt;/b&gt; object. In other words, weakly-typed code is encapsulated within a strongly-typed API.&lt;/p&gt;   &lt;p&gt;While custom collections might seem like a lot of code, most of it is code generation or cut and paste friendly, oftentimes requiring only one search and replace. Let's take a look at the different parts that make up a custom collection for our &lt;b&gt;User&lt;/b&gt; class:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Class UserCollection&lt;br /&gt;  Inherits CollectionBase&lt;br /&gt;Default Public Property Item(ByVal index As Integer) As User&lt;br /&gt; Get&lt;br /&gt;  Return CType(List(index), User)&lt;br /&gt; End Get&lt;br /&gt; Set&lt;br /&gt;  List(index) = value&lt;br /&gt; End Set&lt;br /&gt;End Property&lt;br /&gt;Public Function Add(ByVal value As User) As Integer&lt;br /&gt; Return (List.Add(value))&lt;br /&gt;End Function&lt;br /&gt;Public Function IndexOf(ByVal value As User) As Integer&lt;br /&gt; Return (List.IndexOf(value))&lt;br /&gt;End Function&lt;br /&gt;Public Sub Insert(ByVal index As Integer, ByVal value As User)&lt;br /&gt; List.Insert(index, value)&lt;br /&gt;End Sub&lt;br /&gt;Public Sub Remove(ByVal value As User)&lt;br /&gt; List.Remove(value)&lt;br /&gt;End Sub&lt;br /&gt;Public Function Contains(ByVal value As User) As Boolean&lt;br /&gt; Return (List.Contains(value))&lt;br /&gt;End Function&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public class UserCollection : CollectionBase {&lt;br /&gt;public User this[int index] {&lt;br /&gt; get {return (User)List[index];}&lt;br /&gt; set {List[index] = value;}&lt;br /&gt;}&lt;br /&gt;public int Add(User value) {&lt;br /&gt; return (List.Add(value));&lt;br /&gt;}&lt;br /&gt;public int IndexOf(User value) {&lt;br /&gt; return (List.IndexOf(value));&lt;br /&gt;}&lt;br /&gt;public void Insert(int index, User value) {&lt;br /&gt; List.Insert(index, value);&lt;br /&gt;}&lt;br /&gt;public void Remove(User value) {&lt;br /&gt; List.Remove(value);&lt;br /&gt;}&lt;br /&gt;public bool Contains(User value) {&lt;br /&gt; return (List.Contains(value));&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;More can be done by implementing &lt;b&gt;CollectionBase,&lt;/b&gt; but the previous code represents the core functionality that is necessary for a custom collection. Looking at the &lt;b&gt;Add&lt;/b&gt; function, we can see how we are simply wrapping the call to &lt;b&gt;List.Add&lt;/b&gt; (which is an &lt;b&gt;Arraylist&lt;/b&gt;) in a function that only allows a &lt;b&gt;User&lt;/b&gt; object.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Mapping Custom Collections&lt;/h3&gt;   &lt;p&gt;The process of mapping our relational data to custom collections is very similar to the one we examined for custom entities. Instead of creating a single entity and returning it, we add the entity to the collection and loop to the next one:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function GetAllUsers() As UserCollection&lt;br /&gt;Dim connection As New SqlConnection(CONNECTION_STRING)&lt;br /&gt;Dim command As New SqlCommand("GetAllUsers", connection)&lt;br /&gt;Dim dr As SqlDataReader = Nothing&lt;br /&gt;Try&lt;br /&gt; connection.Open()&lt;br /&gt; dr = command.ExecuteReader(CommandBehavior.SingleResult)&lt;br /&gt; Dim users As New UserCollection&lt;br /&gt; While dr.Read()&lt;br /&gt;  users.Add(PopulateUser(dr))&lt;br /&gt; End While&lt;br /&gt; Return users&lt;br /&gt;Finally&lt;br /&gt; If Not dr Is Nothing AndAlso Not dr.IsClosed Then&lt;br /&gt;  dr.Close()&lt;br /&gt; End If&lt;br /&gt; connection.Dispose()&lt;br /&gt; command.Dispose()&lt;br /&gt;End Try&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public UserCollection GetAllUsers() {&lt;br /&gt;SqlConnection connection = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;SqlCommand command =new SqlCommand("GetAllUsers", connection);&lt;br /&gt;SqlDataReader dr = null;&lt;br /&gt;try{&lt;br /&gt; connection.Open();&lt;br /&gt; dr = command.ExecuteReader(CommandBehavior.SingleResult);&lt;br /&gt; UserCollection users = new UserCollection();&lt;br /&gt; while (dr.Read()){&lt;br /&gt;  users.Add(PopulateUser(dr));&lt;br /&gt; }&lt;br /&gt; return users;&lt;br /&gt;}finally{&lt;br /&gt; if (dr != null &amp;&amp;amp; !dr.IsClosed){&lt;br /&gt;  dr.Close();&lt;br /&gt; }&lt;br /&gt; connection.Dispose();&lt;br /&gt; command.Dispose();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;We get the data from the database, create our custom collection, and loop through the results to create each &lt;b&gt;User&lt;/b&gt; object and add it into the collection. Notice also how the &lt;b&gt;PopulateUser&lt;/b&gt; mapping function is reused.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Adding Custom Behavior&lt;/h3&gt;   &lt;p&gt;When talking about custom entities we only peripherally mentioned the ability to add custom behavior to our classes. The type of functionality that you'll be adding to your entities will mostly depend on the type of business logic you are implementing, but there is probably some common functionality you'll want to implement in your custom collections. One such example would be to return a single entity based on some key, for example a user based on a &lt;b&gt;userId:&lt;/b&gt;&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function FindUserById(ByVal userId As Integer) As User&lt;br /&gt;For Each user As User In List&lt;br /&gt; If user.UserId = userId Then&lt;br /&gt;  Return user&lt;br /&gt; End If&lt;br /&gt;Next&lt;br /&gt;Return Nothing&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public User FindUserById(int userId) {&lt;br /&gt;foreach (User user in List) {&lt;br /&gt; if (user.UserId == userId){&lt;br /&gt;  return user;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;return null;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Another one might be to return a subset of users based on certain criteria, such as a partial user name:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function FindMatchingUsers(ByVal search As String) As UserCollection&lt;br /&gt;If search Is Nothing Then&lt;br /&gt; Throw New ArgumentNullException("search cannot be null")&lt;br /&gt;End If&lt;br /&gt;Dim matchingUsers As New UserCollection&lt;br /&gt;For Each user As User In List&lt;br /&gt; Dim userName As String = user.UserName&lt;br /&gt; If Not userName Is Nothing And userName.StartsWith(search) Then&lt;br /&gt;  matchingUsers.Add(user)&lt;br /&gt; End If&lt;br /&gt;Next&lt;br /&gt;Return matchingUsers&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public UserCollection FindMatchingUsers(string search) {&lt;br /&gt;if (search == null){&lt;br /&gt; throw new ArgumentNullException("search cannot be null");&lt;br /&gt;}&lt;br /&gt;UserCollection matchingUsers = new UserCollection();&lt;br /&gt;foreach (User user in List) {&lt;br /&gt; string userName = user.UserName;&lt;br /&gt; if (userName != null &amp;&amp;amp; userName.StartsWith(search)){&lt;br /&gt;  matchingUsers.Add(user);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;return matchingUsers;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Using &lt;b&gt;DataSets&lt;/b&gt; the same way can be achieved with &lt;b&gt;DataTable.Select.&lt;/b&gt; It is important to note that while creating your own functionality puts you in absolute control of your code, the &lt;b&gt;Select&lt;/b&gt; method provides a very convenient and code-free means of doing the same thing. On the flip side, &lt;b&gt;Select&lt;/b&gt; requires developers to know the underlying database and isn't strongly-typed.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Binding Custom Collections&lt;/h3&gt;   &lt;p&gt;The first example we looked at was that of binding a &lt;b&gt;DataSet&lt;/b&gt; to an ASP.NET control. Considering how common this is, you'll be glad to know that custom collections bind just as easily (this is because &lt;b&gt;CollectionBase&lt;/b&gt; implements &lt;b&gt;Ilist,&lt;/b&gt; which is used for binding). Custom collections can serve as the &lt;b&gt;DataSource&lt;/b&gt; for any control that exposes it, and &lt;b&gt;DataBinder.Eval&lt;/b&gt; can be used just as you would a &lt;b&gt;DataSet:&lt;/b&gt;&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Dim users as UserCollection = DAL.GetallUsers()&lt;br /&gt;repeater.DataSource = users&lt;br /&gt;repeater.DataBind()&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;UserCollection users = DAL.GetAllUsers();&lt;br /&gt;repeater.DataSource = users;&lt;br /&gt;repeater.DataBind();&lt;br /&gt;&lt;br /&gt;&lt;!-- HTML --&gt;&lt;br /&gt;&lt;asp:repeater onitemdatabound="r_IDB" id="repeater" runat="server"&gt;&lt;br /&gt;&lt;itemtemplate&gt;&lt;br /&gt; &lt;asp:label id="userName" runat="server"&gt;&lt;br /&gt;  &lt;%# DataBinder.Eval(Container.DataItem, "UserName") %&gt;&lt;br /&gt;&lt;br /&gt; &lt;/asp:Label&gt;&lt;br /&gt;&lt;/itemtemplate&gt;&lt;br /&gt;&lt;/asp:Repeater&gt;&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Instead of using the column name as the second parameter for &lt;b&gt;DataBinder.Eval,&lt;/b&gt; you specify the property name you wish to display, in this case &lt;b&gt;UserName.&lt;/b&gt;&lt;/p&gt;   &lt;p&gt;For those doing processing in the &lt;b&gt;OnItemDataBound&lt;/b&gt; or &lt;b&gt;OnItemCreated&lt;/b&gt; exposed by many data bound controls, you are probably casting &lt;b&gt;e.Item.DataItem&lt;/b&gt; to &lt;b&gt;DataRowView.&lt;/b&gt; When binding to a custom collection, &lt;b&gt;e.Item.DataItem&lt;/b&gt; is instead cast to the custom entity; in our example, the &lt;b&gt;User&lt;/b&gt; class:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Protected Sub r_ItemDataBound (s As Object, e As RepeaterItemEventArgs)&lt;br /&gt;Dim type As ListItemType = e.Item.ItemType&lt;br /&gt;If type = ListItemType.AlternatingItem OrElse&lt;br /&gt;?   type = ListItemType.Item Then&lt;br /&gt; Dim u As Label = CType(e.Item.FindControl("userName"), Label)&lt;br /&gt; &lt;b&gt;Dim currentUser As User = CType(e.Item.DataItem, User)&lt;/b&gt;&lt;br /&gt; If Not PasswordUtility.PasswordIsSecure(currentUser.Password) Then&lt;br /&gt;  ul.ForeColor = Drawing.Color.Red&lt;br /&gt; End If&lt;br /&gt;End If&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;protected void r_ItemDataBound(object sender, RepeaterItemEventArgs e) {&lt;br /&gt;ListItemType type = e.Item.ItemType;&lt;br /&gt;if (type == ListItemType.AlternatingItem ||&lt;br /&gt;?    type == ListItemType.Item){&lt;br /&gt; Label ul = (Label)e.Item.FindControl("userName");&lt;br /&gt;&lt;b&gt; User currentUser = (User)e.Item.DataItem;&lt;/b&gt;&lt;br /&gt; if (!PasswordUtility.PasswordIsSecure(currentUser.Password)){&lt;br /&gt;  ul.ForeColor = Color.Red;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic6"&gt;&lt;/a&gt;Managing Relationships&lt;/h2&gt;   &lt;p&gt;Within even the simplest system, relationships between entities will exist. With relational databases, relationships are maintained by means of foreign keys; using objects, a relationship is simply a reference to another object. For example, building on our previous examples, it's reasonable to expect a &lt;b&gt;User&lt;/b&gt; object to have a &lt;b&gt;Role:&lt;/b&gt;&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Class User&lt;br /&gt;Private _role As Role&lt;br /&gt;Public Property Role() As Role&lt;br /&gt; Get&lt;br /&gt;  Return _role&lt;br /&gt; End Get&lt;br /&gt; Set(ByVal Value As Role)&lt;br /&gt;  _role = Value&lt;br /&gt; End Set&lt;br /&gt;End Property&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public class User {&lt;br /&gt;private Role role;&lt;br /&gt;public Role Role {&lt;br /&gt; get {return role;}&lt;br /&gt; set {role = value;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Or a collection of &lt;b&gt;Role&lt;/b&gt;s:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Class User&lt;br /&gt;Private _roles As RoleCollection&lt;br /&gt;Public ReadOnly Property Roles() As RoleCollection&lt;br /&gt; Get&lt;br /&gt;  If _roles Is Nothing Then&lt;br /&gt;   _roles = New RoleCollection&lt;br /&gt;  End If&lt;br /&gt;  Return _roles&lt;br /&gt; End Get&lt;br /&gt;End Property&lt;br /&gt;End Class&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public class User {&lt;br /&gt;private RoleCollection roles;&lt;br /&gt;public RoleCollection Roles {&lt;br /&gt; get {&lt;br /&gt;  if (roles == null){&lt;br /&gt;   roles = new RoleCollection();&lt;br /&gt;  }&lt;br /&gt;  return roles;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;In these two examples, we have a fictitious &lt;b&gt;Role&lt;/b&gt; class or &lt;b&gt;RoleCollection&lt;/b&gt; class, which are just other custom entity or collection classes like the &lt;b&gt;User&lt;/b&gt; and &lt;b&gt;UserCollection&lt;/b&gt; classes.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Mapping Relationships&lt;/h3&gt;   &lt;p&gt;The real issue is how to map relationships. Let's look at a simple example; we want to retrieve a user based on &lt;b&gt;userId&lt;/b&gt; along with his or her roles. First, we'll look at the relational model:&lt;/p&gt;   &lt;p class="fig"&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnaspp/html/entity_fig03.gif" alt="" border="0" /&gt;&lt;/p&gt;   &lt;p class="label"&gt;&lt;b&gt;Figure 3. Relationships between Users and Roles&lt;/b&gt;&lt;/p&gt;   &lt;p&gt;Here we see a &lt;b&gt;Users&lt;/b&gt; table and a &lt;b&gt;Roles&lt;/b&gt; table, both of which we can map in a straightforward manner to custom entities. We also have a &lt;b&gt;UserRoleJoin&lt;/b&gt; table, which represents the many-to-many relationship between &lt;b&gt;Users&lt;/b&gt; and &lt;b&gt;Roles.&lt;/b&gt; &lt;/p&gt;   &lt;p&gt;Next we use a stored procedure to pull two separate results: the first for the &lt;b&gt;User,&lt;/b&gt; and the second for his or her &lt;b&gt;Role(s):&lt;/b&gt;&lt;/p&gt;   &lt;pre class="code"&gt;CREATE PROCEDURE GetUserById(&lt;br /&gt; @UserId INT&lt;br /&gt;)AS&lt;br /&gt;SELECT UserId, UserName, [Password]&lt;br /&gt; FROM Users&lt;br /&gt; WHERE UserId = @UserID&lt;br /&gt;SELECT R.RoleId, R.[Name], R.Code&lt;br /&gt; FROM Roles R INNER JOIN&lt;br /&gt;    UserRoleJoin URJ ON R.RoleId = URJ.RoleId&lt;br /&gt; WHERE  URJ.UserId = @UserId&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Finally, we map from the relational model to the object model:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public Function GetUserById(ByVal userId As Integer) As User&lt;br /&gt;Dim connection As New SqlConnection(CONNECTION_STRING)&lt;br /&gt;Dim command As New SqlCommand("GetUserById", connection)&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId&lt;br /&gt;Dim dr As SqlDataReader = Nothing&lt;br /&gt;Try&lt;br /&gt; connection.Open()&lt;br /&gt; dr = command.ExecuteReader()&lt;br /&gt; Dim user As User = Nothing&lt;br /&gt; If dr.Read() Then&lt;br /&gt;  user = PopulateUser(dr)&lt;br /&gt;  dr.NextResult()&lt;br /&gt;  While dr.Read()&lt;br /&gt;   user.Roles.Add(PopulateRole(dr))&lt;br /&gt;  End While&lt;br /&gt; End If&lt;br /&gt; Return user&lt;br /&gt;Finally&lt;br /&gt; If Not dr Is Nothing AndAlso Not dr.IsClosed Then&lt;br /&gt;  dr.Close()&lt;br /&gt; End If&lt;br /&gt; connection.Dispose()&lt;br /&gt; command.Dispose()&lt;br /&gt;End Try&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public User GetUserById(int userId) {&lt;br /&gt;SqlConnection connection = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;SqlCommand command = new SqlCommand("GetUserById", connection);&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId;&lt;br /&gt;SqlDataReader dr = null;&lt;br /&gt;try{&lt;br /&gt; connection.Open();&lt;br /&gt; dr = command.ExecuteReader();&lt;br /&gt; User user = null;&lt;br /&gt; if (dr.Read()){&lt;br /&gt;  user = PopulateUser(dr);&lt;br /&gt;  dr.NextResult();&lt;br /&gt;  while(dr.Read()){&lt;br /&gt;   user.Roles.Add(PopulateRole(dr));&lt;br /&gt;  }           &lt;br /&gt; }&lt;br /&gt; return user;&lt;br /&gt;}finally{&lt;br /&gt; if (dr != null &amp;&amp;amp; !dr.IsClosed){&lt;br /&gt;  dr.Close();&lt;br /&gt; }&lt;br /&gt; connection.Dispose();&lt;br /&gt; command.Dispose();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;The &lt;b&gt;User&lt;/b&gt; instance is created and populated; we move to the next result/select and loop through, populating &lt;b&gt;Roles&lt;/b&gt; and adding them to the &lt;b&gt;RolesCollection&lt;/b&gt; property of the &lt;b&gt;User&lt;/b&gt; class.&lt;/p&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic7"&gt;&lt;/a&gt;Beyond the Basics&lt;/h2&gt;   &lt;p&gt;The purpose of this guide was to introduce the concept and usage of custom entities and collections. Using custom entities is a widely used practice in the industry, and as such numerous patterns have been documented to deal with a wide range of scenarios. Design patterns are great for a number of reasons. First, when it comes to addressing specific situations, chances are you aren't the first to face a given problem. Design patterns let you reuse a tried and tested solution to a given problem (design patterns aren't meant to be 100% cut and paste, but they almost always provide a sound foundation to a solution). This in turn provides you with confidence that your system will scale well with complexity, not only because it's a widely used approach but also because it's a well documented one. Design patterns also provide you with a common vocabulary, which can make knowledge transfer and training much easier.&lt;/p&gt;   &lt;p&gt;There's nothing to say that design patterns only apply to custom entities, and in fact many don't. However, if you give them a chance you'll likely be pleasantly surprised at how many well documented patterns do apply to custom entities and the mapping process.&lt;/p&gt;   &lt;p&gt;This last section is dedicated to pointing out some more advanced scenarios that larger or more complex systems will likely run into. While most of the topics are probably worthy of individual guides, I'll, at the very least, try to provide you with some starting resources.&lt;/p&gt;   &lt;p&gt;A great place to start is Martin Fowler's &lt;a href="http://martinfowler.com/books.html"&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;, which won't only serve as a great reference (with detailed explanations and plenty of sample code) for common design patterns, but the first 100 pages will really get your mind wrapped around the whole concept. Alternatively, Fowler has an online &lt;a href="http://martinfowler.com/eaaCatalog/"&gt;catalog of patterns&lt;/a&gt;, which is great for those who are already familiar with the concepts but need a handy reference.&lt;/p&gt;   &lt;h3 class="dtH1"&gt;Concurrency&lt;/h3&gt;   &lt;p&gt;The previous examples all dealt with pulling data from the database and creating objects from that data. For the most part, updating, deleting, and inserting data is just as straightforward. Our business layer creates an object, passes it to our Data Access Layer, and lets it handle the mapping to the relational world. For example:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Public sub UpdateUser(ByVal user As User)&lt;br /&gt;Dim connection As New SqlConnection(CONNECTION_STRING)&lt;br /&gt;Dim command As New SqlCommand("UpdateUser", connection)&lt;br /&gt;'could have a reusable function to inversly map this&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int)&lt;br /&gt;command.Parameters(0).Value = user.UserId&lt;br /&gt;command.Parameters.Add("@Password", SqlDbType.VarChar, 64)&lt;br /&gt;command.Parameters(1).Value = user.Password&lt;br /&gt;command.Parameters.Add("@UserName", SqlDbType.VarChar, 128)&lt;br /&gt;command.Parameters(2).Value = user.UserName&lt;br /&gt;Try&lt;br /&gt; connection.Open()&lt;br /&gt; command.ExecuteNonQuery()&lt;br /&gt;Finally&lt;br /&gt; connection.Dispose()&lt;br /&gt; command.Dispose()&lt;br /&gt;End Try&lt;br /&gt;End Sub&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;public void UpdateUser(User user) {&lt;br /&gt;SqlConnection connection = new SqlConnection(CONNECTION_STRING);&lt;br /&gt;SqlCommand command = new SqlCommand("UpdateUser", connection);&lt;br /&gt;//could have a reusable function to inversly map this&lt;br /&gt;command.Parameters.Add("@UserId", SqlDbType.Int);&lt;br /&gt;command.Parameters[0].Value = user.UserId;&lt;br /&gt;command.Parameters.Add("@Password", SqlDbType.VarChar, 64);&lt;br /&gt;command.Parameters[1].Value = user.Password;&lt;br /&gt;command.Parameters.Add("@UserName", SqlDbType.VarChar, 128);&lt;br /&gt;command.Parameters[2].Value = user.UserName;&lt;br /&gt;try{&lt;br /&gt; connection.Open();&lt;br /&gt; command.ExecuteNonQuery();&lt;br /&gt;}finally{&lt;br /&gt; connection.Dispose();&lt;br /&gt; command.Dispose();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;However, one area which isn't as straightforward is when dealing with concurrency—that is, what happens when two users try to update the same data at the same time? The default behavior (if you don't do anything) is that the last person to commit the data will overwrite all previous work. This probably isn't ideal, as one user's work will be silently overwritten. One way to totally avoid any conflicts is to use pessimistic concurrency; however, this method requires some type of locking mechanism, which can be difficult to implement in a scalable manner. The alternative is to use optimistic concurrency techniques. Letting the first commit dominate and notifying subsequent users is typically a gentler and more user-friendly approach to take. This is achieved by some type of row versioning, such as timestamps.&lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further reading:&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/vbcon/html/vbtskPerformingOptimisticConcurrencyChecking.asp"&gt;Introduction to Data Concurrency in ADO.NET&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.lhotka.net/Articles.aspx?id=890d3e3c-8a49-486c-ae48-a44e7e1f7844"&gt;CSLA.NET's concurrency techniques&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html"&gt;Unit of Work design pattern&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://martinfowler.com/eaaCatalog/optimisticOfflineLock.html"&gt;Optimistic offline lock design pattern&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://martinfowler.com/eaaCatalog/pessimisticOfflineLock.html"&gt;Pessimistic offline lock design pattern&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h3 class="dtH1"&gt;Performance&lt;/h3&gt;   &lt;p&gt;Too often we worry about minute performance differences as opposed to legitimate flexibility and capability concerns. While performance is indeed important, providing generalized guidelines on anything but the simplest situations is often difficult. Take, for example, custom collections versus &lt;b&gt;DataSets:&lt;/b&gt; which is faster? With custom collections you can make heavy use of &lt;b&gt;DataReaders,&lt;/b&gt; which is a faster way of pulling data from a database. The point, though, is that the answer really depends on how, and with what type of data, you use them, so a blanket statement is pretty useless. What's even more important to realize is that whatever processing time you are able to save probably doesn't amount to much compared to the difference in maintainability.&lt;/p&gt;   &lt;p&gt;Of course, no one said you couldn't have a high performance solution that is also maintainable. While I reiterate that it really depends on how you use them, there are some patterns that can help maximize performance. First, though, it's important to know that custom entities and collections cache as well as &lt;b&gt;DataSets&lt;/b&gt; and can make use of the same mechanism—likely &lt;b&gt;HttpCache.&lt;/b&gt; One nice thing about &lt;b&gt;DataSets&lt;/b&gt; is the ability to write a &lt;b&gt;Select&lt;/b&gt; statement to just grab the necessary information. With custom entities you often feel obliged to populate the entire entity as well as child entities. For example, if you want to display a list of &lt;b&gt;Organizations,&lt;/b&gt; with a &lt;b&gt;DataSet&lt;/b&gt; you might just pull the &lt;b&gt;OganizationId,&lt;/b&gt; &lt;b&gt;Name,&lt;/b&gt; and &lt;b&gt;Address&lt;/b&gt; and bind it to a repeater. With custom entities I always feel the need to also get all the other &lt;b&gt;Organization&lt;/b&gt; information, which might be a bit flag to say if it's ISO certified, a collection of all employees, additional contact information, and so on. Maybe others don't share this hang-up, but luckily we have, if we want, fine control over our custom entities. The most common approach is to use a type of lazy-load pattern, which only fetches the information when it's first required (which can be nicely encapsulated in a property). This type of control over individual properties provides tremendous flexibility otherwise not easily achieved (imagine trying to do something similar at the &lt;b&gt;DataColumn&lt;/b&gt; level).&lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further Reading:&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://martinfowler.com/eaaCatalog/lazyLoad.html"&gt;Lazy Load&lt;/a&gt; design pattern&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.lhotka.net/Articles.aspx?id=48548dc3-3b64-4bb3-bc84-9476b8f77600"&gt;CSLA.NET lazy load&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h3 class="dtH1"&gt;Sorting and Filtering&lt;/h3&gt;   &lt;p&gt;The &lt;b&gt;DataView&lt;/b&gt;'s built-in support for sorting and filtering, although requiring knowledge of both SQL and the underlying data structure, is a convenience that is somewhat lost with custom collections. We can still sort and filter, but to do so requires us to write the functionality. While the techniques aren't necessarily advanced, a full demonstration of code is outside the scope of this section. Most techniques are fairly similar, such as using a filter class to filter a collection and a comparer class for sorting, no patterns, that I'm aware of, really exist. A number of resources do exist, however: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.c-sharpcorner.com/Code/2002/June/CollectionObgOrdering.asp"&gt;Generic sort function&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://tim-price.net/blog/articles/171.aspx"&gt;Sorting &amp; Filtering Custom Collections&lt;/a&gt; tutorial&lt;/li&gt; &lt;/ul&gt;   &lt;h3 class="dtH1"&gt;Code Generation&lt;/h3&gt;   &lt;p&gt;Once you get past any conceptual roadblocks, the main drawback to custom entities and collections is the amount of additional code all this flexibility, abstraction, and low maintenance costs you. In fact, you might think that all my talk about reduced maintenance cost and bugs doesn't equate with extra code. While this is certainly a valid point (again, no solution is perfect), design patterns and frameworks such as CSLA.NET go a long way to alleviating the problem. While totally different from patterns and frameworks, code generation tools can reduce the amount of code you actually need to write by significant amounts. Initially this guide was going to have an entire section detailed to code-generation tools, in specific the popular and free CodeSmith; however, numerous resources exist that likely exceed my own knowledge of the product.&lt;/p&gt;   &lt;p&gt;Before I continue, I realize that code generation sounds like something of a dream. But when properly used and understood, it truly is a powerful arsenal in your bag of tools—even if you aren't doing custom entities. While it's true that code generation doesn't only apply to custom entities, many are specifically tailored for this purpose. The reason is simple: custom entities require a lot of repetitive code.&lt;/p&gt;   &lt;p&gt;Briefly, how does code generation work? The idea might sound far fetched or even counterproductive, but you basically write code (templates) to generate code. CodeSmith, for example, comes with powerful classes that let you hook into a database and get all the properties: tables, columns (types, sizes, and so on), and relations. Armed with this information, much of what we've talked about so far can be automated. For example, a developer could pick a table and automatically, with the right template, have a custom entity created (with the correct fields, properties, and constructors), a mapping function, a custom collection, and basic select, insert, update, and delete functionality. It could even go a step further and implement sorting, filtering, and the other advanced features we've touched on.&lt;/p&gt;   &lt;p&gt;CodeSmith also comes with many ready-to-use templates, which serve as a great learning resource. Finally, CodeSmith has a number of templates to implement the CSLA.NET framework. The couple of hours I initially took to learn the basics and get comfortable with CodeSmith have saved me untold time. Additionally, when all developers are using the same templates, the high level of consistency throughout your code makes it easy to work on somebody else's functions.&lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further readings:&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnhcvs04/html/vs04e5.asp"&gt;Code Generation with CodeSmith&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ericjsmith.com/codesmith/"&gt;CodeSmith homepage&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h3 class="dtH1"&gt;O/R Mappers&lt;/h3&gt;   &lt;p&gt;Even though my lack of experience with O/R mappers makes me cautious of talking about them, their potential value makes them impossible to ignore. Where code generators create code that is based on templates for you to copy and paste into your own source code, O/R mappers dynamically generates the code at runtime from some type of configuration mechanism. For example, within an XML file you could specify that column X of some table maps to property Y of an entity. You still create the custom entity, but collections, mappings, and other data access functions (including stored procedures) are all created dynamically. In theory, O/R mappers almost entirely mitigate the problems with custom entities. As the relational and object worlds diverge and the mapping process grows in complexity, O/R mappers become even more invaluable. Two of the downsides of O/R mappers are that they are perceived, in the .NET community at least, as being less secure and having poor performance. From what I've read, I'm convinced that they aren't any less secure, and while they might have poorer performance in some situations, they are probably superior in others. O/R mappers aren't suited for all situations, but if you are dealing with complex systems, you owe it to yourself to investigate them.&lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further Reading&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.martinfowler.com/eaaCatalog/mapper.html"&gt;Mapper&lt;/a&gt; design pattern&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.martinfowler.com/eaaCatalog/dataMapper.html"&gt;Data Mapper&lt;/a&gt; design pattern&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ormapper.net/"&gt;Wilson ORMapper&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://weblogs.asp.net/fbouma/category/3053.aspx"&gt;Frans Bouma's O/R mapping posts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.llblgen.com/defaultgeneric.aspx"&gt;LLBGenPro&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://nhibernate.sourceforge.net/"&gt;NHibernate&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h3 class="dtH1"&gt;.NET Framework 2.0 Features&lt;/h3&gt;   &lt;p&gt;The upcoming 2.0 release of the .NET Framework will change some of the implementation details we've looked at throughout this guide. These changes will reduce the amount of code necessary to support custom entities as well as help deal with mapping issues.&lt;/p&gt;   &lt;h4 class="dtH1"&gt;Generics&lt;/h4&gt;   &lt;p&gt;One of the main reasons for the existence of the much talked about generics is to provide developers with strongly-typed collections out of the box. We shied away from the existing collections such as &lt;b&gt;Arraylists&lt;/b&gt; because of their weakly-typed nature. Generics provide the same kind of conveniences as current collections, but in a strongly-typed manner. This is achieved by specifying the type at declaration. For example, we could replace our &lt;b&gt;UserCollection&lt;/b&gt; with no additional code, and simply create a new instance of the &lt;b&gt;List&lt;t&gt;&lt;/b&gt; generic and specify our &lt;b&gt;User&lt;/b&gt; class:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Dim users as new IList(of User)&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;IList&lt;user&gt; users = new IList&lt;user&gt;();&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Once declared, our &lt;b&gt;users&lt;/b&gt; collection can only deal with objects of type &lt;b&gt;User&lt;/b&gt;, which provides us with all the niceties of compile-time checks and optimizations.&lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further Reading&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.15seconds.com/issue/031024.htm"&gt;Introducing .NET Generics&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnvs05/html/csharp_generics.asp"&gt;An Introduction to C# Generics&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h4 class="dtH1"&gt;Nullable Types&lt;/h4&gt;   &lt;p&gt;Nullable types are actually generics that are used for different reasons than those listed previously. One of the challenges faced when dealing with databases is the proper and consistent handling of columns that support &lt;b&gt;NULL&lt;/b&gt;. When dealing with string and other classes (known as reference types), you can simply assign &lt;b&gt;nothing&lt;/b&gt;/&lt;b&gt;null&lt;/b&gt; to a variable in your code:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;if dr("UserName") Is DBNull.Value Then&lt;br /&gt;  user.UserName = nothing&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;if (dr["UserName"] == DBNull.Value){&lt;br /&gt;  user.UserName = null;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;Or you could simply do nothing (by default, reference types are &lt;b&gt;nothing&lt;/b&gt;/&lt;b&gt;null&lt;/b&gt;). This doesn't work nearly as well for value types such as &lt;b&gt;integers&lt;/b&gt;, &lt;b&gt;booleans&lt;/b&gt;, &lt;b&gt;decimals,&lt;/b&gt; and so on. You can certainly assign &lt;b&gt;nothing&lt;/b&gt;/&lt;b&gt;null&lt;/b&gt; to such values, but this will assign a default value. If you just declare an integer, or assign &lt;b&gt;nothing&lt;/b&gt;/&lt;b&gt;null&lt;/b&gt; to it, the variable will actually hold the value &lt;b&gt;0&lt;/b&gt;. This makes it difficult to map back to the database: is the value &lt;b&gt;0&lt;/b&gt; or &lt;b&gt;null&lt;/b&gt;? Nullable types solve this problem by allowing value types to either hold an actual value or null. For example, if we wanted to support a &lt;b&gt;null&lt;/b&gt; value in the &lt;b&gt;userId&lt;/b&gt; column (not exactly realistic), we'd first declare our &lt;b&gt;userId&lt;/b&gt; field and corresponding property as a nullable type:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;Private _userId As Nullable(Of Integer)&lt;br /&gt;Public Property UserId() As Nullable(Of Integer)&lt;br /&gt;  Get&lt;br /&gt;     Return _userId&lt;br /&gt;  End Get&lt;br /&gt;  Set(ByVal value As Nullable(Of Integer))&lt;br /&gt;     _userId = value&lt;br /&gt;  End Set&lt;br /&gt;End Property&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;private Nullable&lt;int&gt; userId;&lt;br /&gt;public Nullable&lt;int&gt; UserId {&lt;br /&gt;  get { return userId; }&lt;br /&gt;  set { userId = value; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;And then make use of the &lt;b&gt;HasValue&lt;/b&gt; property to determine whether &lt;b&gt;nothing&lt;/b&gt;/&lt;b&gt;null&lt;/b&gt; was assigned:&lt;/p&gt;   &lt;pre class="code"&gt;'Visual Basic .NET&lt;br /&gt;If UserId.HasValue Then&lt;br /&gt;  Return UserId.Value&lt;br /&gt;Else&lt;br /&gt;  Return DBNull.Value&lt;br /&gt;End If&lt;br /&gt;&lt;br /&gt;//C#&lt;br /&gt;if (UserId.HasValue) {&lt;br /&gt;  return UserId.Value;&lt;br /&gt;} else {&lt;br /&gt;  return DBNull.Value;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further Reading:&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://blogs.msdn.com/ericgu/archive/2004/05/27/143221.aspx"&gt;Nullable types in C#&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.panopticoncentral.net/archive/2004/06/04/1180.aspx"&gt;Nullable types in VB.NET&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h4 class="dtH1"&gt;Iterators&lt;/h4&gt;   &lt;p&gt;The &lt;b&gt;UserCollection&lt;/b&gt; example that we looked at represents only the base functionality that you'll likely need in your custom collection. Something that you won't be able to do with the provided implementation is loop through the collection in a &lt;b&gt;foreach&lt;/b&gt; loop. To do so, your custom collection must have an enumerator support-class that implements the &lt;b&gt;IEnumerable&lt;/b&gt; interface. This is a fairly straightforward and repetitive process, but nonetheless introduces even more code. C# 2.0 introduces the new &lt;b&gt;yield&lt;/b&gt; keyword to handle the implementation detail of this interface for you. There is currently no Visual Basic .NET equivalent to the new &lt;b&gt;yield&lt;/b&gt; keyword. &lt;/p&gt;   &lt;p&gt;&lt;b&gt;&lt;i&gt;Further Readings:&lt;/i&gt;&lt;/b&gt;  &lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://www.dotnetfun.com/Articles/csharp/2.0/WhatsNew20Iterators.aspx"&gt;What's new In C# 2.0 - Iterators&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ondotnet.com/pub/a/dotnet/2004/06/07/liberty.html"&gt;C# Iterators&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;   &lt;h2 class="dtH1"&gt;&lt;a name="custentcls_topic8"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;   &lt;p&gt;Making the switch to custom entities and collections shouldn't be a decision you make lightly. Numerous factors exist that need to be taken into consideration. For example, your familiarity with OO concepts, the time you have to play with this new approach, as well as the environment you are thinking of deploying it in. While the advantages are significant in general, they may not be in your particular situation. Even if they are significant in your case, the drawbacks may negate them. Also keep in mind that numerous alternative solutions exist. Jimmy Nilsson has an overview of some of these alternatives in his 5 part series &lt;i&gt;Choosing Data Containers for .NET&lt;/i&gt; (part &lt;a href="http://www.informit.com/articles/article.asp?p=31099"&gt;1&lt;/a&gt;, &lt;a href="http://www.informit.com/articles/article.asp?p=31325"&gt;2&lt;/a&gt;, &lt;a href="http://www.informit.com/articles/article.asp?p=31457"&gt;3&lt;/a&gt;, &lt;a href="http://www.informit.com/articles/article.asp?p=31672"&gt;4&lt;/a&gt;, and &lt;a href="http://www.informit.com/articles/article.asp?p=99034"&gt;5&lt;/a&gt;).&lt;/p&gt;   &lt;p&gt;Custom entities empower you with the rich capabilities of object-oriented programming, as well as help you set up the Framework for a solid, maintainable N-Tier architecture. One of the goals of this guide is to make you think of your system in terms of the business entities that make it up, instead of generic &lt;b&gt;DataSets&lt;/b&gt; and &lt;b&gt;DataTable.&lt;/b&gt; We've also touched on some key issues you should be aware of regardless of the route you chose, namely design patterns, differences between the object and relational world (&lt;a href="http://www.agiledata.org/essays/impedanceMismatch.html"&gt;read more&lt;/a&gt;), and N-Tier architecture. Remember that time spent upfront has a way of paying for itself a number of times over throughout the life of a system.&lt;/p&gt;   &lt;h4 class="dtH1"&gt;Related Books&lt;/h4&gt;   &lt;ul type="disc"&gt; &lt;li&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=4650&amp;prodId=1627168&amp;amp;ptnrid=141&amp;ptnrdata=0"&gt;Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET Team&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=12231&amp;amp;prodId=2180604&amp;ptnrid=141&amp;amp;ptnrdata=0"&gt;Expert C# Business Objects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://shopping.msn.com/search/detail.aspx?pcId=4319&amp;prodId=1876448&amp;amp;ptnrid=141&amp;amp;ptnrdata=0"&gt;Expert One-on-One Visual Basic .NET Business Objects&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-112577486175287071?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112577486175287071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112577486175287071'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/09/on-way-to-mastering-aspnet-introducing.html' title='On the Way to Mastering ASP.NET: Introducing Custom Entity Classes'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112555967911598580</id><published>2005-09-01T14:26:00.000+07:00</published><updated>2005-09-01T14:27:59.143+07:00</updated><title type='text'>Implementing Page Controller in ASP.NET</title><content type='html'>&lt;h1 class="dtH1"&gt;Implementing Page Controller in ASP.NET&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_TL.gif" border="0" height="26" width="26" /&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_A1-up.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_I1.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Architecture Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_A.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_2.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_3.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_4.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/designpatoverview.aspx"&gt;&lt;img alt="Design Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_D.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_5.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_6.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_7.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_8.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/implpatoverview.aspx"&gt;&lt;img alt="Implementation Row" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_I-up.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_9.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_10-up.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_11.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_12.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_BL.gif" border="0" height="27" width="26" /&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo1.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo2.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo3.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo4.gif" border="0" height="27" width="45" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Version 1.0.1&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://www.gotdotnet.com/Community/Workspaces/Workspace.aspx?id=08a23452-ac75-4e12-93c1-ec4e31e2de2f"&gt;&lt;span style="color:gray;"&gt;GotDotNet community for collaboration on this pattern&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/practices/"&gt;&lt;span style="color:gray;"&gt;Complete List of patterns &amp; practices&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Context&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You are building a Web application in ASP.NET and you want to take&lt;br /&gt;advantage of the event-driven nature of ASP.NET by using the built-in&lt;br /&gt;page controller. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Implementation Strategy&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The concepts described in the &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesPageController.asp"&gt;&lt;i&gt;Page Controller&lt;/i&gt;&lt;/a&gt;&lt;br /&gt;pattern are implemented in ASP.NET by default. The ASP.NET page&lt;br /&gt;framework implements these concepts in such a way that the underlying&lt;br /&gt;mechanism of capturing an event on the client, transmitting it to the&lt;br /&gt;server, and calling the appropriate method is automatic and invisible&lt;br /&gt;to the implementer. The page controller is extensible in that it&lt;br /&gt;exposes various events at specific points in the life cycle (see "Page&lt;br /&gt;Life Cycle," later in this pattern) so that application-specific&lt;br /&gt;actions can be run when they are appropriate. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;For example, assume the user is interacting with a Web Forms page&lt;br /&gt;that contains one button server control (see "Simple Page Example,"&lt;br /&gt;later in this pattern). When the user clicks the button control, an&lt;br /&gt;event is transmitted as an HTTP post to the server, where the ASP.NET&lt;br /&gt;page framework interprets the posted information and associates the&lt;br /&gt;raised event with an appropriate event handler. The framework&lt;br /&gt;automatically calls the appropriate event handler for the button as&lt;br /&gt;part of the framework's normal processing. As a result, you no longer&lt;br /&gt;need to implement this functionality. Furthermore, you can use the&lt;br /&gt;built-in controller, or you can replace the built-in controller with&lt;br /&gt;you own customized controller (see &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt;). &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Page Life Cycle&lt;/p&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The following list contains the most common stages of the page&lt;br /&gt;life cycle in the order in which they occur. It also includes the&lt;br /&gt;specific events that are raised and some typical actions that could be&lt;br /&gt;performed at the various stages in the processing of the request: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table class="clsContainer" float="left" border="0" cellpadding="15" cellspacing="0" width="100%"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;ASP.NET page framework initialization (Event: Init)&lt;/b&gt;. This is the first step in the life cycle, which initializes the ASP.NET runtime for the request.  &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;User code initialization (Event: Load)&lt;/b&gt;. You should&lt;br /&gt;perform common tasks specific to your application, such as opening&lt;br /&gt;database connections, when the page controller raises the &lt;b&gt;Load&lt;/b&gt; event. You can assume that when the &lt;b&gt;Load&lt;/b&gt;&lt;br /&gt;event is raised, server controls are created and initialized, state has&lt;br /&gt;been restored, and form controls reflect client-side changes. [Reilly02]&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Application-specific event handling&lt;/b&gt;. At this stage, you should perform processing specific to your application in response to the events raised by the controller. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Cleanup (Event: Unload)&lt;/b&gt;. The page has finished rendering and is ready to be discarded. You should close any database connections that the &lt;b&gt;Load&lt;/b&gt;&lt;br /&gt;event opened and discard any objects that are no longer needed. The&lt;br /&gt;Microsoft.NET Framework closes database connections automatically,&lt;br /&gt;after the connection object is garbage collected. However, you do not&lt;br /&gt;have any control over when the garbage collection occurs. Therefore, it&lt;br /&gt;is good practice to close database connections explicitly to make&lt;br /&gt;efficient use of the database connection pool.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;blockquote class="dtBlock"&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; There are several more stages of page processing&lt;br /&gt;than are listed here. However, they are not used for most page&lt;br /&gt;processing scenarios. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;h3 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Simple Page Example&lt;/p&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The first example is a simple page that takes input from the&lt;br /&gt;user and then displays the input on the screen. The example illustrates&lt;br /&gt;the event-driven model that ASP.NET uses to implement server controls. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig01.gif" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;head3&gt; Figure 1: Simple page&lt;/head3&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;When the user types his or her name and then clicks the Click&lt;br /&gt;Here button, the name appears directly below the button, as shown in&lt;br /&gt;Figure 2. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig02.gif" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;head3&gt; Figure 2: Simple page displaying user input&lt;/head3&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In ASP.NET pages, the user interface programming is divided into&lt;br /&gt;two distinct pieces: the visual component, or view, and the logic,&lt;br /&gt;which is a combination of the model and the controller. This division&lt;br /&gt;separates the visible portion of the page (the view) from the code&lt;br /&gt;behind the page with which the page interacts (model and controller). &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The visual element is called the Web Forms &lt;i&gt;page&lt;/i&gt;. The page&lt;br /&gt;consists of a file containing static HTML or ASP.NET server controls,&lt;br /&gt;or both simultaneously. For this example, the Web Forms page is named&lt;br /&gt;SimplePage.aspx and consists of the following code: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%@ Page language="c#" Codebehind="SimplePage.aspx.cs" AutoEventWireup="false" Inherits="SimplePage" %&amp;gt;&lt;br /&gt;&amp;lt;HTML&amp;gt;&lt;br /&gt; &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="Form1" runat="server"&amp;gt;&lt;br /&gt;       Name:&amp;lt;asp:textbox id="name" runat="server" /&amp;gt;&lt;br /&gt;       &amp;lt;p /&amp;gt;&lt;br /&gt;       &amp;lt;asp:button id="MyButton" text="Click Here" OnClick="SubmitBtn_Click" runat="server" /&amp;gt;&lt;br /&gt;       &amp;lt;p /&amp;gt;&lt;br /&gt;       &amp;lt;span id="mySpan" runat="server"&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/HTML&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The&lt;br /&gt;logic for the Web Forms page consists of code that you create to&lt;br /&gt;interact with the form. The programming logic resides in a file that is&lt;br /&gt;separate from the user interface file. This file, referred to as the &lt;i&gt;code-behind&lt;/i&gt; file, is named SimplePage.aspx.cs:&lt;/p&gt; &lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;using System.Web.UI.HtmlControls;&lt;br /&gt;&lt;br /&gt;public class SimplePage : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt; protected System.Web.UI.WebControls.TextBox name;&lt;br /&gt; protected System.Web.UI.WebControls.Button MyButton;&lt;br /&gt; protected System.Web.UI.HtmlControls.HtmlGenericControl mySpan;&lt;br /&gt;&lt;br /&gt; public void SubmitBtn_Click(Object sender, EventArgs e)&lt;br /&gt; {&lt;br /&gt;    mySpan.InnerHtml = "Hello, " + name.Text + ".";&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The&lt;br /&gt;purpose of this code is to indicate to the page controller that when&lt;br /&gt;the user clicks the button, a request will be sent back to the server&lt;br /&gt;and the &lt;b&gt;SubmitBtn_Click&lt;/b&gt; function will be executed.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This implementation shows how simple it is to connect to the events&lt;br /&gt;that the controller provides. It also illustrates that code written in&lt;br /&gt;this fashion is easier to understand because the application logic is&lt;br /&gt;not combined with the low-level code that manages the event&lt;br /&gt;dispatching. &lt;/p&gt;&lt;h3 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Common Look and Feel Example&lt;/p&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The following example uses a typical implementation strategy of&lt;br /&gt;the page controller to provide a banner that displays dynamic content:&lt;br /&gt;the authenticated user's e-mail address (which is retrieved from the&lt;br /&gt;database) on every page in the application. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The common implementation is contained in a base class from&lt;br /&gt;which all of the page objects in the site inherit. Figure 3 shows one&lt;br /&gt;of the pages in the site. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig03.gif" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;head3&gt; Figure 3: Banner displaying dynamic content&lt;/head3&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The individual pages in the site are responsible for rendering&lt;br /&gt;their own content, while the base class is responsible for rendering&lt;br /&gt;the header. Because the individual pages inherit from the base class,&lt;br /&gt;they all have the same functionality. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This implementation uses a design pattern called &lt;i&gt;Template Method&lt;/i&gt;. The pattern defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. &lt;i&gt;Template Method&lt;/i&gt; lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. [Gamma95]&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Applying &lt;i&gt;Template Method&lt;/i&gt; to this problem involves moving&lt;br /&gt;common code from the individual pages into a base class. This ensures&lt;br /&gt;that the common code is contained in one place and is easily&lt;br /&gt;maintainable. In this example, the base class is named &lt;b&gt;BasePage&lt;/b&gt; and is responsible for connecting the &lt;b&gt;Page_Load&lt;/b&gt; method to the &lt;b&gt;Load&lt;/b&gt; event. After the work associated with the &lt;b&gt;BasePage&lt;/b&gt;; which is retrieving the user's e-mail address from the database and setting the site name, the &lt;b&gt;Page_Load&lt;/b&gt; function calls a method named &lt;b&gt;PageLoadEvent&lt;/b&gt;. Subclasses implement &lt;b&gt;PageLoadEvent&lt;/b&gt; to perform their own specific Load functionality. Figure 4 shows the structure of this solution. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig04.gif" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;head3&gt; Figure 4: Structure of the code-behind pages implementation&lt;/head3&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;When a page is requested, the ASP.NET runtime fires the &lt;b&gt;Load&lt;/b&gt; event, which in turn calls the &lt;b&gt;Page_Load&lt;/b&gt; method on &lt;b&gt;BasePage&lt;/b&gt;. The &lt;b&gt;BasePage&lt;/b&gt; method retrieves the data it needs and then calls &lt;b&gt;PageLoadEvent&lt;/b&gt;&lt;br /&gt;on the specific page that was requested to perform any page-specific&lt;br /&gt;loading that is required. Figure 5 shows the page request sequence.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig05.gif" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;head3&gt; Figure 5: Page request sequence&lt;/head3&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Implementing the common functionality in this manner frees the&lt;br /&gt;pages from having to set up the header and also allows for site-wide&lt;br /&gt;changes to be made easily. If the header rendering and initialization&lt;br /&gt;code is not contained in a single file, the changes must be made to all&lt;br /&gt;files that contain code that is related to the header. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;BasePage.cs&lt;/p&gt;&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The code for the base class implements the following functionality:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt; Connects the &lt;b&gt;Load&lt;/b&gt; event to the &lt;b&gt;Page_Load&lt;/b&gt; method for request-specific initialization. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt; Retrieves the authenticated user's name from the request context and using the &lt;b&gt;DatabaseGateway&lt;/b&gt; class finds the user's record in the database. The code assigns the &lt;b&gt;eMail&lt;/b&gt; label to the user's e-mail address. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt; Assigns the site name to the &lt;b&gt;siteName&lt;/b&gt; label. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt; Calls the &lt;b&gt;PageLoadEvent&lt;/b&gt; method, which derived classes can implement for any page-specific loading. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;blockquote class="dtBlock"&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; It would be better to define the &lt;b&gt;BasePage&lt;/b&gt; class as abstract, because doing so would force the implementers to provide an implementation for &lt;b&gt;PageLoadEvent&lt;/b&gt;.&lt;br /&gt;However, in Microsoft Visual Studio .NET, it is not possible to define&lt;br /&gt;this base class as abstract. Instead, the class provides a default&lt;br /&gt;implementation that can be overridden by derived classes. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;public class BasePage : Page&lt;br /&gt;{&lt;br /&gt; protected Label eMail;&lt;br /&gt; protected Label siteName;&lt;br /&gt;&lt;br /&gt; virtual protected void PageLoadEvent(object sender, System.EventArgs e)&lt;br /&gt; {}&lt;br /&gt;&lt;br /&gt; protected void Page_Load(object sender, System.EventArgs e)&lt;br /&gt; {&lt;br /&gt;       if(!IsPostBack)&lt;br /&gt;       {&lt;br /&gt;             string name = Context.User.Identity.Name;&lt;br /&gt;&lt;br /&gt;             eMail.Text = DatabaseGateway.RetrieveAddress(name);&lt;br /&gt;             siteName.Text = "Micro-site";&lt;br /&gt;&lt;br /&gt;             PageLoadEvent(sender, e);&lt;br /&gt;       }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; #region Web Form Designer generated code&lt;br /&gt; override protected void OnInit(EventArgs e)&lt;br /&gt; {&lt;br /&gt;    //&lt;br /&gt;    //&lt;br /&gt;    // CODEGEN: This call is required by the ASP.NET Web Form Designer.&lt;br /&gt;       //&lt;br /&gt;       InitializeComponent();&lt;br /&gt;       base.OnInit(e);&lt;br /&gt; }&lt;br /&gt;     &lt;br /&gt; /// &amp;lt;summary&amp;gt;&lt;br /&gt; /// Required method for Designer support - do not modify&lt;br /&gt; /// the contents of this method with the code editor.&lt;br /&gt; /// &amp;lt;/summary&amp;gt;&lt;br /&gt; private void InitializeComponent()&lt;br /&gt; {  &lt;br /&gt;       this.Load += new System.EventHandler(this.Page_Load);&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt; #endregion&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;BasePage.inc&lt;/p&gt;&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Not only do you have to provide a common base class for the&lt;br /&gt;logic code behind the page, but you also have to provide a common file&lt;br /&gt;that holds the view or UI rendering code. The code is included in each&lt;br /&gt;.aspx page. This HTML file is not intended to be displayed on its own.&lt;br /&gt;Using a common file enhances your ability to make changes in one place&lt;br /&gt;and have them propagate to all the pages that include the file. The&lt;br /&gt;following example code shows the common file for this example, named&lt;br /&gt;BasePage.inc:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;table width="100%" cellspacing="0" cellpadding="0"&amp;gt;&lt;br /&gt; &amp;lt;tr&amp;gt;&lt;br /&gt;    &amp;lt;td align="right" bgcolor="#9c0001" cellspacing="0" cellpadding="0" width="100%" height="20"&amp;gt;&lt;br /&gt;       &amp;lt;font size="2" color="#ffffff"&amp;gt;Welcome:&lt;br /&gt;       &amp;lt;asp:Label id="eMail" runat="server"&amp;gt;username&amp;lt;/asp:Label&amp;gt;  &amp;lt;/font&amp;gt;&lt;br /&gt;    &amp;lt;/td&amp;gt;&lt;br /&gt; &amp;lt;/tr&amp;gt;&lt;br /&gt; &amp;lt;tr&amp;gt;&lt;br /&gt;    &amp;lt;td align="right" width="100%" bgcolor="#d3c9c7" height="70"&amp;gt;&lt;br /&gt;       &amp;lt;font size="6" color="#ffffff"&amp;gt;&lt;br /&gt;       &amp;lt;asp:Label id="siteName" Runat="server"&amp;gt;Micro-site Banner&amp;lt;/asp:Label&amp;gt;  &amp;lt;/font&amp;gt;&lt;br /&gt;    &amp;lt;/td&amp;gt;&lt;br /&gt; &amp;lt;/tr&amp;gt;&lt;br /&gt;&amp;lt;/table&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4 class="dtH1"&gt;&lt;br /&gt;DatabaseGateway.cs&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This class encapsulates all access to the database for these pages. This is an example of a &lt;i&gt;Table Data Gateway&lt;/i&gt; [Fowler03] which represents the model code for the pages in this application. &lt;/p&gt;&lt;br /&gt;&lt;pre class="code"&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;&lt;br /&gt;public class DatabaseGateway&lt;br /&gt;{&lt;br /&gt; public static string RetrieveAddress(string name)&lt;br /&gt; {&lt;br /&gt;       String address = null;&lt;br /&gt;&lt;br /&gt;       String selectCmd =&lt;br /&gt;             String.Format("select * from webuser where (id = '{0}')",&lt;br /&gt;             name);&lt;br /&gt;&lt;br /&gt;       SqlConnection myConnection =&lt;br /&gt;             new SqlConnection("server=(local);database=webusers;Trusted_Connection=yes");&lt;br /&gt;       SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);&lt;br /&gt;&lt;br /&gt;       DataSet ds = new DataSet();&lt;br /&gt;       myCommand.Fill(ds,"webuser");&lt;br /&gt;       if(ds.Tables["webuser"].Rows.Count == 1)&lt;br /&gt;       {&lt;br /&gt;             DataRow row = ds.Tables["webuser"].Rows[0];&lt;br /&gt;             address = row["address"].ToString();&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       return address;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Page1.aspx&lt;/p&gt;&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The following is an example of how to use the common functionality in a page: &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;%@ Page language="c#" Codebehind="Page1.aspx.cs" AutoEventWireup="false" Inherits="Page1" %&amp;gt;&lt;br /&gt;&amp;lt;HTML&amp;gt;&lt;br /&gt; &amp;lt;HEAD&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Page-1&amp;lt;/title&amp;gt;&lt;br /&gt; &amp;lt;/HEAD&amp;gt;&lt;br /&gt; &amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;!-- #include virtual="BasePage.inc" --&amp;gt;&lt;br /&gt;    &amp;lt;form id="Page1" method="post" runat="server"&amp;gt;&lt;br /&gt;       &amp;lt;h1&amp;gt;Page:&lt;br /&gt;          &amp;lt;asp:label id="pageNumber" Runat="server"&amp;gt;NN&amp;lt;/asp:label&amp;gt;&amp;lt;/h1&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/HTML&amp;gt;&lt;br /&gt;&lt;/pre&gt;The following directive from the file loads the common HTML for the header:&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- #include virtual="BasePage.inc" --&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Page1.aspx.cs&lt;/p&gt;&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The code-behind class must inherit from the &lt;b&gt;BasePage&lt;/b&gt; class and then implement the &lt;b&gt;PageLoadEvent&lt;/b&gt; method to do any page-specific loading. In this example, the page-specific activity is to assign the number 1 to the &lt;b&gt;pageNumber&lt;/b&gt; label. &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;public class Page1 : BasePage&lt;br /&gt;{&lt;br /&gt; protected System.Web.UI.WebControls.Label pageNumber;&lt;br /&gt;&lt;br /&gt; protected override void PageLoadEvent(object sender, System.EventArgs e)&lt;br /&gt; {&lt;br /&gt;    pageNumber.Text = "1";&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Testing Considerations&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The dependence on the ASP.NET runtime makes testing of the&lt;br /&gt;implementation difficult. It is not possible to instantiate classes&lt;br /&gt;that inherit from System.Web.UI.Page or the other various classes&lt;br /&gt;contained in the environment. This makes it impossible to unit test the&lt;br /&gt;individual pieces of the application in isolation. The only remaining&lt;br /&gt;way to test this implementation automatically is to generate HTTP&lt;br /&gt;requests and then retrieve the HTTP response and determine if the&lt;br /&gt;response is correct. This approach is prone to error because you are&lt;br /&gt;comparing the text of the response with expected text. &lt;/p&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Resulting Context&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The built-in ASP.NET page controller functionality results in the following benefits and liabilities:&lt;/p&gt;&lt;br /&gt;&lt;h3 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Benefits&lt;/p&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Takes advantage of framework features&lt;/b&gt;. The page&lt;br /&gt;controller functionality is built into ASP.NET and can be easily&lt;br /&gt;extended by connecting application-specific actions to the events&lt;br /&gt;exposed by the controller. It is also easy to separate the&lt;br /&gt;controller-specific code from the model and view code by using the&lt;br /&gt;code-behind feature. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Explicit URLs&lt;/b&gt;. The URL that the user enters refers to an&lt;br /&gt;actual page in the application. This means that the pages can be&lt;br /&gt;bookmarked and entered later. The URLs also tend to have fewer&lt;br /&gt;parameters making them easier for users to enter. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt; Increases modularity and reuse&lt;/b&gt;. The Common Look and Feel example demonstrated how you could reuse &lt;b&gt;BasePage&lt;/b&gt; for many pages without having to modify the &lt;b&gt;BasePage&lt;/b&gt; class or HTML file.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;h3 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Liabilities&lt;/p&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Requires code changes&lt;/b&gt;. To share common functionality, as&lt;br /&gt;demonstrated in the Common Look and Feel example, the individual pages&lt;br /&gt;have to be modified to inherit from the newly defined base class&lt;br /&gt;instead of &lt;b&gt;System.Web.UI.Page&lt;/b&gt;. The &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesInterceptingFilter.asp"&gt;&lt;i&gt;Intercepting Filter&lt;/i&gt;&lt;/a&gt; pattern describes a mechanism for adding common functionality by changing the Web.config file and not the pages themselves.&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Uses inheritance&lt;/b&gt;. The Common Look and Feel example uses&lt;br /&gt;inheritance to share the implementation across multiple pages. Most&lt;br /&gt;programmers who learn object-oriented programming initially like&lt;br /&gt;inheritance. However, using inheritance to share implementation can&lt;br /&gt;often lead to software that is difficult to change. If the base class&lt;br /&gt;become complicated with conditional logic, it is better to introduce&lt;br /&gt;helper classes or to consider using &lt;i&gt;Front Controller&lt;/i&gt; instead. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;Difficult to test&lt;/b&gt;. Because the page controller is&lt;br /&gt;implemented in ASP.NET, it is difficult to test in isolation. To&lt;br /&gt;improve the testability, you should separate as much functionality out&lt;br /&gt;of the ASP.NET - specific code in classes that do not depend on&lt;br /&gt;ASP.NET. This enables you to test without having to start the ASP.NET&lt;br /&gt;runtime. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Related Patterns&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;For more information, see the following related patterns:&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;i&gt;Template Method&lt;/i&gt; [Gamma95]. The &lt;b&gt;BasePage&lt;/b&gt; class and the &lt;b&gt;Page_Load&lt;/b&gt; method are an example implementation of this pattern. &lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesInterceptingFilter.asp"&gt;&lt;i&gt;Intercepting Filter&lt;/i&gt;&lt;/a&gt;&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt;&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;/li&gt;&lt;br /&gt;&lt;h2 class="dtH1"&gt;&lt;br /&gt;&lt;p&gt;Acknowledgments&lt;/p&gt;&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;[Gamma95] Gamma, Helm, Johnson, and Vlissides. &lt;i&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/i&gt;. Addison-Wesley, 1995.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[Reilly02] Reilly, Douglas J. &lt;i&gt;Designing Microsoft ASP.NET Applications.&lt;/i&gt; Microsoft Press, 2002.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[Fowler03] Fowler, Martin. &lt;i&gt;Patterns of Enterprise Application Architecture&lt;/i&gt;. Addison-Wesley, 2003.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-112555967911598580?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555967911598580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555967911598580'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/09/implementing-page-controller-in-aspnet_01.html' title='Implementing Page Controller in ASP.NET'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112555865224183216</id><published>2005-09-01T14:10:00.000+07:00</published><updated>2005-09-01T14:22:32.080+07:00</updated><title type='text'>Implementing Page Controller in ASP.NET</title><content type='html'>&lt;h1 class="dtH1"&gt;Implementing Page Controller in ASP.NET&lt;/h1&gt;  &lt;p&gt; &lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt; &lt;tbody&gt;&lt;tr&gt; &lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_TL.gif" border="0" height="26" width="26"&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_A1-up.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_I1.gif" border="0" height="26" width="45"&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Architecture Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_A.gif" border="0" height="26" width="26"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_1.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_2.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_3.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_4.gif" border="0" height="26" width="45"&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/designpatoverview.aspx"&gt;&lt;img alt="Design Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_D.gif" border="0" height="26" width="26"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_5.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_6.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_7.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_8.gif" border="0" height="26" width="45"&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/implpatoverview.aspx"&gt;&lt;img alt="Implementation Row" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_I-up.gif" border="0" height="26" width="26"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_9.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_10-up.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_11.gif" border="0" height="26" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_12.gif" border="0" height="26" width="45"&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_BL.gif" border="0" height="27" width="26"&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo1.gif" border="0" height="27" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo2.gif" border="0" height="27" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo3.gif" border="0" height="27" width="37"&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo4.gif" border="0" height="27" width="45"&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/p&gt;  &lt;p&gt;Version 1.0.1&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.gotdotnet.com/Community/Workspaces/Workspace.aspx?id=08a23452-ac75-4e12-93c1-ec4e31e2de2f"&gt;&lt;span style="color: gray;"&gt;GotDotNet community for collaboration on this pattern&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/practices/"&gt;&lt;span style="color: gray;"&gt;Complete List of patterns &amp;amp; practices&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Context&lt;/p&gt; &lt;/h2&gt;  &lt;p&gt;You&lt;br /&gt;are building a Web application in ASP.NET and you want to take&lt;br /&gt;advantage of the event-driven nature of ASP.NET by using the built-in&lt;br /&gt;page controller. &lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Implementation Strategy&lt;/p&gt; &lt;/h2&gt;  &lt;p&gt;The concepts described in the &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesPageController.asp"&gt;&lt;i&gt;Page Controller&lt;/i&gt;&lt;/a&gt;&lt;br /&gt;pattern are implemented in ASP.NET by default. The ASP.NET page&lt;br /&gt;framework implements these concepts in such a way that the underlying&lt;br /&gt;mechanism of capturing an event on the client, transmitting it to the&lt;br /&gt;server, and calling the appropriate method is automatic and invisible&lt;br /&gt;to the implementer. The page controller is extensible in that it&lt;br /&gt;exposes various events at specific points in the life cycle (see "Page&lt;br /&gt;Life Cycle," later in this pattern) so that application-specific&lt;br /&gt;actions can be run when they are appropriate. &lt;/p&gt;  &lt;p&gt;For example,&lt;br /&gt;assume the user is interacting with a Web Forms page that contains one&lt;br /&gt;button server control (see "Simple Page Example," later in this&lt;br /&gt;pattern). When the user clicks the button control, an event is&lt;br /&gt;transmitted as an HTTP post to the server, where the ASP.NET page&lt;br /&gt;framework interprets the posted information and associates the raised&lt;br /&gt;event with an appropriate event handler. The framework automatically&lt;br /&gt;calls the appropriate event handler for the button as part of the&lt;br /&gt;framework's normal processing. As a result, you no longer need to&lt;br /&gt;implement this functionality. Furthermore, you can use the built-in&lt;br /&gt;controller, or you can replace the built-in controller with you own&lt;br /&gt;customized controller (see &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt;). &lt;/p&gt;  &lt;h3 class="dtH1"&gt; &lt;p&gt;Page Life Cycle&lt;/p&gt; &lt;/h3&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt; &lt;p&gt;The&lt;br /&gt;following list contains the most common stages of the page life cycle&lt;br /&gt;in the order in which they occur. It also includes the specific events&lt;br /&gt;that are raised and some typical actions that could be performed at the&lt;br /&gt;various stages in the processing of the request: &lt;/p&gt;   &lt;table class="clsContainer" float="left" border="0" cellpadding="15" cellspacing="0" width="100%"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;li&gt;&lt;p&gt;&lt;b&gt;ASP.NET page framework initialization (Event: Init)&lt;/b&gt;. This is the first step in the life cycle, which initializes the ASP.NET runtime for the request.  &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;User code initialization (Event: Load)&lt;/b&gt;.&lt;br /&gt;You should perform common tasks specific to your application, such as&lt;br /&gt;opening database connections, when the page controller raises the &lt;b&gt;Load&lt;/b&gt; event. You can assume that when the &lt;b&gt;Load&lt;/b&gt;&lt;br /&gt;event is raised, server controls are created and initialized, state has&lt;br /&gt;been restored, and form controls reflect client-side changes. [Reilly02]&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Application-specific event handling&lt;/b&gt;. At this stage, you should perform processing specific to your application in response to the events raised by the controller. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Cleanup (Event: Unload)&lt;/b&gt;. The page has finished rendering and is ready to be discarded. You should close any database connections that the &lt;b&gt;Load&lt;/b&gt;&lt;br /&gt;event opened and discard any objects that are no longer needed. The&lt;br /&gt;Microsoft.NET Framework closes database connections automatically,&lt;br /&gt;after the connection object is garbage collected. However, you do not&lt;br /&gt;have any control over when the garbage collection occurs. Therefore, it&lt;br /&gt;is good practice to close database connections explicitly to make&lt;br /&gt;efficient use of the database connection pool.&lt;/p&gt;&lt;/li&gt; &lt;blockquote class="dtBlock"&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;br /&gt;There are several more stages of page processing than are listed here.&lt;br /&gt;However, they are not used for most page processing scenarios. &lt;/p&gt;  &lt;/blockquote&gt; &lt;h3 class="dtH1"&gt; &lt;p&gt;Simple Page Example&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The&lt;br /&gt;first example is a simple page that takes input from the user and then&lt;br /&gt;displays the input on the screen. The example illustrates the&lt;br /&gt;event-driven model that ASP.NET uses to implement server controls. &lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig01.gif"&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 1: Simple page&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;When&lt;br /&gt;the user types his or her name and then clicks the Click Here button,&lt;br /&gt;the name appears directly below the button, as shown in Figure 2. &lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig02.gif"&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 2: Simple page displaying user input&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;In&lt;br /&gt;ASP.NET pages, the user interface programming is divided into two&lt;br /&gt;distinct pieces: the visual component, or view, and the logic, which is&lt;br /&gt;a combination of the model and the controller. This division separates&lt;br /&gt;the visible portion of the page (the view) from the code behind the&lt;br /&gt;page with which the page interacts (model and controller). &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;The visual element is called the Web Forms &lt;i&gt;page&lt;/i&gt;.&lt;br /&gt;The page consists of a file containing static HTML or ASP.NET server&lt;br /&gt;controls, or both simultaneously. For this example, the Web Forms page&lt;br /&gt;is named SimplePage.aspx and consists of the following code: &lt;/p&gt;  &lt;pre class="code"&gt;&lt;br /&gt;&amp;lt;%@ Page language="c#" Codebehind="SimplePage.aspx.cs" AutoEventWireup="false" Inherits="SimplePage" %&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;     &lt;form id="Form1" runat="server"&gt;&lt;br /&gt;        Name:&lt;asp:textbox id="name" runat="server"&gt;&lt;br /&gt;        &lt;/asp:textbox&gt;&lt;p&gt;&lt;br /&gt;        &lt;asp:button id="MyButton" text="Click Here" onclick="SubmitBtn_Click" runat="server"&gt;&lt;br /&gt;        &lt;/asp:button&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;        &lt;span id="mySpan" runat="server"&gt;&lt;/span&gt;&lt;br /&gt;     &lt;/p&gt;&lt;br /&gt;  &lt;/form&gt;&lt;/pre&gt;&lt;p&gt;The&lt;br /&gt;logic for the Web Forms page consists of code that you create to&lt;br /&gt;interact with the form. The programming logic resides in a file that is&lt;br /&gt;separate from the user interface file. This file, referred to as the &lt;i&gt;code-behind&lt;/i&gt; file, is named SimplePage.aspx.cs:&lt;/p&gt; &lt;pre class="code"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;using System.Web.UI.HtmlControls;&lt;br /&gt;&lt;br /&gt;public class SimplePage : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt;  protected System.Web.UI.WebControls.TextBox name;&lt;br /&gt;  protected System.Web.UI.WebControls.Button MyButton;&lt;br /&gt;  protected System.Web.UI.HtmlControls.HtmlGenericControl mySpan;&lt;br /&gt;&lt;br /&gt;  public void SubmitBtn_Click(Object sender, EventArgs e)&lt;br /&gt;  {&lt;br /&gt;     mySpan.InnerHtml = "Hello, " + name.Text + ".";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The purpose of this code is to indicate to the page controller&lt;br /&gt;that when the user clicks the button, a request will be sent back to&lt;br /&gt;the server and the &lt;b&gt;SubmitBtn_Click&lt;/b&gt; function will be executed.&lt;/p&gt; &lt;p&gt;This&lt;br /&gt;implementation shows how simple it is to connect to the events that the&lt;br /&gt;controller provides. It also illustrates that code written in this&lt;br /&gt;fashion is easier to understand because the application logic is not&lt;br /&gt;combined with the low-level code that manages the event dispatching. &lt;/p&gt;&lt;h3 class="dtH1"&gt; &lt;p&gt;Common Look and Feel Example&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The&lt;br /&gt;following example uses a typical implementation strategy of the page&lt;br /&gt;controller to provide a banner that displays dynamic content: the&lt;br /&gt;authenticated user's e-mail address (which is retrieved from the&lt;br /&gt;database) on every page in the application. &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;The&lt;br /&gt;common implementation is contained in a base class from which all of&lt;br /&gt;the page objects in the site inherit. Figure 3 shows one of the pages&lt;br /&gt;in the site. &lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig03.gif"&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 3: Banner displaying dynamic content&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The&lt;br /&gt;individual pages in the site are responsible for rendering their own&lt;br /&gt;content, while the base class is responsible for rendering the header.&lt;br /&gt;Because the individual pages inherit from the base class, they all have&lt;br /&gt;the same functionality. &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;This implementation uses a design pattern called &lt;i&gt;Template Method&lt;/i&gt;. The pattern defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. &lt;i&gt;Template Method&lt;/i&gt; lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. [Gamma95]&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;Applying &lt;i&gt;Template Method&lt;/i&gt;&lt;br /&gt;to this problem involves moving common code from the individual pages&lt;br /&gt;into a base class. This ensures that the common code is contained in&lt;br /&gt;one place and is easily maintainable. In this example, the base class&lt;br /&gt;is named &lt;b&gt;BasePage&lt;/b&gt; and is responsible for connecting the &lt;b&gt;Page_Load&lt;/b&gt; method to the &lt;b&gt;Load&lt;/b&gt; event. After the work associated with the &lt;b&gt;BasePage&lt;/b&gt;; which is retrieving the user's e-mail address from the database and setting the site name, the &lt;b&gt;Page_Load&lt;/b&gt; function calls a method named &lt;b&gt;PageLoadEvent&lt;/b&gt;. Subclasses implement &lt;b&gt;PageLoadEvent&lt;/b&gt; to perform their own specific Load functionality. Figure 4 shows the structure of this solution. &lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig04.gif"&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 4: Structure of the code-behind pages implementation&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;When a page is requested, the ASP.NET runtime fires the &lt;b&gt;Load&lt;/b&gt; event, which in turn calls the &lt;b&gt;Page_Load&lt;/b&gt; method on &lt;b&gt;BasePage&lt;/b&gt;. The &lt;b&gt;BasePage&lt;/b&gt; method retrieves the data it needs and then calls &lt;b&gt;PageLoadEvent&lt;/b&gt;&lt;br /&gt;on the specific page that was requested to perform any page-specific&lt;br /&gt;loading that is required. Figure 5 shows the page request sequence.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_Page%20Controller_Fig05.gif"&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 5: Page request sequence&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;Implementing&lt;br /&gt;the common functionality in this manner frees the pages from having to&lt;br /&gt;set up the header and also allows for site-wide changes to be made&lt;br /&gt;easily. If the header rendering and initialization code is not&lt;br /&gt;contained in a single file, the changes must be made to all files that&lt;br /&gt;contain code that is related to the header. &lt;/p&gt;  &lt;h4 class="dtH1"&gt; &lt;p&gt;BasePage.cs&lt;/p&gt; &lt;/h4&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The code for the base class implements the following functionality:&lt;/p&gt;  &lt;li&gt;&lt;p&gt; Connects the &lt;b&gt;Load&lt;/b&gt; event to the &lt;b&gt;Page_Load&lt;/b&gt; method for request-specific initialization. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; Retrieves the authenticated user's name from the request context and using the &lt;b&gt;DatabaseGateway&lt;/b&gt; class finds the user's record in the database. The code assigns the &lt;b&gt;eMail&lt;/b&gt; label to the user's e-mail address. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; Assigns the site name to the &lt;b&gt;siteName&lt;/b&gt; label. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; Calls the &lt;b&gt;PageLoadEvent&lt;/b&gt; method, which derived classes can implement for any page-specific loading. &lt;/p&gt;&lt;/li&gt; &lt;blockquote class="dtBlock"&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; It would be better to define the &lt;b&gt;BasePage&lt;/b&gt; class as abstract, because doing so would force the implementers to provide an implementation for &lt;b&gt;PageLoadEvent&lt;/b&gt;.&lt;br /&gt;However, in Microsoft Visual Studio .NET, it is not possible to define&lt;br /&gt;this base class as abstract. Instead, the class provides a default&lt;br /&gt;implementation that can be overridden by derived classes. &lt;/p&gt;  &lt;/blockquote&gt; &lt;pre class="code"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;public class BasePage : Page&lt;br /&gt;{&lt;br /&gt;  protected Label eMail;&lt;br /&gt;  protected Label siteName;&lt;br /&gt;&lt;br /&gt;  virtual protected void PageLoadEvent(object sender, System.EventArgs e)&lt;br /&gt;  {}&lt;br /&gt; &lt;br /&gt;  protected void Page_Load(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;        if(!IsPostBack)&lt;br /&gt;        {&lt;br /&gt;              string name = Context.User.Identity.Name;&lt;br /&gt;&lt;br /&gt;              eMail.Text = DatabaseGateway.RetrieveAddress(name);&lt;br /&gt;              siteName.Text = "Micro-site";&lt;br /&gt;&lt;br /&gt;              PageLoadEvent(sender, e);&lt;br /&gt;        }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  #region Web Form Designer generated code&lt;br /&gt;  override protected void OnInit(EventArgs e)&lt;br /&gt;  {&lt;br /&gt;     //&lt;br /&gt;     //&lt;br /&gt;     // CODEGEN: This call is required by the ASP.NET Web Form Designer.&lt;br /&gt;        //&lt;br /&gt;        InitializeComponent();&lt;br /&gt;        base.OnInit(e);&lt;br /&gt;  }&lt;br /&gt;       &lt;br /&gt;  /// &lt;summary&gt;&lt;br /&gt;  /// Required method for Designer support - do not modify&lt;br /&gt;  /// the contents of this method with the code editor.&lt;br /&gt;  /// &lt;/summary&gt;&lt;br /&gt;  private void InitializeComponent()&lt;br /&gt;  {   &lt;br /&gt;        this.Load += new System.EventHandler(this.Page_Load);&lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;  #endregion&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;h4 class="dtH1"&gt; &lt;p&gt;BasePage.inc&lt;/p&gt; &lt;/h4&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;Not&lt;br /&gt;only do you have to provide a common base class for the logic code&lt;br /&gt;behind the page, but you also have to provide a common file that holds&lt;br /&gt;the view or UI rendering code. The code is included in each .aspx page.&lt;br /&gt;This HTML file is not intended to be displayed on its own. Using a&lt;br /&gt;common file enhances your ability to make changes in one place and have&lt;br /&gt;them propagate to all the pages that include the file. The following&lt;br /&gt;example code shows the common file for this example, named BasePage.inc:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" width="100%"&gt;&lt;br /&gt;  &lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;     &lt;td bg="" cellspacing="0" cellpadding="0" style="color: rgb(156, 0, 1);" align="right" height="20" width="100%"&gt;&lt;br /&gt;        &lt;span style="font-size: 85%; color: rgb(255, 255, 255);"&gt;Welcome:&lt;br /&gt;        &lt;asp:label id="eMail" runat="server"&gt;username&lt;/asp:label&gt;  &lt;/span&gt;&lt;br /&gt;     &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;     &lt;td bg="" style="color: rgb(211, 201, 199);" align="right" height="70" width="100%"&gt;&lt;br /&gt;        &lt;span style="font-size: 6px; color: rgb(255, 255, 255);"&gt;&lt;br /&gt;        &lt;asp:label id="siteName" runat="server"&gt;Micro-site Banner&lt;/asp:label&gt;  &lt;/span&gt;&lt;br /&gt;     &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; &lt;h4 class="dtH1"&gt; DatabaseGateway.cs &lt;/h4&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;This class encapsulates all access to the database for these pages. This is an example of a &lt;i&gt;Table Data Gateway&lt;/i&gt; [Fowler03] which represents the model code for the pages in this application. &lt;/p&gt; &lt;pre class="code"&gt;using System;&lt;br&gt;using System.Collections;&lt;br&gt;using System.Data;&lt;br&gt;using System.Data.SqlClient;&lt;br&gt;&lt;br&gt;public class DatabaseGateway&lt;br&gt;{&lt;br&gt;  public static string RetrieveAddress(string name)&lt;br&gt;  {&lt;br&gt;        String address = null;&lt;br&gt;&lt;br&gt;        String selectCmd =&lt;br&gt;              String.Format("select * from webuser where (id = '{0}')",&lt;br&gt;              name);&lt;br&gt;&lt;br&gt;        SqlConnection myConnection =&lt;br&gt;              new SqlConnection("server=(local);database=webusers;Trusted_Connection=yes");&lt;br&gt;        SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);&lt;br&gt;&lt;br&gt;        DataSet ds = new DataSet();&lt;br&gt;        myCommand.Fill(ds,"webuser");&lt;br&gt;        if(ds.Tables["webuser"].Rows.Count == 1)&lt;br&gt;        {&lt;br&gt;              DataRow row = ds.Tables["webuser"].Rows[0];&lt;br&gt;              address = row["address"].ToString();&lt;br&gt;        }&lt;br&gt;&lt;br&gt;        return address;&lt;br&gt;  }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;/pre&gt; &lt;h4 class="dtH1"&gt; &lt;p&gt;Page1.aspx&lt;/p&gt; &lt;/h4&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The following is an example of how to use the common functionality in a page: &lt;/p&gt;  &lt;pre class="code"&gt;&lt;title&gt;Page-1&lt;/title&gt;&lt;br /&gt;&amp;lt;%@ Page language="c#" Codebehind="Page1.aspx.cs" AutoEventWireup="false" Inherits="Page1" %&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;     &lt;br /&gt;  &lt;br /&gt;     &lt;!-- #include virtual="BasePage.inc" --&gt;&lt;br /&gt;     &lt;form id="Page1" method="post" runat="server"&gt;&lt;br /&gt;        &lt;h1&gt;Page:&lt;br&gt;           &lt;asp:label id="pageNumber" runat="server"&gt;NN&lt;/asp:label&gt;&lt;/h1&gt;&lt;br /&gt;     &lt;/form&gt;&lt;br /&gt;  &lt;/pre&gt;The following directive from the file loads the common HTML for the header:&lt;pre class="code"&gt;&lt;br /&gt;&lt;!-- #include virtual="BasePage.inc" --&gt;&lt;br /&gt;&lt;/pre&gt; &lt;h4 class="dtH1"&gt; &lt;p&gt;Page1.aspx.cs&lt;/p&gt; &lt;/h4&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The code-behind class must inherit from the &lt;b&gt;BasePage&lt;/b&gt; class and then implement the &lt;b&gt;PageLoadEvent&lt;/b&gt; method to do any page-specific loading. In this example, the page-specific activity is to assign the number 1 to the &lt;b&gt;pageNumber&lt;/b&gt; label. &lt;/p&gt;  &lt;pre class="code"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;public class Page1 : BasePage&lt;br /&gt;{&lt;br /&gt;  protected System.Web.UI.WebControls.Label pageNumber;&lt;br /&gt;&lt;br /&gt;  protected override void PageLoadEvent(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;     pageNumber.Text = "1";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Testing Considerations&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;The&lt;br /&gt;dependence on the ASP.NET runtime makes testing of the implementation&lt;br /&gt;difficult. It is not possible to instantiate classes that inherit from&lt;br /&gt;System.Web.UI.Page or the other various classes contained in the&lt;br /&gt;environment. This makes it impossible to unit test the individual&lt;br /&gt;pieces of the application in isolation. The only remaining way to test&lt;br /&gt;this implementation automatically is to generate HTTP requests and then&lt;br /&gt;retrieve the HTTP response and determine if the response is correct.&lt;br /&gt;This approach is prone to error because you are comparing the text of&lt;br /&gt;the response with expected text. &lt;/p&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Resulting Context&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;The built-in ASP.NET page controller functionality results in the following benefits and liabilities:&lt;/p&gt; &lt;h3 class="dtH1"&gt; &lt;p&gt;Benefits&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Takes advantage of framework features&lt;/b&gt;.&lt;br /&gt;The page controller functionality is built into ASP.NET and can be&lt;br /&gt;easily extended by connecting application-specific actions to the&lt;br /&gt;events exposed by the controller. It is also easy to separate the&lt;br /&gt;controller-specific code from the model and view code by using the&lt;br /&gt;code-behind feature. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Explicit URLs&lt;/b&gt;. The URL&lt;br /&gt;that the user enters refers to an actual page in the application. This&lt;br /&gt;means that the pages can be bookmarked and entered later. The URLs also&lt;br /&gt;tend to have fewer parameters making them easier for users to enter. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Increases modularity and reuse&lt;/b&gt;. The Common Look and Feel example demonstrated how you could reuse &lt;b&gt;BasePage&lt;/b&gt; for many pages without having to modify the &lt;b&gt;BasePage&lt;/b&gt; class or HTML file.&lt;/p&gt;&lt;/li&gt; &lt;h3 class="dtH1"&gt; &lt;p&gt;Liabilities&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Requires code changes&lt;/b&gt;.&lt;br /&gt;To share common functionality, as demonstrated in the Common Look and&lt;br /&gt;Feel example, the individual pages have to be modified to inherit from&lt;br /&gt;the newly defined base class instead of &lt;b&gt;System.Web.UI.Page&lt;/b&gt;. The &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesInterceptingFilter.asp"&gt;&lt;i&gt;Intercepting Filter&lt;/i&gt;&lt;/a&gt; pattern describes a mechanism for adding common functionality by changing the Web.config file and not the pages themselves.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Uses inheritance&lt;/b&gt;.&lt;br /&gt;The Common Look and Feel example uses inheritance to share the&lt;br /&gt;implementation across multiple pages. Most programmers who learn&lt;br /&gt;object-oriented programming initially like inheritance. However, using&lt;br /&gt;inheritance to share implementation can often lead to software that is&lt;br /&gt;difficult to change. If the base class become complicated with&lt;br /&gt;conditional logic, it is better to introduce helper classes or to&lt;br /&gt;consider using &lt;i&gt;Front Controller&lt;/i&gt; instead. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;Difficult to test&lt;/b&gt;.&lt;br /&gt;Because the page controller is implemented in ASP.NET, it is difficult&lt;br /&gt;to test in isolation. To improve the testability, you should separate&lt;br /&gt;as much functionality out of the ASP.NET - specific code in classes&lt;br /&gt;that do not depend on ASP.NET. This enables you to test without having&lt;br /&gt;to start the ASP.NET runtime. &lt;/p&gt;&lt;/li&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Related Patterns&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;For more information, see the following related patterns:&lt;/p&gt; &lt;li&gt;&lt;p&gt;&lt;i&gt;Template Method&lt;/i&gt; [Gamma95]. The &lt;b&gt;BasePage&lt;/b&gt; class and the &lt;b&gt;Page_Load&lt;/b&gt; method are an example implementation of this pattern. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesInterceptingFilter.asp"&gt;&lt;i&gt;Intercepting Filter&lt;/i&gt;&lt;/a&gt;&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt;&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;/li&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Acknowledgments&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;[Gamma95] Gamma, Helm, Johnson, and Vlissides. &lt;i&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/i&gt;. Addison-Wesley, 1995.&lt;/p&gt; &lt;p&gt;[Reilly02] Reilly, Douglas J. &lt;i&gt;Designing Microsoft ASP.NET Applications.&lt;/i&gt; Microsoft Press, 2002.&lt;/p&gt; &lt;p&gt;[Fowler03] Fowler, Martin. &lt;i&gt;Patterns of Enterprise Application Architecture&lt;/i&gt;. Addison-Wesley, 2003.&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-112555865224183216?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555865224183216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555865224183216'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/09/implementing-page-controller-in-aspnet.html' title='Implementing Page Controller in ASP.NET'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112555860596601833</id><published>2005-09-01T14:09:00.000+07:00</published><updated>2005-09-01T14:10:05.990+07:00</updated><title type='text'>Page Controller</title><content type='html'>&lt;h1 class="dtH1"&gt;Page Controller&lt;/h1&gt;  &lt;p&gt; &lt;table bgcolor="#eeeeee" cellpadding="0" cellspacing="0"&gt; &lt;tbody&gt;&lt;tr&gt; &lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_TL.gif" border="0" height="26" width="26" /&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_A1-up.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_I1.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Architecture Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_A.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_1.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_2.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_3.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_4.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/designpatoverview.aspx"&gt;&lt;img alt="Design Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_D-up.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_5.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_6-up.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_7.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_8.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/implpatoverview.aspx"&gt;&lt;img alt="Implementation Row" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_I.gif" border="0" height="26" width="26" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Data Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_9.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Application Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_10.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Deployment Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_11.gif" border="0" height="26" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"&gt;&lt;img alt="Infrastructure Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_12.gif" border="0" height="26" width="45" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;&lt;img alt="?" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_BL.gif" border="0" height="27" width="26" /&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo1.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo2.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo3.gif" border="0" height="27" width="37" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://msdn.microsoft.com/practices"&gt;&lt;img alt="Complete List of patterns &amp;amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo4.gif" border="0" height="27" width="45" /&gt;&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt; &lt;/p&gt;  &lt;p&gt;Version 1.0.1&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.gotdotnet.com/Community/Workspaces/Workspace.aspx?id=08a23452-ac75-4e12-93c1-ec4e31e2de2f"&gt;&lt;span style="color:gray;"&gt;GotDotNet community for collaboration on this pattern&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/practices/"&gt;&lt;span style="color:gray;"&gt;Complete List of patterns &amp; practices&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Context&lt;/p&gt; &lt;/h2&gt;  &lt;p&gt;You decided to use the &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesMVC.asp"&gt;&lt;i&gt;Model-View-Controller&lt;/i&gt;&lt;/a&gt;&lt;i&gt; (MVC)&lt;/i&gt; pattern to separate the user interface components of your dynamic Web application from the business logic. The application you are building constructs the Web pages dynamically, but the navigation between the pages is mostly static.&lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Problem&lt;/p&gt; &lt;/h2&gt;  &lt;p&gt;How do you best structure the controller for moderately complex Web applications so that you can achieve reuse and flexibility while avoiding code duplication?&lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Forces&lt;/p&gt; &lt;/h2&gt;  &lt;p&gt;The following forces act on a system within this context and must be reconciled as you consider a solution to the problem:&lt;/p&gt;  &lt;table class="clsContainer" float="left" border="0" cellpadding="15" cellspacing="0" width="100%"&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;li&gt;&lt;p&gt; The &lt;i&gt;MVC &lt;/i&gt;pattern often focuses primarily on the separation between the model and the view, while paying less attention to the controller. In many rich-client scenarios, the separation between controller and view is less critical and is often omitted [Fowler03]. In a thin-client application, however, view and controller are inherently separated because the presentation occurs in the client browser, whereas the controller is part of the server-side application. The controller, therefore, warrants a closer examination.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; In dynamic Web applications, multiple user actions can lead to different controller logic, followed by the same page presentation. For example, in a simple Web-based e-mail application, both sending a message and deleting a message from the inbox is likely to return the user to the (refreshed) inbox page. Although the same page is rendered after either activity, the application must perform a different action, based on the previous page and the button the user clicked.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; The code that renders most dynamic Web pages involves very similar steps: verifying user authentication, extracting the page parameters from the query string or the form fields, gathering session information, retrieving data from a data source, rendering the dynamic portion of the page, and adding applicable headers and footers. This can lead to a significant amount of code duplication.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; Scripted server pages (such as ASP.NET) may be easy to create, but can introduce a number of disadvantages as the application grows. Scripted pages provide poor separation between controller and the view, which reduces the opportunities for reuse. For example, if multiple actions lead to the same page, it is difficult to reuse the display code across multiple controllers, because it is intertwined with the controller code. Scripted server pages that intersperse business logic and presentation logic are also more difficult to test and debug. Finally, developing scripted server pages requires expertise both in developing business logic and in rendering visually appealing and efficient HTML pages; these two skill sets are rarely possessed by a single person. Due to these considerations, it makes sense to minimize the scripted server-page code and develop business logic in actual classes.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; As described in the &lt;i&gt;MVC &lt;/i&gt;pattern, testing user interface code tends to be time-consuming and tedious. If you can separate user-interface-specific code from the actual business logic, testing the business logic becomes simpler and more repeatable. This is true not only for the presentation portion, but also for the controller part of an application.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt; Common appearance and navigation tend to improve usability and brand recognition of a Web application. However, common appearance can lead to repetitive presentation code, especially if the code is embedded inside scripted server pages. Therefore, you need a mechanism for improving reuse of presentation logic across pages.&lt;/p&gt;&lt;/li&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Solution&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;Use the &lt;i&gt;Page Controller &lt;/i&gt;pattern to accept input from the page request, invoke the requested actions on the model, and determine the correct view to use for the resulting page. Separate the dispatching logic from any view-related code. Where appropriate, create a common base class for all page controllers to avoid code duplication and increase consistency and testability. Figure 1 shows how the page controller relates to the model and view.&lt;/p&gt; &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Des_Page%20Controller_Fig01.gif" /&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 1: Page Controller structure&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;The page controller receives a page request, extracts any relevant data, invokes any updates to the model, and forwards the request to the view. The view in turn depends on the model for retrieval of data to be displayed. Defining a separate page controller isolates the model from the specifics of the Web request - for example, session management, or the use of query strings or hidden form fields to pass parameters to the page. In this basic form, you create a controller for every link in the Web application. This keeps the controllers simple, because you only have to concern yourself with one action at a time. &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;Creating a separate controller for each Web page (or action) can lead to significant code duplication. Therefore, you should create a &lt;b&gt;BaseController&lt;/b&gt; class to incorporate common functions such as validating parameters (see Figure 2). Each individual page controller can inherit this common functionality from &lt;b&gt;BaseController&lt;/b&gt;. In addition to inheriting from a common base class, you can also define a set of helper classes that the controllers can call to perform common functions.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Des_Page%20Controller_Fig02.gif" /&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 2: Using BaseController to eliminate code duplication&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;This approach works well if most pages are similar and you can pull the common functions into a single base class. The more page variations you have, the more levels you may have to inject into the inheritance tree. Let's say that all pages parse parameters, but only pages that display lists retrieve data from the database, while pages that require data entry update the model, rather than retrieve data. You could now introduce two new base classes, &lt;b&gt;ListController&lt;/b&gt; and &lt;b&gt;DataEntryController&lt;/b&gt;, that both inherit from &lt;b&gt;BaseController&lt;/b&gt;. The list pages could then inherit from &lt;b&gt;ListController&lt;/b&gt;, and the data entry pages could inherit from &lt;b&gt;DataEntryController&lt;/b&gt;. Although this approach may work well in this simple example, the inheritance tree can get rather deep and complicated if you are dealing with a real-life businesses application. You may be tempted to add conditional logic into the base classes to accommodate some of the variants, but doing so violates the principles of encapsulation and makes the base classes a notorious bottleneck for any changes to the system. Therefore, you should consider using helper classes or the &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt; pattern as your application becomes more complex.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;Using a page controller for a Web application is such a common need that most Web application frameworks provide a default implementation of the page controller. Most frameworks incorporate the page controller in the form of a server page (for example, ASP, JSP, and PHP). Server pages actually combine the functions of view and controller and do not provide the desired separation between the presentation code and the controller code. Unfortunately, some of the frameworks make it very easy to blend together view-related code with controller-related code and make it difficult to properly separate the controller logic. As a result, the &lt;i&gt;Page Controller&lt;/i&gt; approach has developed a bad reputation with many developers. Now, many developers associate &lt;i&gt;Page Controller&lt;/i&gt; with bad design and &lt;i&gt;Front Controller&lt;/i&gt; with good design. This perception, in fact, resulted from a specific (faulty) implementation choice; both &lt;i&gt;Page Controller&lt;/i&gt; and the &lt;i&gt;Front Controller &lt;/i&gt;are perfectly viable architectural choices.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;Therefore, it is preferable to separate the controller logic into separate classes that can be called from the server page. The ASP.NET page framework provides an excellent mechanism for achieving this separation, called &lt;i&gt;code-behind classes&lt;/i&gt;. (See &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/ImpPageController.asp"&gt;&lt;i&gt;Implementing Page Controller in ASP.NET&lt;/i&gt;&lt;/a&gt;). &lt;/p&gt;  &lt;h3 class="dtH1"&gt; &lt;p&gt;Variants&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;In most cases, the page controller is dependent on the specifics of an HTTP-based Web request. As a result, the page controllercode usually contains references to HTTP headers, query strings, form fields, multipart form requests, and so forth. This makes it very hard to test the controller code outside the Web application framework. The only option is to test the controller by simulating HTTP requests and parsing the results. This type of testing is both time-consuming and error prone. Therefore, to improve testability you could separate the Web-dependent and the Web-independent code into two separate classes (see Figure 3). &lt;/p&gt;  &lt;p&gt;&lt;img src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Des_Page%20Controller_Fig03.gif" /&gt;&lt;/p&gt; &lt;p&gt;&lt;head3&gt; Figure 3: Separating the Web-dependent and Web-independent code&lt;/head3&gt;&lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;In this example, &lt;b&gt;AspNetController&lt;/b&gt; encapsulates all dependencies on the application framework (ASP.NET). For example, it can extract all incoming parameters from the Web request and pass it to &lt;b&gt;BaseController&lt;/b&gt; in a way that is independent from the Web interface (for example, in a collection). This approach not only improves testability, but enables you to reuse the controller code with other user interfaces, for example a rich-client interface or a custom scripting language.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;&lt;p&gt;The downside of this approach is the additional overhead. You now have an additional class, and each request has to go through a translation before it can be serviced. Therefore, you should keep the environment-specific part of the controller as thin as possible and consider the tradeoffs between reduced dependencies and more efficient development and execution.&lt;/p&gt;  &lt;h2 class="dtH1"&gt; &lt;p&gt;Example &lt;/p&gt; &lt;/h2&gt; &lt;p&gt;See &lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/ImpPageController.asp"&gt;&lt;i&gt;Implementing Page Controller in ASP.NET&lt;/i&gt;&lt;/a&gt;.&lt;/p&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Resulting Context&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;Using the &lt;i&gt;Page Controller&lt;/i&gt; pattern results in a number of benefits and liabilities.&lt;/p&gt; &lt;h3 class="dtH1"&gt; &lt;p&gt;Benefits&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Simplicity&lt;/b&gt;. Because each dynamic Web page is handled by a specific controller, the controllers have to deal with only a limited scope and can remain simple. Because each page controller deals with only a single page, &lt;i&gt;Page Controller &lt;/i&gt;is particularly well-suited for Web applications with simple navigation.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Built-in framework features&lt;/b&gt;. In its most basic form, the controller is already built into most Web application platforms. For example, if the user clicks a link in a Web page that leads to a dynamic page generated by an ASP.NET script, the Web server analyzes the URL associated with the link and executes the associated ASP.NET page. In effect, the ASP.NET page is the controller for the action taken by the user. The ASP.NET page framework also provides code-behind classes to execute controller code. Code-behind classes provide better separation between the controller and the view and also allow you to create a controller base class that incorporates common functionality across all controllers. For an example, see &lt;i&gt;Implementing Page Controller in ASP.NET&lt;/i&gt;.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Increased reuse&lt;/b&gt;. Creating a controller base class reduces code duplication and enables you to reuse common code across page controllers. You can reuse code by implementing recurring logic in the base class. This logic is then automatically inherited by all concrete &lt;i&gt;Page Controller &lt;/i&gt;objects. If the implementation of the logic varies from page to page, you can still use &lt;i&gt;Template Method&lt;/i&gt; and implement the basic execution structure in the base class; the implementation of specific substeps may vary from page to page.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Expandability&lt;/b&gt;. You can expand a page controller quite easily by using helper classes. If the logic inside the controller becomes too complex, you can delegate some of the logic to helper classes. Helper classes also provide another mechanism for reuse, besides inheritance.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Separation of developer responsibilities&lt;/b&gt;. Using a &lt;i&gt;Page Controller&lt;/i&gt; class helps separate responsibilities among members of the development team. The developer of the controller must be familiar with the domain model and the business logic implemented by the application. The designer of the view, on the other hand, can focus on the presentation style of the results.&lt;/p&gt;&lt;/li&gt; &lt;h3 class="dtH1"&gt; &lt;p&gt;Liabilities&lt;/p&gt; &lt;/h3&gt; &lt;p&gt; &lt;/p&gt; &lt;p&gt; &lt;/p&gt;&lt;p&gt;Due to its simplicity, &lt;i&gt;Page Controller&lt;/i&gt; is the default implementation for most dynamic Web applications. However, you should be aware of the following limitations:&lt;/p&gt;  &lt;li&gt;&lt;p&gt;&lt;b&gt; One controller per page&lt;/b&gt;. The key constraint of &lt;i&gt;Page Controller&lt;/i&gt; is that you create one controller for each Web page. This works well for applications with a static set of pages and a simple navigation path. Some more complex applications require dynamic configuration of pages and navigation maps between them. Spreading this logic across many page controllers would make the application hard to maintain, even if some of the logic could be pulled into the base controller. In addition, the built-in features of the Web framework may reduce the amount of flexibility you have in naming URLs and resource paths (even though you can compensate for some of this with low-level mechanisms like ISAPI filters). In these scenarios, consider using &lt;i&gt;Front Controller&lt;/i&gt; that intercepts all Web requests and forwards the request to the appropriate handler, based on configurable rules.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Deep inheritance trees&lt;/b&gt;. Inheritance seems to be one of the most loved and most hated features of object-oriented programming. Using inheritance alone to reuse common functionality may lead to inflexible inheritance hierarchies. For more detail, see &lt;i&gt;Implementing Page Controller in ASP.NET&lt;/i&gt;.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt; Dependency on the Web framework&lt;/b&gt;. In the basic form, the page controller still depends on the Web application environment and cannot be tested independently. You can use a wrapper mechanism to decouple the Web-dependent part, but doing so requires an additional level of indirection.&lt;/p&gt;&lt;/li&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Testing Considerations&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;Because &lt;i&gt;Page Controller&lt;/i&gt; is dependent on specifics of the Web application framework (for example, query strings and HTTP headers), you cannot instantiate and test the controller classes outside the Web framework. If you want to run a suite of automated unit tests on the controller class, you would have to start the Web application server for each test case. You would then have to submit HTTP requests in a format that executes the desired function. This configuration introduces many dependencies and side effects into the test. To improve testability, consider separating the business logic (including controller logic as it becomes more complex) from the Web-dependent code.&lt;/p&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Related Patterns&lt;/p&gt; &lt;/h2&gt; &lt;p&gt;For more information, see the following related patterns:&lt;/p&gt; &lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesInterceptingFilter.asp"&gt;&lt;i&gt;Intercepting Filter&lt;/i&gt;&lt;/a&gt;. This pattern is another construct to implement recurring functionality inside a Web application. The Web server framework can pass each request through a configurable chain of filters before passing it to the controller. Filters tend to deal with lower-level functions such as decoding, authentication, and session management, whereas &lt;i&gt;Page Controller &lt;/i&gt;deals with application functionality. Filters also are not usually page-specific.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesFrontController.asp"&gt;&lt;i&gt;Front Controller&lt;/i&gt;&lt;/a&gt;. This pattern is a more complex, but also more powerful alternative to &lt;i&gt;Page Controller&lt;/i&gt;. &lt;i&gt;Front Controller&lt;/i&gt; defines a single controller for all page requests, which enables it to make navigational decisions that span multiple pages. &lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;&lt;a href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesMVC.asp"&gt;&lt;i&gt;Model-View-Controller&lt;/i&gt;&lt;/a&gt;. &lt;i&gt;Page Controller&lt;/i&gt; is an implementation variant of the controller portion of &lt;i&gt;MVC&lt;/i&gt;.&lt;/p&gt;&lt;/li&gt; &lt;h2 class="dtH1"&gt; &lt;p&gt;Acknowledgments&lt;/p&gt; &lt;/h2&gt; &lt;li&gt;&lt;p&gt;[Fowler03] Fowler, Martin. &lt;i&gt;Patterns of Enterprise Application Architecture&lt;/i&gt;. Addison-Wesley, 2003.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;[Gamma95] Gamma, Helm, Johnson, and Vlissides. &lt;i&gt;Design Patterns: Element of Reusable Object-Oriented Software&lt;/i&gt;. Addison-Wesley, 1995.&lt;/p&gt;&lt;/li&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;&lt;!--
google_ad_client = "pub-3285494640947731";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text_image";
google_ad_channel ="";
google_color_border = "578A24";
google_color_bg = "CCFF99";
google_color_link = "00008B";
google_color_url = "00008B";
google_color_text = "000000";
//--&gt;&lt;/script&gt;
&lt;script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js"&gt;
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/15864493-112555860596601833?l=lethanhhungreading.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555860596601833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/15864493/posts/default/112555860596601833'/><link rel='alternate' type='text/html' href='http://lethanhhungreading.blogspot.com/2005/09/page-controller.html' title='Page Controller'/><author><name>hungle</name><uri>http://www.blogger.com/profile/17516924063901849503</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://photos1.blogger.com/img/145/5635/640/tetsu1.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-15864493.post-112516545002409616</id><published>2005-08-28T15:55:00.000+07:00</published><updated>2005-08-28T00:57:30.050+07:00</updated><title type='text'>Discover the Design Patterns You're Already Using in the .NET Framework</title><content type='html'>Recently, Microsoft has placed increasing emphasis on design patterns. If you are unfamiliar with patterns, suddenly being inundated with new terms and foreign-looking UML diagrams can be overwhelming. This emphasis on patterns, however, doesn't represent a shift in methodology so much as a change in vocabulary. The Microsoft&lt;sup class="clsSmall"&gt;®&lt;/sup&gt; .NET Framework base class library (BCL) already makes extensive use of patterns, and you are probably familiar with the most common ones, even though you might not realize it yet. &lt;p&gt;In this article, I'll cover a basic overview of several common design patterns and how they are used in the BCL and other areas of the .NET Framework. In doing so, you can discover some of the motivation for why the Framework is designed the way it is, as well as make the abstract concepts of the patterns themselves more intuitively understandable.&lt;/p&gt; &lt;p&gt;Most of the patterns I'll be covering come from the canonical reference, &lt;i&gt;Design Patterns&lt;/i&gt; by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, (Addison-Wesley, 1995). These authors are collectively known as the Gang of Four. The Gang of Four didn't invent these patterns, but they documented and formalized the good work others had been doing since the beginning of software development.&lt;/p&gt; &lt;p&gt;If you are already familiar with some of these patterns, feel free to read about those you aren't familiar with, since each section is relatively independent. The section on ASP.NET-related patterns requires familiarity with the request pipeline, a basic overview of which is provided in that section.&lt;/p&gt; &lt;p&gt;Within the .NET Framework, the use of some patterns is so prevalent that they have been built into programming languages themselves, instead of just represented by the class libraries. The first two patterns I will discuss, the Observer and the Iterator, are supported by various language features of both C# and Visual Basic&lt;sup class="clsSmall"&gt;®&lt;/sup&gt; .NET. As you will see, they are an integral part of many common programming tasks.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S2"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Observer Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Good object-oriented design emphasizes both encapsulation and loose coupling. In other words, classes should keep internal details private and also minimize their strict dependencies. In most applications, classes don't work in isolation; they interact with many other classes. A common scenario of class interaction occurs when one class (the Observer) needs to be notified when something changes in another (the Subject). For example, several Windows&lt;sup class="clsSmall"&gt;®&lt;/sup&gt; Forms controls might need to update their display after a button is clicked. A simple solution would be to have the Subject call a specific method of the Observer whenever a change in state occurs. This introduces a host of problems, however. Now, since the Subject needs to know which method to call, it is tightly coupled to that specific Observer. Furthermore, if you need to add more than one Observer, you have to continue to add code for each method call to the Subject. If the number of Observers changes dynamically, this gets even more complex. You'll quickly end up with a brittle mess that's difficult to maintain.&lt;/p&gt; &lt;p&gt;Applying the Observer pattern helps to resolve this problem efficiently. You can decouple the Subject from the Observers so that Observers of any variety can easily be added and removed, at both design time and run time. The Subject maintains a list of interested Observers. Each time the Subject's state changes, it calls the Notify method on each Observer. Figure 1 shows a sample implementation. All classes designed to act as Observers implement the ICanonicalObserver interface, and all Subjects must derive from CanonicalSubjectBase. If a new Observer wants to monitor a Subject, the Add method easily handles this without having to change any code in the Subject class. Note also that each Subject only directly depends on the ICanonicalObserver interface, not any specific Observer.&lt;/p&gt; &lt;p&gt;While the Gang of Four's Observer pattern solves some of these problems, there are still some roadblocks, since subjects must inherit from a specific base class and Observers must implement a special interface. Thinking back to the Windows Forms button example, a solution emerges. The .NET Framework introduces delegates and events to solve these problems. If you have done any programming for ASP.NET or Windows Forms, then you have probably worked with events and event handlers. Events act as the Subject, while delegates act as Observers. Figure 2 shows an example of the Observer pattern, making use of events.&lt;/p&gt; &lt;p&gt;The Windows Forms Button control exposes a Click event which gets raised whenever the button is clicked. Any class designed to react to this event just needs to register a delegate with that event. The Button class doesn't depend on any of the potential Observers, and each Observer only needs to know the correct type of the delegate for the event (EventHandler, in this case). Since EventHandler is a delegate type and not an interface, each Observer doesn't need to implement an extra interface. Assuming it already contains a method with a compatible signature, it only needs to register that method with the event of the Subject. Through delegates and events, the Observer pattern lets you decouple Subjects and their Observers.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S3"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Iterator Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Many programming tasks involve manipulating collections of objects. Whether these collections are simple lists or something more complex such as binary trees, you'll often need some way to get access to each object in the collection. In fact, depending on the collection, you may want several ways to access each object such as front to back, back to front, preorder or postorder. To keep the collection simple, the traversal code itself is often in its own class.&lt;/p&gt; &lt;p&gt;One of the most basic ways to store a list of objects is in an array. Array types are built into both Visual Basic .NET and C#. Both languages also have a loop structure that aids in iterating over arrays: foreach in C# and For Each in Visual Basic .NET. Here's an easy example of iterating over arrays: &lt;/p&gt; &lt;pre class="clsCode"&gt;int[] values = new int[] {1, 2, 3, 4, 5};&lt;br /&gt;foreach(int i in values)&lt;br /&gt;{&lt;br /&gt;   Console.Write(i.ToString() + " ");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; These statements make use of the iterator for the array behind the scenes. All you need to know is that you are guaranteed to have the loop run exactly once for each item in the array. &lt;p&gt;To make those statements work, the object referenced in the In expression must implement IEnumerable. Any collection of objects that implements the IEnumerable interface can be traversed (enumerated). This interface has a single method, GetEnumerator, that returns an object which implements IEnumerator. The IEnumerator class contains the code necessary to iterate through the collection. It has a property for the current object (Current) and methods to advance to the next object as well as start over (MoveNext, and Reset). All of the collection classes in the System.Collections namespace, as well as arrays, implement IEnumerable and can therefore be iterated over.&lt;/p&gt; &lt;p&gt;If you examine the Microsoft intermediate language (MSIL) generated by the C# compiler for any code that uses foreach, you can see that in most cases it just uses the IEnumerator to do the iteration (certain types, such as arrays and strings, are special cased by the compiler). Here you can see the IEnumerator approach for iterating over the same array shown previously: &lt;/p&gt; &lt;pre class="clsCode"&gt;int[] values = new int[] {1, 2, 3, 4, 5};&lt;br /&gt;IEnumerator e = ((IEnumerable)values).GetEnumerator();&lt;br /&gt;while(e.MoveNext())&lt;br /&gt;{&lt;br /&gt;   Console.Write(e.Current.ToString() + " ");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;The .NET Framework uses the IEnumerable and IEnumerator interfaces to implement the Iterator pattern. The Iterator pattern lets you easily traverse a collection without exposing the inner workings of that collection. An Iterator class, an implementer of IEnumerator, is a separate class from the collection, which implements IEnumerable. The Iterator class maintains the state of the traversal (including what the current item is and whether or not there are more items to be traversed) outside of the collection itself. The algorithm for the traversal is contained in the Iterator as well. This way you can simultaneously have multiple Iterators, each traversing the same collection in wildly different ways, without adding any complexity to the collection class itself.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S4"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Decorator Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Any useful executable program involves either reading input, writing output, or both. Regardless of the source of the data being read or written, it can be treated abstractly as a sequence of bytes. .NET uses the System.IO.Stream class to represent this abstraction. Whether the data involves characters in a text file, TCP/IP network traffic, or something else entirely, chances are you will have access to it via a Stream. Since the class for working with file data (FileStream) and the class for working with network traffic (NetworkStream) both inherit from Stream, you can easily write code that processes the data independent of its origins. Here's a method for printing out some bytes from a Stream to the console: &lt;/p&gt; &lt;pre class="clsCode"&gt;public static void PrintBytes(Stream s)&lt;br /&gt;{&lt;br /&gt;   int b;&lt;br /&gt;   while((b = fs.ReadByte()) &gt;= 0)&lt;br /&gt;   {&lt;br /&gt;       Console.Write(b + " ");&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;Reading a single byte at a time is typically not the most efficient way to access a stream. For example, hard drives are capable of (and optimized for) reading continuous blocks of data from the disk in a big chunk. If you know you are going to be reading several characters, it is better to read a chunk from the disk all at once and then consume the chunk from memory byte by byte. The Framework includes the BufferedStream class for doing just that. The constructor for BufferedStream takes as the parameter whatever stream you would like buffered access to. BufferedStream overrides the main methods of Stream, such as Read and Write, to provide more functionality. Since it is still a child class of Stream, you can use it the same as any other Stream (note that FileStream includes its own buffering capabilities). Similarly, you can use System.Security.Cryptography.CryptoStream to encrypt and decrypt Streams on the fly, without the rest of the application needing to know anything more than the fact that it is a Stream. Figure 3 shows several calls to my printing method using different Streams.&lt;/p&gt; &lt;div style="margin: 5px 0px 10px 5px; width: 210px; float: right;"&gt;&lt;img src="http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/fig04.gif" alt="Figure 4 Using the Decorator Pattern" height="191" width="210" /&gt;&lt;br /&gt;&lt;span class="clsCap"&gt;Figure 4&lt;/span&gt; &lt;span class="clsCaptxt"&gt;Using the Decorator Pattern&lt;/span&gt;&lt;/div&gt; &lt;p&gt;This ability to dynamically attach new functionality to objects transparently using composition is an example of the Decorator pattern, as shown in &lt;span class="clsFigs"&gt;Figure 4&lt;/span&gt;. Given any instance of Stream, you can add the capability for buffered access by wrapping it in a BufferedStream, without changing the interface to the data. Since you are just composing objects, this can be done at run time, rather than using a technique like inheritance, which is a compile-time decision. The core functionality is defined either by an interface or by an abstract class (like Stream) from which all the Decorators derive. The Decorators themselves implement (or override) the methods in the interface (or base class) to provide the extra functionality. BufferedStream, for example, overrides Read to read from a buffer fed by the wrapped Stream, instead of reading from that Stream directly. As Figure 3 illustrates, any composition of Decorators, no matter how complex, can still be used as if it were only the base class.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S5"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Adapter Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;One of the strengths of the .NET Framework is backward compatibility. From .NET-based code you can easily call legacy COM objects and vice versa. In order to use a COM component in your project, all you have to do is add a reference to it via the Add Reference dialog in Visual Studio .NET. Behind the scenes, Visual Studio&lt;sup class="clsSmall"&gt;®&lt;/sup&gt; .NET invokes the tlbimp.exe tool to create a Runtime Callable Wrapper (RCW) class, contained in an interop assembly. Once the reference has been added (and the interop assembly has been generated for you), the COM component can be used like any other class in managed code. If you were looking at code someone else had written without seeing the list of references (and without examining metadata associated with the classes or their implementation), you would be unable to tell which classes were written in a .NET-targeted language and which were COM components.&lt;/p&gt; &lt;p&gt;The magic that makes this happen is contained in the RCW. COM components have different error handling mechanisms and also make use of different data types. For example, strings in the .NET Framework use the System.String class while COM might use a BSTR. When calling a COM component with a string parameter from .NET-based code, though, you can pass in a System.String just like you would to any other similar managed code method. Inside the RCW, this System.String is converted into a format that the COM component expects, like a BSTR, before the COM call is made. Similarly, a method call on a COM component typically returns an HRESULT to indicate success or failure. When a COM method call returns an HRESULT that indicates that the call failed, the RCW turns this into an exception (by default), so it can be handled like all other managed code errors.&lt;/p&gt; &lt;p&gt;By allowing managed classes and COM components to interact despite their interface differences, RCWs are an example of the Adapter pattern. The Adapter pattern lets you adapt one interface to another. COM doesn't understand the System.String class, so the RCW adapts it to something that it can understand. Even though you can't change how a legacy component works, you can still interact with it. Adapters are frequently used like this.&lt;/p&gt; &lt;p&gt;The Adapter class itself wraps an Adaptee, translating all calls from the client into the appropriate format and sequence of calls. Though this sounds similar to the Decorator, there are several key differences. With a Decorator, the interfaces of the objects you're composing are the same, while the entire point of an Adapter is to allow you to change interfaces.Adapters also have a definite sequence to them; the Adaptee must be contained by the Adapter. A Decorator class doesn't need to know whether it is wrapped by 1 or 500 other classes, since the interfaces are all the same. As a result, the use of Decorators can be transparent to the application, while the use of Adapter cannot.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S6"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Factory Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;There are many cases in the Framework where you can obtain a new instance of a struct or class without calling its constructor yourself. The System.Convert class contains a host of static methods that work like this. To convert an integer to a Boolean, for example, you can call Convert.ToBoolean and pass in the integer. The return value of this method call is a new Boolean set to "true" if the integer was non-zero and "false" otherwise. The Convert class creates the Boolean for you with the correct value. Other type conversion methods work similarly. The Parse methods on Int32 and Double return new instances of those objects set to the appropriate value given only a string.&lt;/p&gt; &lt;p&gt;This strategy for creating new object instances is known as a Factory pattern. Rather than invoking the object's constructor, you can ask the object factory to create the instance for you. That way, the factory class can hide the complexity of object creation (like how to parse a Double out of a string). If you wanted to change the details of creating the object, you'd only have to change the factory itself; you would not have to change every single place in the code where the constructor is called.&lt;/p&gt; &lt;p&gt;These type conversion methods are one variant of this pattern, since you're not required to use the factory to create the objects in question. A more pure example of this pattern is the System.Net.WebRequest class, used to make a request and receive a response from a resource on the Internet. FTP, HTTP, and file system requests are supported by default. To create a request, call the Create method and pass in a URI. The Create method itself determines the appropriate protocol for the request and returns the appropriate subclass of WebRequest: HttpWebRequest, FtpWebRequest (new to the .NET Framework 2.0), or FileWebRequest. The caller doesn't need to know the specifics of each protocol, only how to invoke the factory and work with the WebRequest that gets returned. If the URI changes from an HTTP address to an FTP address, the code won't have to change at all. This is another common use of the Factory pattern. The parent class acts as a factory and returns a specific derived class based on parameters the client passes in. As in the WebRequest example, this hides the complexity of selecting an appropriate derived class from the caller.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S7"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Strategy Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Both Array and ArrayList provide the capability to sort the objects contained in the collection via the Sort method. In fact, ArrayList.Sort just calls Sort on the underlying array. These methods use the QuickSort algorithm. By default, the Sort method will use the IComparable implementation for each element to handle the comparisons necessary for sorting. Sometimes, though, it is useful to sort the same list in different ways. For example, arrays of strings might be sorted with or without case sensitivity. To accomplish this, an overload of Sort exists that takes an IComparer as a parameter; IComparer.Compare is then used for the comparisons. This overload allows users of the class to use any of the built-in IComparers or any of their own making, without having to change or even know the implementation details of Array, ArrayList, or the QuickSort algorithm.&lt;/p&gt; &lt;p&gt;Leaving the choice of comparison algorithm up to the user of the class like this is an example of the Strategy pattern. The use of Strategy lets a variety of different algorithms be used interchangeably. QuickSort itself only requires a way to compare objects to each other. By calling Compare through a provided interface, the caller is free to substitute whatever particular comparison algorithm fits its specific needs. The code for the QuickSort can remain unchanged.&lt;/p&gt; &lt;div style="margin: 5px 0px 10px 5px; width: 192px; float: right;"&gt;&lt;img src="http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/fig05.gif" alt="Figure 5 Strategy in Action" height="79" width="192" /&gt;&lt;br /&gt;&lt;span class="clsCap"&gt;Figure 5&lt;/span&gt; &lt;span class="clsCaptxt"&gt;Strategy in Action&lt;/span&gt;&lt;/div&gt; &lt;p&gt;One of the new generic collections in version 2.0 of the .NET Framework, List&lt;t&gt;, also makes heavy use of the Strategy pattern, shown in &lt;span class="clsFigs"&gt;Figure 5&lt;/span&gt;. In addition to the updated Sort method, the find-related methods, BinarySearch, and others all take parameters that allow parts of the respective algorithms to vary based on the needs of the caller. The use of a Predicate&lt;t&gt; delegate in the FindAll&lt;t&gt; method lets the caller use any method as a filter for the List&lt;t&gt; so long as it takes the appropriate object type and returns a Boolean. Combined with anonymous methods (another new C# language feature in version 2.0), clients can easily filter lists based on properties and methods of the objects in the list, without introducing dependencies into the List&lt;t&gt; class itself. Using the Strategy pattern lets complicated processes like sorting be easily modified to fit a caller's specific purpose, meaning you'll be able to write and maintain less code.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S8"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Composite Pattern in ASP.NET&lt;/span&gt;&lt;br /&gt;&lt;p&gt;The ASP.NET request/response pipeline is a complex system. Patterns are used in the design of the pipeline itself and in the control architecture to effectively balance its performance with extensibility and ease of programming. Before delving into the pipeline, however, I'll examine the patterns used in the programming model itself.&lt;/p&gt; &lt;p&gt;When dealing with collections of objects, there are often operations that are appropriate for both a single object and the entire collection. Think about an ASP.NET control. A control may be a simple single item like a Literal, or it could be composed of a complex collection of child controls, like a DataGrid is. Regardless, calling the Render method on either of these controls should still perform the same intuitive function.&lt;/p&gt; &lt;p&gt;When each item in the collection might itself contain collections of other objects, the use of the Composite pattern is appropriate. Composite is an easy way to represent tree-like collections without having to treat parent and leaf nodes differently.&lt;/p&gt; &lt;p&gt;The canonical example of Composite relies on an abstract base class, Component, that contains both methods for adding and removing children, and the operations common among parents and children. ASP.NET uses this formulation exactly with System.Web.UI.Control. Control represents the Component base class. It has operations for dealing with children (such as the child Controls property) as well as standard operations and properties like Render and Visible. Each object, whether a primitive object (like Literal) or a composite of several objects (like DataGrid), inherits from this base class.&lt;/p&gt; &lt;p&gt;Because the domain of controls is so diverse, there are several intermediate derived classes like WebControl and BaseDataList that serve as base classes for other controls. Though these classes expose additional properties and methods, they still retain the child management functions and core operations inherited from Control. In fact, the use of the Composite pattern helps to hide their complexity, if desired. Regardless of whether a control is a Literal or a DataGrid, the use of Composite means you can just call Render and everything will sort itself out.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S9"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Template Method Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;When the standard library of ASP.NET controls doesn't meet your needs, you have several options on how to create your own. For simple controls that only need to be used in a single project, a user control is often the best choice. When the control is to be used in several Web applications or requires more functionality, a custom server control may be a better fit.&lt;/p&gt; &lt;p&gt;When dealing with custom controls, there are two general types: controls that combine the functionality of several existing controls (called composite controls), and controls with a unique visual representation. The process for creating both of these types is very similar. For composite controls, you create a new class that inherits from one of the control base classes (like Control or WebControl) and then override the CreateChildControls method. In this method you add the controls whose functionality you are combining to the collection of child controls, called Controls. For other custom controls, you override Render instead and use the HtmlTextWriter parameter to output the HTML for your control directly.&lt;/p&gt; &lt;p&gt;Regardless of which style of custom control you choose, you don't have to write any code to handle the functionality that's common to all controls, like loading and saving ViewState at the right time, allowing PostBack events to be handled, and making sure the control lifecycle events are raised in the correct order. The main algorithm for how a control should be loaded, rendered, and unloaded is contained in the control base class.&lt;/p&gt; &lt;p&gt;The specifics of your particular control are handled at well-defined places in the control algorithm (the CreateChildControls or Render methods). This is an example of the Template Method pattern. The main algorithm skeleton is defined in a base class and subclasses can then plug in their own details without affecting the algorithm itself, as shown in &lt;span class="clsFigs"&gt;Figure 6&lt;/span&gt;. A composite control and a custom control both share the same general lifecycle, but they can end up with drastically different visual representations.&lt;/p&gt; &lt;div style="margin: 5px 0px 10px 5px; width: 198px; float: right;"&gt;&lt;img src="http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/fig06.gif" alt="Figure 6 Template Method Pattern" height="67" width="198" /&gt;&lt;br /&gt;&lt;span class="clsCap"&gt;Figure 6&lt;/span&gt; &lt;span class="clsCaptxt"&gt;Template Method Pattern&lt;/span&gt;&lt;/div&gt; &lt;p&gt;This pattern is similar to the Strategy pattern. These two patterns differ in scope and in methodology. Strategy is used to allow callers to vary an entire algorithm, like how to compare two objects, while Template Method is used to vary steps in an algorithm. Because of this, Strategy is more coarsely grained. There can be vast differences between different client implementations, while with Template Method the algorithm remains fundamentally the same. The other main difference is that Strategy uses delegation while Template Method uses inheritance. In the sorting example of Strategy, the comparison algorithm is delegated to the IComparer parameter, but with custom controls you subclass the base and override methods to make changes. Both, however, let you easily alter processes to fit your specific needs.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S10"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Patterns in the ASP.NET Pipeline&lt;/span&gt;&lt;br /&gt;&lt;p&gt;When a client requests an ASPX page from the Web server, the request travels through many steps before ultimately ending up as HTML displayed by the client's browser. First, the request is processed by IIS and routed to the appropriate ISAPI extension. The ISAPI extension for ASP.NET (aspnet_isapi.dll) routes the request to the ASP.NET worker process.&lt;/p&gt; &lt;div style="margin: 5px 0px 10px 5px; width: 107px; float: right;"&gt;&lt;img src="http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/fig07.gif" alt="Figure 7 ASP.NET Request Pipeline" height="196" width="107" /&gt;&lt;br /&gt;&lt;span class="clsCap"&gt;Figure 7&lt;/span&gt; &lt;span class="clsCaptxt"&gt;ASP.NET Request Pipeline&lt;/span&gt;&lt;/div&gt; &lt;p&gt;At this point, the request begins to interact with classes that you are used to dealing with. The request is passed to an HttpApplication. Usually this is the class created in the codebehind file for Global.asax. The HttpApplication then passes the request through any number of HTTP Modules. These classes implement the IHttpModule interface and have a chance to modify the request (or even halt the processing of it) before it gets passed on to the next module. ASP.NET provides some standard modules which provide functionality you're probably familiar with, including FormsAuthenticationModule, PassportAuthenticationModule, WindowsAuthenticationModule, and SessionStateModule, all of which provide exactly the functionality that their names imply.&lt;/p&gt; &lt;p&gt;Ultimately, the request ends up at an IHttpHandler, the most common of which is System.Web.UI.Page. Inside the IHttpHandler.ProcessRequest method, Page raises appropriate events (like Init, Load, and Render), handles ViewState, and provides the programming model for ASP.NET. &lt;span class="clsFigs"&gt;Figure 7&lt;/span&gt; shows an outline of this process.&lt;/p&gt; &lt;p&gt;Several of the patterns employed by this process are more thoroughly documented in another standard reference for patterns, Martin Fowler's &lt;i&gt;Patterns of Enterprise Application Architecture&lt;/i&gt; (Addison-Wesley, 2002).&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S11"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Intercepting Filter Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;Once a request has made it into an HttpApplication, it passes through any number of IHttpModules. Each module is independent and has only a limited amount of control over the order in which it is invoked. The HttpApplication class exposes a sequence of events that get raised as the request makes its way through processing. These events include BeginRequest, AuthenticateRequest, AuthorizeRequest, and EndRequest. When the HttpApplication loads a module, it calls the Init method of the IHttpModule interface, allowing the module to register for any of the events it cares about. As a given request is handled, the events are raised in the appropriate order and all registered modules get a chance to interact with the request. The module can therefore control the stage at which it gets invoked, but not the exact order within that stage.&lt;/p&gt; &lt;p&gt;These modules are an example of the Intercepting Filter pattern. This pattern represents a chain of filters that are each in turn given a chance to modify a request (or message) that passes through them. &lt;span class="clsFigs"&gt;Figure 8&lt;/span&gt; shows a simplified flow diagram of this process. The key ideas of this pattern are that the filters are independent; filters can modify the request as it passes through.&lt;/p&gt; &lt;div style="margin: 5px 0px 10px 5px; width: 229px; float: right;"&gt;&lt;img src="http://msdn.microsoft.com/msdnmag/issues/05/07/DesignPatterns/fig08.gif" alt="Figure 8 Request Flow " height="78" width="229" /&gt;&lt;br /&gt;&lt;span class="clsCap"&gt;Figure 8&lt;/span&gt; &lt;span class="clsCaptxt"&gt;Request Flow &lt;/span&gt;&lt;/div&gt; &lt;p&gt;There are several different implementation variations of the Intercepting Filter pattern, one of which is the event-based model employed by ASP.NET. A simpler variant involves maintaining a list of filters and iterating over it, invoking a method on each one in turn. This is how the Web Services Enhancements (WSE) for ASP.NET Web services uses this pattern. Each filter either extends SoapInputFilter (for request messages) or SoapOutputFilter (for responses), overriding the ProcessMessage method to perform the work of the filter.&lt;/p&gt; &lt;p&gt;Another option is to implement Intercepting Filter via the Decorator pattern. Then each filter would wrap its successor, performing preprocessing, invoking the successor, and then performing post-processing. The chain would be built using recursive composition, from back to front. This pattern is used to implement .NET Remoting channel sinks.&lt;/p&gt; &lt;p&gt;Regardless of implementation, the result is a dynamically configurable chain of independent filters. Since they are independent, these filters can easily be reordered and reused in other applications. Common tasks like authentication or logging can be encapsulated in a filter and used over and over. These tasks can then be handled by the filter chain before a request even reaches the HttpHandler, keeping the handler code cleaner.&lt;/p&gt;&lt;br /&gt;&lt;a style="display: none;" name="S12"&gt;&lt;/a&gt;&lt;span class="clsSubhead"&gt;Page Controller Pattern&lt;/span&gt;&lt;br /&gt;&lt;p&gt;System.Web.UI.Page implements a core part of the programming model for ASP.NET. Whenever you want to add a logical page to a Web application, you can create a Web Form (represented by an ASPX file and its codebehind). You can then write code to handle the specific demands of the new page, whether through handling page-level events, displaying a set of controls,
