Repository: dotnet/aspnetcore
Pull request #60769: Fix ASP.NET Core module installer upgrade issues
Author: login: lextm
Labels: name: area-infrastructure
description: Includes: MSBuild projects/targets, build scripts, CI, Installers and shared framework
name: community-contribution
description: Indicates that the PR has been added by a community member
Created: 2025-03-06T05:00:22Z | Merged: 2025-03-13T21:13:52Z

# Fix ASP.NET Core module installer upgrade issues

<!-- Thank you for submitting a pull request to our repo. -->

<!-- If this is your first PR in the ASP.NET Core repo, please run through the checklist
below to ensure a smooth review and merge process for your PR. -->

- [x] You've read the [Contributor Guide](https://github.com/dotnet/aspnetcore/blob/main/CONTRIBUTING.md) and [Code of Conduct](https://github.com/dotnet/aspnetcore/blob/main/CODE-OF-CONDUCT.md).
- [ ] You've included unit or integration tests for your change, where applicable.
- [ ] You've included inline docs for your change, where applicable.
- [x] There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

<!-- Once all that is done, you're ready to go. Open the PR with the content below. -->

Summary of the changes (Less than 80 chars)

* Add version numbers to ARM64X pure forwarder compilation.
* Revise WiX installer component/file relationship to ensure upgrade is possible.

## Description

Initial PR #59483 left a few issues unresolved and led to #60764.

### Changes in ancm_iis_expressv2.wxs and aspnetcoremodulev2.wxs

The previously introduced new components `AspNetCoreModuleV2.forwarder` and `AspNetCoreModuleHandler.forwarder` can confuse Windows Installer, and caused files like `aspnetcorev2.dll` to be mistakenly removed during upgrades from .NET 7/8/9.

Here they have been removed and the new files are conditionally included in previously existing components `AspNetCoreModuleV2` and `AspNetCoreModuleHandler`.

### Changes in all.cmd/build.cmd and build.proj

Previously the pure forwarder dlls were not built with version information. That confused Windows Installer when it tried to compare files like `aspnetcorev2.dll` with previous installed versions.

Here we ask the linker to use .res files that were used to build the x64 builds of related .dll files. This ensures that pure forwarders have the same version information as well as other metadata.

Fixes #60764


Linked issue #60764: Windows hosting bundle upgrade breaks ANCM on ARM64 machines
Starting in .NET 10 preview 2, changes to the Windows hosting bundle installer fix running x64 and x86 web applications with ANCM v2 on ARM64 has broken upgrade scenarios. Some important components like aspnetcorev2.dll and the module entry in applicationhost.config get removed rather than updated if you have a previous version of the hosting bundle already installed.

This causes problems for both IIS and IIS express on ARM64 machines only after attempting to update. Fortunately, **you can work around this issue by uninstalling all hosting bundles and reinstalling the .NET 10 preview 2 hosting bundle.**

Looking at the `dd_dd_DotNetCoreWinSvrHosting__20250303210516_001_AspNetCoreModuleV2_arm64.log` installer log in the temp directory we see the following.

> MSI (s) (48:E0) [21:05:26:022]: Disallowing installation of component: {4B6BB33A-01F0-48C7-BCE9-5A5514AC0431} since the same component with higher versioned keyfile exists

This is despite the referenced component being newly added by #59483. Fortunately, it looks like @lextm and @joeloff have gotten to the bottom of this issue and are ready with a fix. I just filed this issue for tracking purposes.


Diff:
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
index df2e44ea40b2..9aa2c78478e0 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
@@ -164,22 +164,63 @@
       <DirectoryRef Id="INSTALLDIR">
         <Directory Id="INSTALLLOCATION" ShortName="ANCM" Name="$(var.ProductName)">
           <Directory Id="VersionDir" Name="$(var.ProductVersionString)">
