diff --git a/.vscode/settings.json b/.vscode/settings.json
index 89a3c7cca0c7..14126dac8b89 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,6 +4,69 @@
"*.*proj": "xml",
"*.props": "xml",
"*.targets": "xml",
- "*.tasks": "xml"
+ "*.tasks": "xml",
+ "filesystem": "cpp",
+ "array": "cpp",
+ "initializer_list": "cpp",
+ "list": "cpp",
+ "random": "cpp",
+ "type_traits": "cpp",
+ "vector": "cpp",
+ "xhash": "cpp",
+ "xstring": "cpp",
+ "xtree": "cpp",
+ "xutility": "cpp",
+ "algorithm": "cpp",
+ "atomic": "cpp",
+ "cctype": "cpp",
+ "chrono": "cpp",
+ "cmath": "cpp",
+ "cstddef": "cpp",
+ "cstdint": "cpp",
+ "cstdio": "cpp",
+ "cstdlib": "cpp",
+ "cstring": "cpp",
+ "ctime": "cpp",
+ "cwchar": "cpp",
+ "exception": "cpp",
+ "fstream": "cpp",
+ "functional": "cpp",
+ "iomanip": "cpp",
+ "ios": "cpp",
+ "iosfwd": "cpp",
+ "istream": "cpp",
+ "iterator": "cpp",
+ "limits": "cpp",
+ "locale": "cpp",
+ "map": "cpp",
+ "memory": "cpp",
+ "new": "cpp",
+ "optional": "cpp",
+ "ostream": "cpp",
+ "ratio": "cpp",
+ "stdexcept": "cpp",
+ "streambuf": "cpp",
+ "string": "cpp",
+ "system_error": "cpp",
+ "thread": "cpp",
+ "tuple": "cpp",
+ "typeinfo": "cpp",
+ "unordered_map": "cpp",
+ "utility": "cpp",
+ "xfacet": "cpp",
+ "xiosbase": "cpp",
+ "xlocale": "cpp",
+ "xlocbuf": "cpp",
+ "xlocinfo": "cpp",
+ "xlocmes": "cpp",
+ "xlocmon": "cpp",
+ "xlocnum": "cpp",
+ "xloctime": "cpp",
+ "xmemory": "cpp",
+ "xstddef": "cpp",
+ "xtr1common": "cpp",
+ "iostream": "cpp",
+ "set": "cpp",
+ "sstream": "cpp"
}
}
diff --git a/eng/Dependencies.props b/eng/Dependencies.props
index 754b192df387..3e35ae7b3666 100644
--- a/eng/Dependencies.props
+++ b/eng/Dependencies.props
@@ -184,6 +184,9 @@ and are generated based on the last package release.
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 69452ee23103..6be083dfdf2d 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -405,6 +405,10 @@
https://github.com/dotnet/core-setup
2bb2dcaeffb1dfeda077354449868ddac254bc3d
+
+ https://github.com/dotnet/core-setup
+ 3f9156d5d9b5ae4b100baeaa75011aaee88a3f4b
+
diff --git a/eng/Versions.props b/eng/Versions.props
index df0077a0a312..61440c281ccb 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -57,7 +57,9 @@
3.0.0-preview8-27914-06
3.0.0-preview8-27914-06
3.0.0-preview8-27914-06
+ 3.0.0-preview8-27914-06
2.1.0-preview8-27914-06
+
1.0.0-preview8.19364.1
4.6.0-preview8.19364.1
diff --git a/eng/targets/Cpp.Common.targets b/eng/targets/Cpp.Common.targets
index f32f3f18213b..2b8733ae9f81 100644
--- a/eng/targets/Cpp.Common.targets
+++ b/eng/targets/Cpp.Common.targets
@@ -12,6 +12,7 @@
+
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 fa6326578ae2..f63ef673f4d9 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMIISExpressV2/ancm_iis_expressv2.wxs
@@ -35,10 +35,12 @@
+
+
@@ -177,6 +179,14 @@
+
+
+
+
+
+
+
+
@@ -251,10 +269,12 @@
+
+
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
index b04b1e21f5bd..fe294ee69302 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/ANCMV2/aspnetcoremodulev2.wxs
@@ -27,9 +27,11 @@
+
+
@@ -144,7 +146,7 @@
-
+
+
+
+
+
+
+
@@ -200,6 +212,16 @@
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props
index d08b147e4ae5..cab788f32c8e 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/Directory.Build.props
@@ -36,6 +36,8 @@
AspNetCoreSchemaPath=$(_ServerIISBasePath)AspNetCoreModuleV2\AspNetCore\aspnetcore_schema_v2.xml;
AspNetCoreMofPath=$(_ServerIISBasePath)AspNetCoreModuleV2\AspNetCore\ancm.mof;
+ NetHost64bit=$(Pkgruntime_win-x64_Microsoft_NETCore_DotNetAppHost)\runtimes\win-x64\native\nethost.dll;
+ NetHost32bit=$(Pkgruntime_win-x86_Microsoft_NETCore_DotNetAppHost)\runtimes\win-x86\native\nethost.dll;
$(DefineConstants)
@@ -70,5 +72,7 @@
false
Platform=Win32
+
+
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
index bb4202398864..bc82981e9c65 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
@@ -65,6 +65,7 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication
pApplication.GetApplicationPhysicalPath(),
pConfiguration.QueryArguments(),
errorContext,
+ m_hModule,
options));
location = options->GetDotnetExeLocation();
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp
index 9a80749f2c70..d2356f54c105 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.cpp
@@ -24,6 +24,7 @@ HRESULT HostFxrResolutionResult::Create(
_In_ const std::wstring& pcwzApplicationPhysicalPath,
_In_ const std::wstring& pcwzArguments,
_In_ ErrorContext& errorContext,
+ _In_ HMODULE aspNetCoreModule,
_Out_ std::unique_ptr& ppWrapper)
{
std::filesystem::path knownDotnetLocation;
@@ -44,7 +45,8 @@ HRESULT HostFxrResolutionResult::Create(
hostFxrDllPath,
knownDotnetLocation,
arguments,
- errorContext);
+ errorContext,
+ aspNetCoreModule);
LOG_INFOF(L"Parsed hostfxr options: dotnet location: '%ls' hostfxr path: '%ls' arguments:", knownDotnetLocation.c_str(), hostFxrDllPath.c_str());
for (size_t i = 0; i < arguments.size(); i++)
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h
index a0bbf1700356..a4e90451fb98 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolutionResult.h
@@ -47,6 +47,7 @@ class HostFxrResolutionResult
_In_ const std::wstring& pcwzApplicationPhysicalPath,
_In_ const std::wstring& pcwzArguments,
_In_ ErrorContext& errorContext,
+ _In_ HMODULE aspNetCoreModule,
_Out_ std::unique_ptr& ppWrapper);
private:
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp
index 45e3699fadc3..e972f726188c 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.cpp
@@ -11,9 +11,13 @@
#include "Environment.h"
#include "StringHelpers.h"
#include "RegistryKey.h"
+#include "ModuleHelpers.h"
+#include "GlobalVersionUtility.h"
namespace fs = std::filesystem;
+typedef INT(*get_hostfxr_path) (PWSTR buffer, size_t* bufferSize, PCWSTR assemblyPath);
+
void
HostFxrResolver::GetHostFxrParameters(
const fs::path &processPath,
@@ -22,7 +26,8 @@ HostFxrResolver::GetHostFxrParameters(
fs::path &hostFxrDllPath,
fs::path &dotnetExePath,
std::vector &arguments,
- ErrorContext& errorContext
+ ErrorContext& errorContext,
+ HMODULE aspNetCoreModule
)
{
LOG_INFOF(L"Resolving hostfxr parameters for application: '%ls' arguments: '%ls' path: '%ls'",
@@ -46,7 +51,17 @@ HostFxrResolver::GetHostFxrParameters(
throw InvalidOperationException(format(L"Process path '%s' doesn't have '.exe' extension.", expandedProcessPath.c_str()));
}
- // Check if the absolute path is to dotnet or not.
+ // TODO make sure we figure out a way to load this dll sxs
+ std::wstring modulePath = GlobalVersionUtility::GetModuleName(aspNetCoreModule);
+
+ // If we are in the shim, load hostfxr.
+ // Otherwise, throw.
+ // I think we need to assume that hostfxr is loaded by the shim.
+ // but we may need a backup, which really sucks.
+ modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
+
+ auto moduleHandle = LoadLibrary(modulePath.append(L"\\nethost.dll").c_str());
+
if (IsDotnetExecutable(expandedProcessPath))
{
LOG_INFOF(L"Process path '%ls' is dotnet, treating application as portable", expandedProcessPath.c_str());
@@ -58,17 +73,45 @@ HostFxrResolver::GetHostFxrParameters(
if (dotnetExePath.empty())
{
- dotnetExePath = GetAbsolutePathToDotnet(applicationPhysicalPath, expandedProcessPath);
- }
+ if (moduleHandle != nullptr)
+ {
+ auto get_host_fxr_path = ModuleHelpers::GetKnownProcAddress(moduleHandle, "get_hostfxr_path");
+
+ std::wstring hostfxrPath;
+ size_t size = MAX_PATH * 2;
+ hostfxrPath.resize(size);
+
+ AppendArguments(
+ expandedApplicationArguments,
+ applicationPhysicalPath,
+ arguments,
+ true);
+
+ get_host_fxr_path(hostfxrPath.data(), &size, arguments[0].c_str());
- hostFxrDllPath = GetAbsolutePathToHostFxr(dotnetExePath);
+ // If this fails, path probe
- arguments.push_back(dotnetExePath);
- AppendArguments(
- expandedApplicationArguments,
- applicationPhysicalPath,
- arguments,
- true);
+ hostfxrPath.resize(size);
+ hostFxrDllPath = hostfxrPath;
+ dotnetExePath = GetAbsolutePathToDotnetFromHostfxr(hostFxrDllPath);
+
+ arguments.insert(arguments.begin(), dotnetExePath);
+ }
+ else
+ {
+ // TODO need to review 2.2 code, this may need to still be allowed for handler if we shipped 2.2 without this assumption
+ throw InvalidOperationException(L"Must have hostfxr loaded in shim or have nethost.dll next to app.");
+ }
+ }
+ else
+ {
+ arguments.push_back(dotnetExePath);
+ AppendArguments(
+ expandedApplicationArguments,
+ applicationPhysicalPath,
+ arguments,
+ true);
+ }
}
else
{
@@ -113,17 +156,31 @@ HostFxrResolver::GetHostFxrParameters(
}
else
{
- LOG_INFOF(L"hostfxr.dll found app local at '%ls', treating application as portable with launcher", hostFxrDllPath.c_str());
-
- // passing "dotnet" here because we don't know where dotnet.exe should come from
- // so trying all fallbacks is appropriate
if (dotnetExePath.empty())
{
- dotnetExePath = GetAbsolutePathToDotnet(applicationPhysicalPath, L"dotnet");
+ if (moduleHandle != nullptr)
+ {
+ auto get_host_fxr_path = ModuleHelpers::GetKnownProcAddress(moduleHandle, "get_hostfxr_path");
+
+ LOG_INFOF(L"hostfxr.dll found app local at '%ls', treating application as portable with launcher", hostFxrDllPath.c_str());
+
+ std::wstring hostfxrPath;
+ size_t size = MAX_PATH * 2;
+ hostfxrPath.resize(size);
+
+ get_host_fxr_path(hostfxrPath.data(), &size, applicationDllPath.c_str());
+ hostfxrPath.resize(size);
+ hostFxrDllPath = hostfxrPath;
+
+ dotnetExePath = GetAbsolutePathToDotnetFromHostfxr(hostFxrDllPath);
+ }
+ else
+ {
+ // TODO need to review 2.2 code, this may need to still be allowed for handler if we shipped 2.2 without this assumption
+ throw InvalidOperationException(L"Must have hostfxr loaded in shim or have nethost.dll next to app.");
+ }
}
- hostFxrDllPath = GetAbsolutePathToHostFxr(dotnetExePath);
- // For portable with launcher apps we need dotnet.exe to be argv[0] and .dll be argv[1]
arguments.push_back(dotnetExePath);
arguments.push_back(applicationDllPath);
}
@@ -144,12 +201,6 @@ HostFxrResolver::GetHostFxrParameters(
}
}
-BOOL
-HostFxrResolver::IsDotnetExecutable(const std::filesystem::path & dotnetPath)
-{
- return ends_with(dotnetPath, L"dotnet.exe", true);
-}
-
void
HostFxrResolver::AppendArguments(
const std::wstring &applicationArguments,
@@ -219,324 +270,14 @@ HostFxrResolver::AppendArguments(
}
}
-// The processPath ends with dotnet.exe or dotnet
-// like: C:\Program Files\dotnet\dotnet.exe, C:\Program Files\dotnet\dotnet, dotnet.exe, or dotnet.
-// Get the absolute path to dotnet. If the path is already an absolute path, it will return that path
fs::path
-HostFxrResolver::GetAbsolutePathToDotnet(
- const fs::path & applicationPath,
- const fs::path & requestedPath
-)
+HostFxrResolver::GetAbsolutePathToDotnetFromHostfxr(const fs::path& hostfxrPath)
{
- LOG_INFOF(L"Resolving absolute path to dotnet.exe from '%ls'", requestedPath.c_str());
-
- auto processPath = requestedPath;
- if (processPath.is_relative())
- {
- processPath = applicationPath / processPath;
- }
-
- //
- // If we are given an absolute path to dotnet.exe, we are done
- //
- if (is_regular_file(processPath))
- {
- LOG_INFOF(L"Found dotnet.exe at '%ls'", processPath.c_str());
-
- return processPath;
- }
-
- // At this point, we are calling where.exe to find dotnet.
- // If we encounter any failures, try getting dotnet.exe from the
- // backup location.
- // Only do it if no path is specified
- if (requestedPath.has_parent_path())
- {
- LOG_INFOF(L"Absolute path to dotnet.exe was not found at '%ls'", requestedPath.c_str());
-
- throw InvalidOperationException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str()));
- }
-
- const auto dotnetViaWhere = InvokeWhereToFindDotnet();
- if (dotnetViaWhere.has_value())
- {
- LOG_INFOF(L"Found dotnet.exe via where.exe invocation at '%ls'", dotnetViaWhere.value().c_str());
-
- return dotnetViaWhere.value();
- }
-
- auto isWow64Process = Environment::IsRunning64BitProcess();
-
- std::wstring regKeySubSection;
-
- if (isWow64Process)
- {
- regKeySubSection = L"SOFTWARE\\WOW6432Node\\dotnet\\Setup\\InstalledVersions\\x64";
- }
- else
- {
- regKeySubSection = L"SOFTWARE\\dotnet\\Setup\\InstalledVersions\\x86";
- }
-
- const auto installationLocation = RegistryKey::TryGetString(
- HKEY_LOCAL_MACHINE,
- regKeySubSection,
- L"InstallLocation");
-
- if (installationLocation.has_value())
- {
- LOG_INFOF(L"InstallLocation registry key is set to '%ls'", installationLocation.value().c_str());
-
- auto const installationLocationDotnet = fs::path(installationLocation.value()) / "dotnet.exe";
-
- if (is_regular_file(installationLocationDotnet))
- {
- LOG_INFOF(L"Found dotnet.exe in InstallLocation at '%ls'", installationLocationDotnet.c_str());
- return installationLocationDotnet;
- }
- }
-
- const auto programFilesLocation = GetAbsolutePathToDotnetFromProgramFiles();
- if (programFilesLocation.has_value())
- {
- LOG_INFOF(L"Found dotnet.exe in Program Files at '%ls'", programFilesLocation.value().c_str());
-
- return programFilesLocation.value();
- }
-
- LOG_INFOF(L"dotnet.exe not found");
- throw InvalidOperationException(format(
- L"Could not find dotnet.exe at '%s' or using the system PATH environment variable."
- " Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process.",
- processPath.c_str()));
+ return hostfxrPath.parent_path().parent_path().parent_path().parent_path() / "dotnet.exe";
}
-fs::path
-HostFxrResolver::GetAbsolutePathToHostFxr(
- const fs::path & dotnetPath
-)
-{
- std::vector versionFolders;
- const auto hostFxrBase = dotnetPath.parent_path() / "host" / "fxr";
-
- LOG_INFOF(L"Resolving absolute path to hostfxr.dll from '%ls'", dotnetPath.c_str());
-
- if (!is_directory(hostFxrBase))
- {
- throw InvalidOperationException(format(L"Unable to find hostfxr directory at %s", hostFxrBase.c_str()));
- }
-
- FindDotNetFolders(hostFxrBase, versionFolders);
-
- if (versionFolders.empty())
- {
- throw InvalidOperationException(format(L"Hostfxr directory '%s' doesn't contain any version subdirectories", hostFxrBase.c_str()));
- }
-
- const auto highestVersion = FindHighestDotNetVersion(versionFolders);
- const auto hostFxrPath = hostFxrBase / highestVersion / "hostfxr.dll";
-
- if (!is_regular_file(hostFxrPath))
- {
- throw InvalidOperationException(format(L"hostfxr.dll not found at '%s'", hostFxrPath.c_str()));
- }
-
- LOG_INFOF(L"hostfxr.dll located at '%ls'", hostFxrPath.c_str());
- return hostFxrPath;
-}
-
-//
-// Tries to call where.exe to find the location of dotnet.exe.
-// Will check that the bitness of dotnet matches the current
-// worker process bitness.
-// Returns true if a valid dotnet was found, else false.R
-//
-std::optional
-HostFxrResolver::InvokeWhereToFindDotnet()
-{
- HRESULT hr = S_OK;
- // Arguments to call where.exe
- STARTUPINFOW startupInfo = { 0 };
- PROCESS_INFORMATION processInformation = { 0 };
- SECURITY_ATTRIBUTES securityAttributes;
-
- CHAR pzFileContents[READ_BUFFER_SIZE];
- HandleWrapper hStdOutReadPipe;
- HandleWrapper hStdOutWritePipe;
- HandleWrapper hProcess;
- HandleWrapper hThread;
- CComBSTR pwzDotnetName = NULL;
- DWORD dwFilePointer;
- BOOL fIsCurrentProcess64Bit;
- DWORD dwExitCode;
- STRU struDotnetSubstring;
- STRU struDotnetLocationsString;
- DWORD dwNumBytesRead;
- DWORD dwBinaryType;
- INT index = 0;
- INT prevIndex = 0;
- std::optional result;
-
- // Set the security attributes for the read/write pipe
- securityAttributes.nLength = sizeof(securityAttributes);
- securityAttributes.lpSecurityDescriptor = NULL;
- securityAttributes.bInheritHandle = TRUE;
-
- LOG_INFO(L"Invoking where.exe to find dotnet.exe");
-
- // Create a read/write pipe that will be used for reading the result of where.exe
- FINISHED_LAST_ERROR_IF(!CreatePipe(&hStdOutReadPipe, &hStdOutWritePipe, &securityAttributes, 0));
- FINISHED_LAST_ERROR_IF(!SetHandleInformation(hStdOutReadPipe, HANDLE_FLAG_INHERIT, 0));
-
- // Set the stdout and err pipe to the write pipes.
- startupInfo.cb = sizeof(startupInfo);
- startupInfo.dwFlags |= STARTF_USESTDHANDLES;
- startupInfo.hStdOutput = hStdOutWritePipe;
- startupInfo.hStdError = hStdOutWritePipe;
-
- // CreateProcess requires a mutable string to be passed to commandline
- // See https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083/
- pwzDotnetName = L"\"where.exe\" dotnet.exe";
-
- // Create a process to invoke where.exe
- FINISHED_LAST_ERROR_IF(!CreateProcessW(NULL,
- pwzDotnetName,
- NULL,
- NULL,
- TRUE,
- CREATE_NO_WINDOW,
- NULL,
- NULL,
- &startupInfo,
- &processInformation
- ));
-
- // Store handles into wrapper so they get closed automatically
- hProcess = processInformation.hProcess;
- hThread = processInformation.hThread;
-
- // Wait for where.exe to return
- WaitForSingleObject(processInformation.hProcess, INFINITE);
-
- //
- // where.exe will return 0 on success, 1 if the file is not found
- // and 2 if there was an error. Check if the exit code is 1 and set
- // a new hr result saying it couldn't find dotnet.exe
- //
- FINISHED_LAST_ERROR_IF (!GetExitCodeProcess(processInformation.hProcess, &dwExitCode));
-
- //
- // In this block, if anything fails, we will goto our fallback of
- // looking in C:/Program Files/
- //
- if (dwExitCode != 0)
- {
- FINISHED_IF_FAILED(E_FAIL);
- }
-
- // Where succeeded.
- // Reset file pointer to the beginning of the file.
- dwFilePointer = SetFilePointer(hStdOutReadPipe, 0, NULL, FILE_BEGIN);
- if (dwFilePointer == INVALID_SET_FILE_POINTER)
- {
- FINISHED_IF_FAILED(E_FAIL);
- }
-
- //
- // As the call to where.exe succeeded (dotnet.exe was found), ReadFile should not hang.
- // TODO consider putting ReadFile in a separate thread with a timeout to guarantee it doesn't block.
- //
- FINISHED_LAST_ERROR_IF (!ReadFile(hStdOutReadPipe, pzFileContents, READ_BUFFER_SIZE, &dwNumBytesRead, NULL));
-
- if (dwNumBytesRead >= READ_BUFFER_SIZE)
- {
- // This shouldn't ever be this large. We could continue to call ReadFile in a loop,
- // however if someone had this many dotnet.exes on their machine.
- FINISHED_IF_FAILED(E_FAIL);
- }
-
- FINISHED_IF_FAILED(struDotnetLocationsString.CopyA(pzFileContents, dwNumBytesRead));
-
- LOG_INFOF(L"where.exe invocation returned: '%ls'", struDotnetLocationsString.QueryStr());
-
- fIsCurrentProcess64Bit = Environment::IsRunning64BitProcess();
-
- LOG_INFOF(L"Current process bitness type detected as isX64=%d", fIsCurrentProcess64Bit);
-
- while (TRUE)
- {
- index = struDotnetLocationsString.IndexOf(L"\r\n", prevIndex);
- if (index == -1)
- {
- break;
- }
-
- FINISHED_IF_FAILED(struDotnetSubstring.Copy(&struDotnetLocationsString.QueryStr()[prevIndex], index - prevIndex));
- // \r\n is two wchars, so add 2 here.
- prevIndex = index + 2;
-
- LOG_INFOF(L"Processing entry '%ls'", struDotnetSubstring.QueryStr());
-
- if (LOG_LAST_ERROR_IF(!GetBinaryTypeW(struDotnetSubstring.QueryStr(), &dwBinaryType)))
- {
- continue;
- }
-
- LOG_INFOF(L"Binary type %d", dwBinaryType);
-
- if (fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
- {
- // The bitness of dotnet matched with the current worker process bitness.
- return std::make_optional(struDotnetSubstring.QueryStr());
- }
- }
-
- Finished:
- return result;
-}
-
-std::optional
-HostFxrResolver::GetAbsolutePathToDotnetFromProgramFiles()
-{
- const auto programFilesDotnet = fs::path(Environment::ExpandEnvironmentVariables(L"%ProgramFiles%")) / "dotnet" / "dotnet.exe";
- return is_regular_file(programFilesDotnet) ? std::make_optional(programFilesDotnet) : std::nullopt;
-}
-
-std::wstring
-HostFxrResolver::FindHighestDotNetVersion(
- _In_ std::vector & vFolders
-)
-{
- fx_ver_t max_ver(-1, -1, -1);
- for (const auto& dir : vFolders)
- {
- fx_ver_t fx_ver(-1, -1, -1);
- if (fx_ver_t::parse(dir, &fx_ver, false))
- {
- max_ver = max(max_ver, fx_ver);
- }
- }
-
- return max_ver.as_str();
-}
-
-VOID
-HostFxrResolver::FindDotNetFolders(
- const std::filesystem::path &path,
- _Out_ std::vector &pvFolders
-)
+BOOL
+HostFxrResolver::IsDotnetExecutable(const std::filesystem::path& dotnetPath)
{
- WIN32_FIND_DATAW data = {};
- const auto searchPattern = std::wstring(path) + L"\\*";
- HandleWrapper handle = FindFirstFileExW(searchPattern.c_str(), FindExInfoStandard, &data, FindExSearchNameMatch, nullptr, 0);
- if (handle == INVALID_HANDLE_VALUE)
- {
- LOG_LAST_ERROR();
- return;
- }
-
- do
- {
- pvFolders.emplace_back(data.cFileName);
- } while (FindNextFileW(handle, &data));
+ return ends_with(dotnetPath, L"dotnet.exe", true);
}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h
index 70f63fca6f90..ea67d692f17a 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/HostFxrResolver.h
@@ -26,7 +26,8 @@ class HostFxrResolver
std::filesystem::path &hostFxrDllPath,
std::filesystem::path &dotnetExePath,
std::vector &arguments,
- ErrorContext& errorContext
+ ErrorContext& errorContext,
+ HMODULE aspNetCoreModule
);
static
@@ -38,9 +39,6 @@ class HostFxrResolver
bool expandDllPaths = false
);
- static
- std::optional
- GetAbsolutePathToDotnetFromProgramFiles();
private:
static
@@ -49,35 +47,9 @@ class HostFxrResolver
const std::filesystem::path & dotnetPath
);
- static
- VOID
- FindDotNetFolders(
- const std::filesystem::path& path,
- std::vector & pvFolders
- );
-
- static
- std::wstring
- FindHighestDotNetVersion(
- std::vector & vFolders
- );
-
static
std::filesystem::path
- GetAbsolutePathToHostFxr(
- const std::filesystem::path & dotnetPath
- );
-
- static
- std::optional
- InvokeWhereToFindDotnet();
-
- static
- std::filesystem::path
- GetAbsolutePathToDotnet(
- const std::filesystem::path & applicationPath,
- const std::filesystem::path & requestedPath
- );
+ GetAbsolutePathToDotnetFromHostfxr(const std::filesystem::path& hostfxrPath);
struct LocalFreeDeleter
{
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp
deleted file mode 100644
index 060224c60d9b..000000000000
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the MIT License. See License.txt in the project root for license information.
-
-#include "hostfxroptions.h"
-
-#include "hostfxr_utility.h"
-#include "debugutil.h"
-#include "exceptions.h"
-#include "EventLog.h"
-
-HRESULT HOSTFXR_OPTIONS::Create(
- _In_ const std::wstring& pcwzDotnetExePath,
- _In_ const std::wstring& pcwzProcessPath,
- _In_ const std::wstring& pcwzApplicationPhysicalPath,
- _In_ const std::wstring& pcwzArguments,
- _Out_ std::unique_ptr& ppWrapper)
-{
- std::filesystem::path knownDotnetLocation;
-
- if (!pcwzDotnetExePath.empty())
- {
- knownDotnetLocation = pcwzDotnetExePath;
- }
-
- try
- {
- std::filesystem::path hostFxrDllPath;
- std::vector arguments;
- HOSTFXR_UTILITY::GetHostFxrParameters(
- pcwzProcessPath,
- pcwzApplicationPhysicalPath,
- pcwzArguments,
- hostFxrDllPath,
- knownDotnetLocation,
- arguments);
-
- LOG_INFOF(L"Parsed hostfxr options: dotnet location: '%ls' hostfxr path: '%ls' arguments:", knownDotnetLocation.c_str(), hostFxrDllPath.c_str());
- for (size_t i = 0; i < arguments.size(); i++)
- {
- LOG_INFOF(L"Argument[%d] = '%ls'", i, arguments[i].c_str());
- }
- ppWrapper = std::make_unique(knownDotnetLocation, hostFxrDllPath, arguments);
- }
- catch (InvalidOperationException &ex)
- {
- EventLog::Error(
- ASPNETCORE_EVENT_INPROCESS_START_ERROR,
- ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG,
- pcwzApplicationPhysicalPath.c_str(),
- ex.as_wstring().c_str());
-
- RETURN_CAUGHT_EXCEPTION();
- }
- catch (std::runtime_error &ex)
- {
- EventLog::Error(
- ASPNETCORE_EVENT_INPROCESS_START_ERROR,
- ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG,
- pcwzApplicationPhysicalPath.c_str(),
- GetUnexpectedExceptionMessage(ex).c_str());
-
- RETURN_CAUGHT_EXCEPTION();
- }
- CATCH_RETURN();
-
- return S_OK;
-}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.h
deleted file mode 100644
index 243cc53ae7b8..000000000000
--- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/hostfxroptions.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the MIT License. See License.txt in the project root for license information.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-class HOSTFXR_OPTIONS
-{
-public:
- HOSTFXR_OPTIONS(
- std::filesystem::path dotnetExeLocation,
- std::filesystem::path hostFxrLocation,
- std::vector arguments
- ) noexcept
- : m_dotnetExeLocation(std::move(dotnetExeLocation)),
- m_hostFxrLocation(std::move(hostFxrLocation)),
- m_arguments(std::move(arguments))
- {}
-
- void
- GetArguments(DWORD &hostfxrArgc, std::unique_ptr &hostfxrArgv) const
- {
- hostfxrArgc = static_cast(m_arguments.size());
- hostfxrArgv = std::make_unique(hostfxrArgc);
- for (DWORD i = 0; i < hostfxrArgc; ++i)
- {
- hostfxrArgv[i] = m_arguments[i].c_str();
- }
- }
-
- const std::filesystem::path&
- GetHostFxrLocation() const noexcept
- {
- return m_hostFxrLocation;
- }
-
- const std::filesystem::path&
- GetDotnetExeLocation() const noexcept
- {
- return m_dotnetExeLocation;
- }
-
- static
- HRESULT Create(
- _In_ const std::wstring& pcwzExeLocation,
- _In_ const std::wstring& pcwzProcessPath,
- _In_ const std::wstring& pcwzApplicationPhysicalPath,
- _In_ const std::wstring& pcwzArguments,
- _Out_ std::unique_ptr& ppWrapper);
-
-private:
- const std::filesystem::path m_dotnetExeLocation;
- const std::filesystem::path m_hostFxrLocation;
- const std::vector m_arguments;
-};
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp
new file mode 100644
index 000000000000..f3530e3254e8
--- /dev/null
+++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/hostfxr_utility_tests.cpp
@@ -0,0 +1,52 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+#include "stdafx.h"
+#include
+#include
+#include
+#include "HostFxrResolver.h"
+#include "Environment.h"
+
+TEST(ParseHostFxrArguments, BasicHostFxrArguments)
+{
+ std::vector bstrArray;
+
+ HostFxrResolver::AppendArguments(
+ L"exec \"test.dll\"", // args
+ L"invalid", // physical path to application
+ bstrArray); // args array.
+
+ EXPECT_EQ(2, bstrArray.size());
+ ASSERT_STREQ(L"exec", bstrArray[0].c_str());
+ ASSERT_STREQ(L"test.dll", bstrArray[1].c_str());
+}
+
+TEST(ParseHostFxrArguments, NoExecProvided)
+{
+ std::vector bstrArray;
+
+ HostFxrResolver::AppendArguments(
+ L"test.dll", // args
+ L"ignored", // physical path to application
+ bstrArray); // args array.
+
+ EXPECT_EQ(1, bstrArray.size());
+ ASSERT_STREQ(L"test.dll", bstrArray[0].c_str());
+}
+
+TEST(ParseHostFxrArguments, ConvertDllToAbsolutePath)
+{
+ std::vector bstrArray;
+ // we need to use existing dll so let's use ntdll that we know exists everywhere
+ auto system32 = Environment::ExpandEnvironmentVariables(L"%WINDIR%\\System32");
+ HostFxrResolver::AppendArguments(
+ L"exec \"ntdll.dll\"", // args
+ system32, // physical path to application
+ bstrArray, // args array.
+ true); // expandDllPaths
+
+ EXPECT_EQ(2, bstrArray.size());
+ ASSERT_STREQ(L"exec", bstrArray[0].c_str());
+ ASSERT_STREQ((system32 + L"\\ntdll.dll").c_str(), bstrArray[1].c_str());
+}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
index 5707e4cd7728..dfe17f645b1f 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
@@ -195,7 +195,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
auto context = std::make_shared();
- ErrorContext errorContext; // unused
+ ErrorContext errorContext; // unused
if (s_fMainCallback == nullptr)
{
@@ -205,6 +205,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication()
QueryApplicationPhysicalPath(),
m_pConfig->QueryArguments(),
errorContext,
+ GetModuleHandle(TEXT("aspnetcorev2.dll")),
hostFxrResolutionResult
));
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs
index 11467d4424bc..cac6bcc70d77 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs
@@ -15,7 +15,6 @@
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
-using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Win32;
using Xunit;
@@ -44,8 +43,6 @@ public async Task ExpandEnvironmentVariableInWebConfig()
[ConditionalTheory]
[InlineData("bogus", "", @"Executable was not found at '.*?\\bogus.exe")]
- [InlineData("c:\\random files\\dotnet.exe", "something.dll", @"Could not find dotnet.exe at '.*?\\dotnet.exe'")]
- [InlineData(".\\dotnet.exe", "something.dll", @"Could not find dotnet.exe at '.*?\\.\\dotnet.exe'")]
[InlineData("dotnet.exe", "", @"Application arguments are empty.")]
[InlineData("dotnet.zip", "", @"Process path 'dotnet.zip' doesn't have '.exe' extension.")]
public async Task InvalidProcessPath_ExpectServerError(string path, string arguments, string subError)
@@ -104,8 +101,6 @@ public async Task StartsWithDotnetOnThePath(string path)
await deploymentResult.AssertStarts();
StopServer();
- // Verify that in this scenario where.exe was invoked only once by shim and request handler uses cached value
- Assert.Equal(1, TestSink.Writes.Count(w => w.Message.Contains("Invoking where.exe to find dotnet.exe")));
}
[ConditionalTheory]
@@ -140,7 +135,6 @@ public async Task StartsWithDotnetInstallLocation(RuntimeArchitecture runtimeArc
// Verify that in this scenario dotnet.exe was found using InstallLocation lookup
// I would've liked to make a copy of dotnet directory in this test and use it for verification
// but dotnet roots are usually very large on dev machines so this test would take disproportionally long time and disk space
- Assert.Equal(1, TestSink.Writes.Count(w => w.Message.Contains($"Found dotnet.exe in InstallLocation at '{installDir}\\dotnet.exe'")));
}
}
}
diff --git a/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj b/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
index 424be8c5f5d6..1bc403b14b5f 100644
--- a/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
+++ b/src/Servers/IIS/IntegrationTesting.IIS/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
@@ -45,6 +45,8 @@
+
+
@@ -61,6 +63,8 @@
+
+
diff --git a/src/Servers/IIS/build.cmd b/src/Servers/IIS/build.cmd
index 4369bfd550d3..ceccd91c6eaa 100644
--- a/src/Servers/IIS/build.cmd
+++ b/src/Servers/IIS/build.cmd
@@ -1,3 +1,3 @@
@ECHO OFF
SET RepoRoot=%~dp0..\..\..
-%RepoRoot%\build.cmd -BuildNative -projects %~dp0**\*.csproj %*
+%RepoRoot%\build.cmd -BuildNative -projects %~dp0**\*.csproj %*