A special element for maintaining IIS AppPools in IIS extension is called WebAppPool. As usual, we'll wrap it into a separate component, so that it is created on install. Later, we'll create a special custom action to deceive the standard removing mechanism on uninstall:
<Component DiskId="1" Id="CreateIISAppPool" Guid="{YOURGUID-6C5B-4980-AD0B-E32FA2DBC1F4}" Directory="WebsiteFolder">
<Condition>IISMAJORVERSION <> "#5"</Condition>
<iis:WebAppPool Id="IISSiteAppPool6" Name="[IISAPPPOOL_NAME]" MaxWorkerProcesses="1" Identity="networkService" />
<RegistryKey Root="HKLM" Key="$(var.ParentKey)">
<RegistryValue Name="IISAppPoolName" Type="string" Value="[IISAPPPOOL_NAME]"/>
</RegistryKey>
</Component>
As you can see, the component is installed once the target system has IIS 6+. It creates a WebAppPool with the name provided in IISAPPPOOL_NAME public property. It also writes this name into a registry value, which resides under the instance-specific registry key.
With this component included into the MSI package, the app pool is created when the first instance is installed, and nothing happens for second and subsequent instances.
Let's examine the uninstall behavior. The MSI behaves natural - when it meets the component to uninstall, it removes the WebAppPool specified in it. But the IIS extension which performs the actual deletion of app pool, needs the name to be passed in it. So, the only thing we should do is to supply this action with a fake app pool name each time, except for the last instance uninstall.
Here is the algorithm:
- search the registry for the app pool name as usual
- schedule a special action on unistall after AppSearch, which detects if this is the last instance being uninstalled, and if not, "breaks" the app pool name into something non-existent
The first point is quite straight-forward:
<Property Id="IISAPPPOOL_NAME">
<RegistrySearch Id="IISAppPoolName" Root="HKLM" Key="$(var.ParentKey)" Name="IISAppPoolName" Type="raw" />
</Property>
The second one is not natural, like any hack:
[CustomAction]
public static ActionResult ChangeWebAppPoolNameToDeceiveUninstall(Session session)
{
int numberOfInstalled = 1;
foreach (ProductInstallation product in ProductInstallation.GetRelatedProducts(session["UpgradeCode"]))
{
if ((session["ProductCode"] != product.ProductCode) && product.IsInstalled)
{
numberOfInstalled++;
break;
}
}
if (numberOfInstalled > 1)
{
session["IISAPPPOOL_NAME"] += string.Format("|{0}", DateTime.Now.ToLongTimeString());
}
return ActionResult.Success;
}
It iterates the related products (those sharing the UpgradeCode), and if it finds others installed, except for itself, it changes the app pool name we retrieved from registry into something unique, for instance, appends a unique string.
Thus, the IIS custom action which is going to delete the app pool fails to find the one with the provided name, and does nothing. When, otherwise, it is the last instance being uninstalled, the retrieved app pool name remains unchanged, and the app pool is successfully removed.
Note that the mentioned action should be immediate, should occur after AppSearch on uninstall.
That's it! I would appreciate any comments as usual.
Buy without a bank There are many legal requirements when buying a house without a bank.i can buy any things and any property without any help of any bank .This Is very nice blog .
ReplyDeleteThanks for sharing in detail. Your blog is an inspiration! Apart of really useful tips, it's just really !
ReplyDelete___________________________
Cyprus property
Good line and nice image this post. this post will be effectively Just about everything looks good displayed thanks for sharing.
ReplyDelete-----------
Land selling