-            <?if $(var.Platform) = "arm64" ?>
-            <Component Id="AspNetCoreModuleV2.forwarder"
-                Guid="08968573-05c1-4bf1-8879-7b818ac9525b"
-                Win64="$(var.IsWin64)">
-                <File Id="AspNetCoreModuleV2Dll.forwarder"
+            <Component Id="AspNetCoreModule" Guid="84ed6ce6-c8a3-4fa8-a872-c98a1d15dd4f" Win64="$(var.IsWin64)">
+                <?if $(var.Platform) = "arm64" ?>
+                <File Id="AspNetCoreModuleDll"
                     Name="aspnetcorev2.dll"
                     Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2.dll"
                     DiskId="1"
                     Vital="yes"/>
-                <RegistryKey Root="HKLM"
-                    Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                    <RegistryValue Name="EventMessageFile" Type="expandable"
-                        Value="[#AspNetCoreModuleV2Dll.forwarder]" />
-                    <RegistryValue Name="TypesSupported" Type="integer" Value="7" />
-                </RegistryKey>
+                <?else ?>
+                <File Id="AspNetCoreModuleDll"
+                    Name="aspnetcorev2.dll"
+                    Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
+                    DiskId="1"
+                    Vital="yes"/>
+                <?endif ?>
+              <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
+                <RegistryValue Name="EventMessageFile" Type="expandable" Value="[#AspNetCoreModuleDll]"/>
+                <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
+              </RegistryKey>
             </Component>
+            <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)" >
+              <Component Id="AspNetCoreModuleHandler" Guid="559EF726-B25C-480F-AFA4-32D0BA8B2376" Win64="$(var.IsWin64)">
+                    <?if $(var.Platform) = "arm64" ?>
+                    <File Id="AspNetCoreModuleHandlerDll"
+                        Name="aspnetcorev2_outofprocess.dll"
+                        Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2_outofprocess.dll"
+                        DiskId="1"
+                        Vital="yes"/>
+                    <?else ?>
+                    <File Id="AspNetCoreModuleHandlerDll"
+                        Name="aspnetcorev2_outofprocess.dll"
+                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
+                        DiskId="1"
+                        Vital="yes">
+                    </File>
+                    <?endif ?>
+              </Component>
+              <?if $(var.Platform) = "arm64" ?>
+                <Component Id="AspNetCoreModuleHandler.x64"
+                    Guid="0b192457-9c6a-4703-ba6a-0c5a58b7c9cb"
+                    Win64="$(var.IsWin64)">
+                    <File Id="AspNetCoreModuleHandlerDll.x64"
+                        Name="aspnetcorev2_outofprocess_x64.dll"
+                        Source="$(var.ArtifactsDir)\bin\OutOfProcessRequestHandler\x64\$(var.Configuration)\aspnetcorev2_outofprocess.dll"
+                        DiskId="1"
+                        Vital="yes"/>
+                </Component>
+                <Component Id="AspNetCoreModuleHandler.arm64"
+                    Guid="21cc9da0-ab0a-4717-90df-dbaaa3f68510" Win64="$(var.IsWin64)">
+                    <File Id="AspNetCoreModuleHandlerDll.arm64"
+                        Name="aspnetcorev2_outofprocess_arm64.dll"
+                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
+                        DiskId="1"
+                        Vital="yes"/>
+                </Component>
+              <?endif ?>
+            </Directory>
+            <?if $(var.Platform) = "arm64" ?>
             <Component Id="AspNetCoreModuleV2.x64"
                 Guid="1962b1b0-6345-4b37-97b3-a8f2c9e82bee"
                 Win64="$(var.IsWin64)">
@@ -210,56 +251,6 @@
                     <RegistryValue Name="TypesSupported" Type="integer" Value="7" />
                 </RegistryKey>
             </Component>
