In his latest entry Christopher Painter discusses the .NET Framework distribution size and the complications of distributing the framework.

The "accepted" practice has usually involved embedding the .NET Framework with your installation via a wrapper.  This becomes complicated with the ever increasing size of the redistributable.  There are other problems that can arise and not to mention, it violates the EULA.

If you take the time to read through the EULA, you will see that you are accepting some pretty hefty stipulations (and making some assumptions) on behalf of the user by silently installing the .NET Framework for them.  If you are in any kind of software development or enterprise IT role, you should really take the time to read through the Microsoft Patterns and Practices.  Some of the best practices may seem over the top and excessive, but it will provide a good baseline to begin from.

I don't disagree with Chris on any particular point in his blog, but if it were up to me, I would suggest detecting if the .NET Framework is present and either directing the user to the download site or providing it on your distribution media if you are redistributing from hard media.

So...how do you do that?  I'll show you how to detect the presence of the .NET Framework and cancel your installation if it is not detected.  For the purposes of this article, we'll assume that you need to search for version 2.0.

Microsoft has provided a support article that describes the best method for detecting the required version of the .NET Framework.

Many Windows Installer development products have built in methods for detecting the existence of the .NET Framework, but in case your's does not, here it is.  The first thing you will need to do is populate the RegLocator table:
RegLocator Table
Signature Root Key Name Type
AppReg 2 SOFTWARE\Microsoft\.NETFramework\policy\v2.0 50727 2

We are telling the installation to search for the designated registry key, and populate a property with its value if it is found.  The property to be populated is defined in the AppSearch table:
AppSearch Table
Property Signature
DETECTDOTNOT20 AppReg

If you would like to use the results of this search in a Launch Condition, you will need to ensure that the AppSearch action is sequenced before the LaunchConditions action in both the InstallUISequence and InstallExecuteSequence tables.  Keep in mind that a LaunchCondition is a no frills way to boot the user out of an install.  It will not give the option to ignore the error and continue; it's a pass/fail system.  Any other method would either require a customer installer dialog or a custom action.  With that in mind, if you would like to use the LaunchCondition table, here is how to populate it with the given example:
LaunchCondition Table
Condition Description
DETECTDOTNET20="50727-50727" [ProductName] requires Microsoft .NET Framework 2.0 in order to function properly.  Setup will now terminate.

I find this method superior to cramming the redistributable in your installer.  It saves space, reduces failure points, and adheres to the EULA.