-            <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)">
-                <Component Id="AspNetCoreModuleHandler.forwarder"
-                    Guid="51045d90-7231-480c-bac7-2969a2861ece" Win64="$(var.IsWin64)">
-                    <File Id="AspNetCoreModuleHandlerDll.forwarder"
-                        Name="aspnetcorev2_outofprocess.dll"
-                        Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2_outofprocess.dll"
-                        DiskId="1"
-                        Vital="yes"/>
-                </Component>
-                <Component Id="AspNetCoreModuleHandler.x64"
-                    Guid="0b192457-9c6a-4703-ba6a-0c5a58b7c9cb"
-                    Win64="$(var.IsWin64)">
-                    <File Id="AspNetCoreModuleHandlerDll.x64"
-                        Name="aspnetcorev2_outofprocess_x64.dll"
-                        Source="$(var.ArtifactsDir)\bin\OutOfProcessRequestHandler\x64\$(var.Configuration)\aspnetcorev2_outofprocess.dll"
-                        DiskId="1"
-                        Vital="yes"/>
-                </Component>
-                <Component Id="AspNetCoreModuleHandler.arm64"
-                    Guid="21cc9da0-ab0a-4717-90df-dbaaa3f68510" Win64="$(var.IsWin64)">
-                    <File Id="AspNetCoreModuleHandlerDll.arm64"
-                        Name="aspnetcorev2_outofprocess_arm64.dll"
-                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
-                        DiskId="1"
-                        Vital="yes"/>
-                </Component>
-            </Directory>
-            <?else ?>
-            <Component Id="AspNetCoreModule" Guid="84ed6ce6-c8a3-4fa8-a872-c98a1d15dd4f" Win64="$(var.IsWin64)">
-                <File Id="AspNetCoreModuleDll"
-                    Name="aspnetcorev2.dll"
-                    Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
-                    DiskId="1"
-                    Vital="yes">
-                </File>
-              <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                <RegistryValue Name="EventMessageFile" Type="expandable" Value="[#AspNetCoreModuleDll]"/>
-                <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
-              </RegistryKey>
-            </Component>
-              <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)" >
-              <Component Id="AspNetCoreModuleHandler" Guid="559EF726-B25C-480F-AFA4-32D0BA8B2376" Win64="$(var.IsWin64)">
-                    <File Id="AspNetCoreModuleHandlerDll"
-                        Name="aspnetcorev2_outofprocess.dll"
-                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
-                        DiskId="1"
-                        Vital="yes">
-                    </File>
-              </Component>
-            </Directory>
             <?endif ?>
           </Directory>
         </Directory>
@@ -324,16 +315,13 @@
 
         <!-- Feature Definition -->
         <Feature Id="AspNetCoreModuleFeature" Title="!(loc.AspNetCoreModuleProductTitle)" Description="!(loc.AspNetCoreModuleProductDescription)" Level="1">
+            <ComponentRef Id="AspNetCoreModule"/>
+            <ComponentRef Id="AspNetCoreModuleHandler"/>
             <?if $(var.Platform) = "arm64" ?>
-            <ComponentRef Id="AspNetCoreModuleV2.forwarder" />
-            <ComponentRef Id="AspNetCoreModuleHandler.forwarder" />
             <ComponentRef Id="AspNetCoreModuleV2.x64" />
             <ComponentRef Id="AspNetCoreModuleHandler.x64" />
             <ComponentRef Id="AspNetCoreModuleV2.arm64" />
             <ComponentRef Id="AspNetCoreModuleHandler.arm64" />
-            <?else ?>
-            <ComponentRef Id="AspNetCoreModule"/>
-            <ComponentRef Id="AspNetCoreModuleHandler"/>
             <?endif ?>
             <ComponentRef Id="AspNetCoreSchema"/>
             <?if $(var.Platform) != "x86" ?>
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
index f96c13979b5f..ef4e4a1216e7 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
@@ -144,20 +144,62 @@
                <Directory Id="IISModuleDirectory" Name="IIS">
                    <Directory Id="INSTALLLOCATION" ShortName="ANCM" Name="Asp.Net Core Module">
                        <Directory Id="VersionDir" Name="$(var.ProductVersionString)">
-                           <?if $(var.Platform) = "arm64" ?>
-                           <Component Id="AspNetCoreModuleV2.forwarder" Guid="4b6bb33a-01f0-48c7-bce9-5a5514ac0431" Win64="$(var.IsWin64)">
-                                <File Id="AspNetCoreModuleV2Dll.forwarder"
+                           <Component Id="AspNetCoreModuleV2" Guid="3a692941-59be-43cf-98a8-6ed01b12a519" Win64="$(var.IsWin64)">
+                             <?if $(var.Platform) = "arm64" ?>
+                             <File Id="AspNetCoreModuleV2Dll"
                                     Name="aspnetcorev2.dll"
                                     Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2.dll"
                                     DiskId="1"
-                                    Vital="yes">
-                                </File>
-                               <RemoveFile Id="AspNetCoreModuleV2Dll_Remove.forwarder" Name="aspnetcorev2.dll" On="install" />
-                               <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                                   <RegistryValue Name="EventMessageFile" Type="expandable" Value="[#AspNetCoreModuleV2Dll.forwarder]"/>
-                                   <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
-                               </RegistryKey>
+                                    Vital="yes"/>
+                             <?else ?>
+                             <File Id="AspNetCoreModuleV2Dll"
+                               Name="aspnetcorev2.dll"
+                               Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
+                               DiskId="1"
+                               Vital="yes"/>
+                             <?endif ?>
+                             <RemoveFile Id="AspNetCoreModuleV2Dll_Remove" Name="aspnetcorev2.dll" On="install" />
+                             <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
+                               <RegistryValue Name="EventMessageFile" Type="expandable" Value="[#AspNetCoreModuleV2Dll]"/>
+                               <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
+                             </RegistryKey>
                            </Component>
+                           <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)" >
+                             <Component Id="AspNetCoreModuleHandler" Guid="4b62060a-deb8-4de3-9557-9c0be21dc844" Win64="$(var.IsWin64)">
+                               <?if $(var.Platform) = "arm64" ?>
+                               <File Id="AspNetCoreModuleHandlerDll"
+                                        Name="aspnetcorev2_outofprocess.dll"
+                                        Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2_outofprocess.dll"
+                                        DiskId="1"
+                                        Vital="yes"/>
+                               <?else ?>
+                               <File Id="AspNetCoreModuleHandlerDll"
+                                 Name="aspnetcorev2_outofprocess.dll"
+                                 Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
+                                 DiskId="1"
+                                 Vital="yes"/>
+                               <?endif ?>
+                             </Component>
+                             <?if $(var.Platform) = "arm64" ?>
+                             <Component Id="AspNetCoreModuleHandler.x64" Guid="d9b0b5c9-8bbe-46f2-97d5-ba23d1a1ffed" Win64="$(var.IsWin64)">
+                                    <File Id="AspNetCoreModuleHandlerDll.x64"
+                                        Name="aspnetcorev2_outofprocess_x64.dll"
+                                        Source="$(var.ArtifactsDir)\bin\OutOfProcessRequestHandler\x64\$(var.Configuration)\aspnetcorev2_outofprocess.dll"
+                                        DiskId="1"
+                                        Vital="yes">
+                                    </File>
+                             </Component>
+                             <Component Id="AspNetCoreModuleHandler.arm64" Guid="ab249ab5-9203-4fd5-87b6-8acc3e1a0702" Win64="$(var.IsWin64)">
+                                    <File Id="AspNetCoreModuleHandlerDll.arm64"
+                                        Name="aspnetcorev2_outofprocess_arm64.dll"
+                                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
+                                        DiskId="1"
+                                        Vital="yes">
+                                    </File>
+                             </Component>
+                             <?endif ?>
+                           </Directory>
+                           <?if $(var.Platform) = "arm64" ?>
                            <Component Id="AspNetCoreModuleV2.x64" Guid="325cf239-162d-4de8-97e7-642e6c66181c" Win64="$(var.IsWin64)">
                                 <File Id="AspNetCoreModuleV2Dll.x64"
                                     Name="aspnetcorev2_x64.dll"
@@ -184,54 +226,6 @@
                                    <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
                                </RegistryKey>
                            </Component>
-                           <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)" >
-                               <Component Id="AspNetCoreModuleHandler.forwarder" Guid="4862728c-e943-49f0-901a-cd96e4bf03ef" Win64="$(var.IsWin64)">
-                                    <File Id="AspNetCoreModuleHandlerDll.forwarder"
-                                        Name="aspnetcorev2_outofprocess.dll"
-                                        Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2_outofprocess.dll"
-                                        DiskId="1"
-                                        Vital="yes">
-                                    </File>
-                               </Component>
-                               <Component Id="AspNetCoreModuleHandler.x64" Guid="d9b0b5c9-8bbe-46f2-97d5-ba23d1a1ffed" Win64="$(var.IsWin64)">
-                                    <File Id="AspNetCoreModuleHandlerDll.x64"
-                                        Name="aspnetcorev2_outofprocess_x64.dll"
-                                        Source="$(var.ArtifactsDir)\bin\OutOfProcessRequestHandler\x64\$(var.Configuration)\aspnetcorev2_outofprocess.dll"
-                                        DiskId="1"
-                                        Vital="yes">
-                                    </File>
-                               </Component>
-                               <Component Id="AspNetCoreModuleHandler.arm64" Guid="ab249ab5-9203-4fd5-87b6-8acc3e1a0702" Win64="$(var.IsWin64)">
-                                    <File Id="AspNetCoreModuleHandlerDll.arm64"
-                                        Name="aspnetcorev2_outofprocess_arm64.dll"
-                                        Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
-                                        DiskId="1"
-                                        Vital="yes">
-                                    </File>
-                               </Component>
-                           </Directory>
-                           <?else ?>
-                           <Component Id="AspNetCoreModuleV2" Guid="3a692941-59be-43cf-98a8-6ed01b12a519" Win64="$(var.IsWin64)">
-                             <File Id="AspNetCoreModuleV2Dll"
-                               Name="aspnetcorev2.dll"
-                               Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
-                               DiskId="1"
-                               Vital="yes"/>
-                             <RemoveFile Id="AspNetCoreModuleV2Dll_Remove" Name="aspnetcorev2.dll" On="install" />
-                             <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                               <RegistryValue Name="EventMessageFile" Type="expandable" Value="[#AspNetCoreModuleV2Dll]"/>
-                               <RegistryValue Name="TypesSupported" Type="integer" Value="7"/>
-                             </RegistryKey>
-                           </Component>
-                           <Directory Id="HandlerVersionDir" Name="$(var.ANCMFolderVersion)" >
-                             <Component Id="AspNetCoreModuleHandler" Guid="4b62060a-deb8-4de3-9557-9c0be21dc844" Win64="$(var.IsWin64)">
-                               <File Id="AspNetCoreModuleHandlerDll"
-                                 Name="aspnetcorev2_outofprocess.dll"
-                                 Source="$(var.AspNetCoreV2HandlerProgramFilesTargetPath)"
-                                 DiskId="1"
-                                 Vital="yes"/>
-                             </Component>
-                           </Directory>
                            <?endif ?>
                        </Directory>
                    </Directory>
@@ -287,16 +281,13 @@
         <Feature Id="AspNetCoreModuleFeature" Title="!(loc.AspNetCoreModuleProductTitle)" Description="!(loc.AspNetCoreModuleProductDescription)" Level="1">
             <ComponentRef Id="C_DiscoverabilityKey"/>
             <ComponentRef Id="AspNetCoreSchemaV2"/>
+            <ComponentRef Id="AspNetCoreModuleV2" />
+            <ComponentRef Id="AspNetCoreModuleHandler" />
             <?if $(var.Platform) = "arm64"?>
-            <ComponentRef Id="AspNetCoreModuleV2.forwarder"/>
-            <ComponentRef Id="AspNetCoreModuleHandler.forwarder"/>
             <ComponentRef Id="AspNetCoreModuleV2.x64"/>
             <ComponentRef Id="AspNetCoreModuleHandler.x64"/>
             <ComponentRef Id="AspNetCoreModuleV2.arm64"/>
             <ComponentRef Id="AspNetCoreModuleHandler.arm64"/>
-            <?else ?>
-            <ComponentRef Id="AspNetCoreModuleV2" />
-            <ComponentRef Id="AspNetCoreModuleHandler" />
             <?endif ?>
             <?if $(var.Platform) != "x86" ?>
             <ComponentRef Id="C_DiscoverabilityKeyWow"/>
@@ -323,11 +314,7 @@
         <CustomTable Id="IISGlobalModule">
             <Row>
                 <Data Column="Name">AspNetCoreModuleV2</Data>
-                <?if $(var.Platform) = "arm64" ?>
-                <Data Column="File_">AspNetCoreModuleV2Dll.forwarder</Data>
-                <?else ?>
                 <Data Column="File_">AspNetCoreModuleV2Dll</Data>
-                <?endif ?>
             </Row>
         </CustomTable>
 
@@ -347,11 +334,7 @@
             <Data Column="AreaName">ANCM</Data>
             <Data Column="AreaValue">65536</Data>
             <Data Column="BinaryName_">AncmMofFile</Data>
-            <?if $(var.Platform) = "arm64" ?>
-            <Data Column="Component_">AspNetCoreModuleV2.forwarder</Data>
-            <?else ?>
             <Data Column="Component_">AspNetCoreModuleV2</Data>
-            <?endif ?>
           </Row>
         </CustomTable>
         <!-- <?endif ?> -->
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/all.cmd b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/all.cmd
index b9152822828e..80543b729c47 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/all.cmd
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/all.cmd
@@ -1,2 +1,2 @@
 call %1 -host_arch=x64 -arch=arm64 -no_logo
-call build.cmd %2 %3
+call build.cmd %2 %3 %4
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.cmd b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.cmd
index a3ef34304dff..7e150ccbd565 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.cmd
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.cmd
@@ -1,5 +1,6 @@
 SET objDir=%1
 SET binDir=%2
+SET configuration=%3
 
 cl /nologo /c /Fo%objDir%\aspnetcorev2_arm64.obj empty.cpp
 cl /nologo /c /arm64EC /Fo%objDir%\aspnetcorev2_x64.obj empty.cpp
@@ -7,7 +8,7 @@ cl /nologo /c /arm64EC /Fo%objDir%\aspnetcorev2_x64.obj empty.cpp
 link /lib /nologo /machine:arm64 /def:aspnetcorev2_arm64.def /out:%objDir%\aspnetcorev2_arm64.lib
 link /lib /nologo /machine:x64 /def:aspnetcorev2_x64.def /out:%objDir%\aspnetcorev2_x64.lib
 
-link /dll /nologo /noentry /machine:arm64x /defArm64Native:aspnetcorev2_arm64.def /def:aspnetcorev2_x64.def %objDir%\aspnetcorev2_arm64.obj %objDir%\aspnetcorev2_x64.obj /out:%binDir%\aspnetcorev2.dll %objDir%\aspnetcorev2_arm64.lib %objDir%\aspnetcorev2_x64.lib
+link /dll /nologo /noentry /machine:arm64x /defArm64Native:aspnetcorev2_arm64.def /def:aspnetcorev2_x64.def %objDir%\aspnetcorev2_arm64.obj %objDir%\aspnetcorev2_x64.obj %objDir%\..\AspNetCoreModuleShim\x64\%configuration%\aspnetcoremodule.res /out:%binDir%\aspnetcorev2.dll %objDir%\aspnetcorev2_arm64.lib %objDir%\aspnetcorev2_x64.lib
 
 cl /nologo /nologo /c /Fo%objDir%\aspnetcorev2_outofprocess_arm64.obj empty.cpp
 cl /nologo /nologo /c /arm64EC /Fo%objDir%\aspnetcorev2_outofprocess_x64.obj empty.cpp
@@ -15,4 +16,4 @@ cl /nologo /nologo /c /arm64EC /Fo%objDir%\aspnetcorev2_outofprocess_x64.obj emp
 link /lib /nologo /machine:arm64 /def:aspnetcorev2_outofprocess_arm64.def /out:%objDir%\aspnetcorev2_outofprocess_arm64.lib
 link /lib /nologo /machine:x64 /def:aspnetcorev2_outofprocess_x64.def /out:%objDir%\aspnetcorev2_outofprocess_x64.lib
 
-link /dll /nologo /noentry /machine:arm64x /defArm64Native:aspnetcorev2_outofprocess_arm64.def /def:aspnetcorev2_outofprocess_x64.def %objDir%\aspnetcorev2_outofprocess_arm64.obj %objDir%\aspnetcorev2_outofprocess_x64.obj /out:%binDir%\aspnetcorev2_outofprocess.dll %objDir%\aspnetcorev2_outofprocess_arm64.lib %objDir%\aspnetcorev2_outofprocess_x64.lib
+link /dll /nologo /noentry /machine:arm64x /defArm64Native:aspnetcorev2_outofprocess_arm64.def /def:aspnetcorev2_outofprocess_x64.def %objDir%\aspnetcorev2_outofprocess_arm64.obj %objDir%\aspnetcorev2_outofprocess_x64.obj %objDir%\..\OutOfProcessRequestHandler\x64\%configuration%\outofprocessrequesthandler.res /out:%binDir%\aspnetcorev2_outofprocess.dll %objDir%\aspnetcorev2_outofprocess_arm64.lib %objDir%\aspnetcorev2_outofprocess_x64.lib
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.proj b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.proj
index cc058255fa7c..012ea1d06ea2 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.proj
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/Forwarders/build.proj
@@ -16,6 +16,6 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Target Name="Build" DependsOnTargets="SetBuildDefaultEnvironmentVariables">
     <MakeDir Directories="$(ObjDir);$(BinDir)" />
-    <Exec Command="all.cmd $(Prompt) $(ObjDir) $(BinDir)" />
+    <Exec Command="all.cmd $(Prompt) $(ObjDir) $(BinDir) $(Configuration)" />
   </Target>
 </Project>


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T05:00:25Z
user: login: joeloff
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T16:49:18Z
user: login: joeloff
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T16:51:11Z
user: login: joeloff
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T16:59:09Z
user: login: joeloff
body: @wtgodbe once this is merged, I'd suggest doing a full setup test pass on multiple scenarios including

* Clean install
* Upgrade (8+10+9)
* Include Repair/Uninstall tests for the scenarios above
* Double check what happens with success blockers. In this case, install 10.0.0-preview.2 and then install 10.0.0-preview.1 Success blockers bypass the downgrade check at the bundle level, allowing it to run. The MSI though should not get executed. 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-06T17:09:33Z

Review comments:
diff_hunk: @@ -164,22 +164,63 @@
       <DirectoryRef Id="INSTALLDIR">
         <Directory Id="INSTALLLOCATION" ShortName="ANCM" Name="$(var.ProductName)">
           <Directory Id="VersionDir" Name="$(var.ProductVersionString)">
-            <?if $(var.Platform) = "arm64" ?>
-            <Component Id="AspNetCoreModuleV2.forwarder"
-                Guid="08968573-05c1-4bf1-8879-7b818ac9525b"
-                Win64="$(var.IsWin64)">
-                <File Id="AspNetCoreModuleV2Dll.forwarder"
+            <Component Id="AspNetCoreModule" Guid="84ed6ce6-c8a3-4fa8-a872-c98a1d15dd4f" Win64="$(var.IsWin64)">
+                <?if $(var.Platform) = "arm64" ?>
+                <File Id="AspNetCoreModuleDll"
                     Name="aspnetcorev2.dll"
                     Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2.dll"
                     DiskId="1"
                     Vital="yes"/>
-                <RegistryKey Root="HKLM"
-                    Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                    <RegistryValue Name="EventMessageFile" Type="expandable"
-                        Value="[#AspNetCoreModuleV2Dll.forwarder]" />
-                    <RegistryValue Name="TypesSupported" Type="integer" Value="7" />
-                </RegistryKey>
+                <?else ?>
+                <File Id="AspNetCoreModuleDll"
+                    Name="aspnetcorev2.dll"
+                    Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
+                    DiskId="1"
path: src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
user: login: joeloff
body: `File@DiskId="1"` and `File@Vital="yes"` are the defaults, there are probably more of these to clean up
created_at: 2025-03-06T16:49:18Z
author_association: MEMBER
diff_hunk: @@ -164,22 +164,63 @@
       <DirectoryRef Id="INSTALLDIR">
         <Directory Id="INSTALLLOCATION" ShortName="ANCM" Name="$(var.ProductName)">
           <Directory Id="VersionDir" Name="$(var.ProductVersionString)">
-            <?if $(var.Platform) = "arm64" ?>
-            <Component Id="AspNetCoreModuleV2.forwarder"
-                Guid="08968573-05c1-4bf1-8879-7b818ac9525b"
-                Win64="$(var.IsWin64)">
-                <File Id="AspNetCoreModuleV2Dll.forwarder"
+            <Component Id="AspNetCoreModule" Guid="84ed6ce6-c8a3-4fa8-a872-c98a1d15dd4f" Win64="$(var.IsWin64)">
+                <?if $(var.Platform) = "arm64" ?>
+                <File Id="AspNetCoreModuleDll"
                     Name="aspnetcorev2.dll"
                     Source="$(var.ArtifactsDir)\bin\AspNetCoreModuleForwarders\aspnetcorev2.dll"
                     DiskId="1"
                     Vital="yes"/>
-                <RegistryKey Root="HKLM"
-                    Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
-                    <RegistryValue Name="EventMessageFile" Type="expandable"
-                        Value="[#AspNetCoreModuleV2Dll.forwarder]" />
-                    <RegistryValue Name="TypesSupported" Type="integer" Value="7" />
-                </RegistryKey>
+                <?else ?>
+                <File Id="AspNetCoreModuleDll"
+                    Name="aspnetcorev2.dll"
+                    Source="$(var.AspNetCoreV2ProgramFilesTargetPath)"
+                    DiskId="1"
+                    Vital="yes"/>
+                <?endif ?>
+              <RegistryKey Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\EventLog\Application\$(var.ProductShortName)">
path: src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
user: login: joeloff
body: The general rule for components is one file/reg key per component. When performing repairs, the keypath of the component is used to determine its state and whether it needs to be reinstalled during a repair. If non-keypath items are missing or damaged, repairs my not necessarily work. It's likely repair will write the registry keys again since WiX by default will set the reinstall mode to include registry keys. Just calling it out in case this is an issue.
created_at: 2025-03-06T16:51:11Z
author_association: MEMBER
diff_hunk: @@ -164,22 +164,63 @@
       <DirectoryRef Id="INSTALLDIR">
         <Directory Id="INSTALLLOCATION" ShortName="ANCM" Name="$(var.ProductName)">
           <Directory Id="VersionDir" Name="$(var.ProductVersionString)">
-            <?if $(var.Platform) = "arm64" ?>
-            <Component Id="AspNetCoreModuleV2.forwarder"
-                Guid="08968573-05c1-4bf1-8879-7b818ac9525b"
-                Win64="$(var.IsWin64)">
-                <File Id="AspNetCoreModuleV2Dll.forwarder"
+            <Component Id="AspNetCoreModule" Guid="84ed6ce6-c8a3-4fa8-a872-c98a1d15dd4f" Win64="$(var.IsWin64)">
+                <?if $(var.Platform) = "arm64" ?>
+                <File Id="AspNetCoreModuleDll"
path: src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
user: login: joeloff
body: You should consider setting the `File@KeyPath="yes"`. If child elements of a component do not have a keypath set, and the parent directory of the component is not a key path, then the first child is selected. In this case, it would be the file. However, if you modify the order, the key path will change. Setting it explicitly will avoid issues in the future.

This might be a good read: https://learn.microsoft.com/en-us/windows/win32/msi/what-happens-if-the-component-rules-are-broken
created_at: 2025-03-06T16:59:09Z
author_association: MEMBER

PR comments:
user: login: lextm
created_at: 2025-03-06T06:23:38Z
body: Tested with IIS Express and IIS. This pull request is now ready for further review.
author_association: CONTRIBUTOR
user: login: halter73
created_at: 2025-03-13T21:13:45Z
body: @joeloff Since you approved the PR and your suggestions seem like style improvements, I'm going to merge it as-is to make it easier to get started manually testing upgrade scenarios.

Let me know if any of these suggestions are important enough to warrant a quick follow up PR or tracking issue to look at more holistically across all our .wxs files.
author_association: MEMBER
user: login: joeloff
created_at: 2025-03-13T21:23:04Z
body: They're not style suggestions.
author_association: MEMBER