Add tests for processpath and arguments (#1331)
This commit is contained in:
parent
6ddbfb64b9
commit
9b68c5ce89
|
|
@ -108,7 +108,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, Shim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Loading request handler: %S", handlerDllPath.c_str());
|
LOG_INFOF(L"Loading request handler: '%ls'", handlerDllPath.c_str());
|
||||||
|
|
||||||
hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str());
|
hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str());
|
||||||
if (preventUnload)
|
if (preventUnload)
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ APPLICATION_INFO::GetOrCreateApplication(
|
||||||
{
|
{
|
||||||
if (m_pApplication->QueryStatus() == RECYCLED)
|
if (m_pApplication->QueryStatus() == RECYCLED)
|
||||||
{
|
{
|
||||||
LOG_INFO("Application went offline");
|
LOG_INFO(L"Application went offline");
|
||||||
|
|
||||||
// Call to wait for application to complete stopping
|
// Call to wait for application to complete stopping
|
||||||
m_pApplication->Stop(/* fServerInitiated */ false);
|
m_pApplication->Stop(/* fServerInitiated */ false);
|
||||||
|
|
@ -50,14 +50,14 @@ APPLICATION_INFO::GetOrCreateApplication(
|
||||||
|
|
||||||
if (AppOfflineApplication::ShouldBeStarted(httpApplication))
|
if (AppOfflineApplication::ShouldBeStarted(httpApplication))
|
||||||
{
|
{
|
||||||
LOG_INFO("Detected app_offline file, creating polling application");
|
LOG_INFO(L"Detected app_offline file, creating polling application");
|
||||||
m_pApplication.reset(new AppOfflineApplication(httpApplication));
|
m_pApplication.reset(new AppOfflineApplication(httpApplication));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FINISHED_IF_FAILED(m_handlerResolver.GetApplicationFactory(httpApplication, m_pApplicationFactory));
|
FINISHED_IF_FAILED(m_handlerResolver.GetApplicationFactory(httpApplication, m_pApplicationFactory));
|
||||||
|
|
||||||
LOG_INFO("Creating handler application");
|
LOG_INFO(L"Creating handler application");
|
||||||
IAPPLICATION * newApplication;
|
IAPPLICATION * newApplication;
|
||||||
FINISHED_IF_FAILED(m_pApplicationFactory->Execute(
|
FINISHED_IF_FAILED(m_pApplicationFactory->Execute(
|
||||||
&m_pServer,
|
&m_pServer,
|
||||||
|
|
@ -97,7 +97,7 @@ APPLICATION_INFO::ShutDownApplication(bool fServerInitiated)
|
||||||
|
|
||||||
if (m_pApplication)
|
if (m_pApplication)
|
||||||
{
|
{
|
||||||
LOG_ERRORF("Stopping application %S", QueryApplicationInfoKey().c_str());
|
LOG_ERRORF(L"Stopping application '%ls'", QueryApplicationInfoKey().c_str());
|
||||||
m_pApplication ->Stop(fServerInitiated);
|
m_pApplication ->Stop(fServerInitiated);
|
||||||
m_pApplication = nullptr;
|
m_pApplication = nullptr;
|
||||||
m_pApplicationFactory = nullptr;
|
m_pApplicationFactory = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ APPLICATION_MANAGER::RecycleApplicationFromManager(
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
LOG_ERRORF("Failed to stop application %S", application->QueryApplicationInfoKey().c_str());
|
LOG_ERRORF(L"Failed to stop application '%ls'", application->QueryApplicationInfoKey().c_str());
|
||||||
OBSERVE_CAUGHT_EXCEPTION();
|
OBSERVE_CAUGHT_EXCEPTION();
|
||||||
|
|
||||||
// Failed to recycle an application. Log an event
|
// Failed to recycle an application. Log an event
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ ASPNET_CORE_GLOBAL_MODULE::OnGlobalStopListening(
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(pProvider);
|
UNREFERENCED_PARAMETER(pProvider);
|
||||||
|
|
||||||
LOG_INFO("ASPNET_CORE_GLOBAL_MODULE::OnGlobalStopListening");
|
LOG_INFO(L"ASPNET_CORE_GLOBAL_MODULE::OnGlobalStopListening");
|
||||||
|
|
||||||
if (g_fInShutdown)
|
if (g_fInShutdown)
|
||||||
{
|
{
|
||||||
|
|
@ -56,7 +56,7 @@ ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange(
|
||||||
// Retrieve the path that has changed.
|
// Retrieve the path that has changed.
|
||||||
PCWSTR pwszChangePath = pProvider->GetChangePath();
|
PCWSTR pwszChangePath = pProvider->GetChangePath();
|
||||||
|
|
||||||
LOG_INFOF("ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange %S", pwszChangePath);
|
LOG_INFOF(L"ASPNET_CORE_GLOBAL_MODULE::OnGlobalConfigurationChange '%ls'", pwszChangePath);
|
||||||
|
|
||||||
// Test for an error.
|
// Test for an error.
|
||||||
if (NULL != pwszChangePath &&
|
if (NULL != pwszChangePath &&
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ public:
|
||||||
|
|
||||||
VOID Terminate()
|
VOID Terminate()
|
||||||
{
|
{
|
||||||
LOG_INFO("ASPNET_CORE_GLOBAL_MODULE::Terminate");
|
LOG_INFO(L"ASPNET_CORE_GLOBAL_MODULE::Terminate");
|
||||||
// Remove the class from memory.
|
// Remove the class from memory.
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ EventLog::LogEvent(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugPrintf(dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO, "Event Log: %S \r\nEnd Event Log Message.", pstrMsg);
|
DebugPrintfW(dwEventInfoType == EVENTLOG_ERROR_TYPE ? ASPNETCORE_DEBUG_FLAG_ERROR : ASPNETCORE_DEBUG_FLAG_INFO, L"Event Log: '%ls' \r\nEnd Event Log Message.", pstrMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ HRESULT PipeOutputManager::Stop()
|
||||||
if (!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
|
if (!LOG_LAST_ERROR_IF(GetExitCodeThread(m_hErrThread, &dwThreadStatus) == 0) &&
|
||||||
dwThreadStatus == STILL_ACTIVE)
|
dwThreadStatus == STILL_ACTIVE)
|
||||||
{
|
{
|
||||||
LOG_WARN("Thread reading stdout/err hit timeout, forcibly closing thread.");
|
LOG_WARN(L"Thread reading stdout/err hit timeout, forcibly closing thread.");
|
||||||
TerminateThread(m_hErrThread, STATUS_CONTROL_C_EXIT);
|
TerminateThread(m_hErrThread, STATUS_CONTROL_C_EXIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ HRESULT
|
||||||
PrintDebugHeader()
|
PrintDebugHeader()
|
||||||
{
|
{
|
||||||
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
|
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
|
||||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "Initializing logs for %S. %S. %S.",
|
DebugPrintfW(ASPNETCORE_DEBUG_FLAG_INFO, L"Initializing logs for '%ls'. %ls. %ls.",
|
||||||
GetModuleName().c_str(),
|
GetModuleName().c_str(),
|
||||||
GetProcessIdString().c_str(),
|
GetProcessIdString().c_str(),
|
||||||
GetVersionInfoString().c_str()
|
GetVersionInfoString().c_str()
|
||||||
|
|
@ -86,7 +86,7 @@ std::wstring
|
||||||
GetModuleName()
|
GetModuleName()
|
||||||
{
|
{
|
||||||
WCHAR path[MAX_PATH];
|
WCHAR path[MAX_PATH];
|
||||||
LOG_LAST_ERROR_IF(GetModuleFileName(g_hModule, path, sizeof(path)));
|
LOG_LAST_ERROR_IF(!GetModuleFileName(g_hModule, path, sizeof(path)));
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +146,7 @@ bool CreateDebugLogFile(const std::wstring &debugOutputFile)
|
||||||
{
|
{
|
||||||
if (g_logFile != INVALID_HANDLE_VALUE)
|
if (g_logFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
LOG_INFOF("Switching debug log files to %S", debugOutputFile.c_str());
|
LOG_INFOF(L"Switching debug log files to '%ls'", debugOutputFile.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SRWExclusiveLock lock(g_logFileLock);
|
SRWExclusiveLock lock(g_logFileLock);
|
||||||
|
|
@ -296,19 +296,29 @@ IsEnabled(
|
||||||
return ( dwFlag & DEBUG_FLAGS_VAR );
|
return ( dwFlag & DEBUG_FLAGS_VAR );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WriteFileEncoded(UINT codePage, HANDLE hFile, const LPCWSTR szString)
|
||||||
|
{
|
||||||
|
DWORD nBytesWritten = 0;
|
||||||
|
auto const encodedByteCount = WideCharToMultiByte(codePage, 0, szString, -1, nullptr, 0, nullptr, nullptr);
|
||||||
|
auto encodedBytes = std::shared_ptr<CHAR[]>(new CHAR[encodedByteCount]);
|
||||||
|
WideCharToMultiByte(codePage, 0, szString, -1, encodedBytes.get(), encodedByteCount, nullptr, nullptr);
|
||||||
|
|
||||||
|
WriteFile(hFile, encodedBytes.get(), encodedByteCount - 1, &nBytesWritten, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
DebugPrint(
|
DebugPrintW(
|
||||||
DWORD dwFlag,
|
DWORD dwFlag,
|
||||||
const LPCSTR szString
|
const LPCWSTR szString
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
STACK_STRA (strOutput, 256);
|
STACK_STRU (strOutput, 256);
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
if ( IsEnabled( dwFlag ) )
|
if ( IsEnabled( dwFlag ) )
|
||||||
{
|
{
|
||||||
hr = strOutput.SafeSnprintf(
|
hr = strOutput.SafeSnwprintf(
|
||||||
"[%s] %s\r\n",
|
L"[%S] %s\r\n",
|
||||||
DEBUG_LABEL_VAR, szString );
|
DEBUG_LABEL_VAR, szString );
|
||||||
|
|
||||||
if (FAILED (hr))
|
if (FAILED (hr))
|
||||||
|
|
@ -316,22 +326,68 @@ DebugPrint(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputDebugStringA( strOutput.QueryStr() );
|
OutputDebugString( strOutput.QueryStr() );
|
||||||
DWORD nBytesWritten = 0;
|
|
||||||
if (IsEnabled(ASPNETCORE_DEBUG_FLAG_CONSOLE))
|
if (IsEnabled(ASPNETCORE_DEBUG_FLAG_CONSOLE) || g_logFile != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
auto outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
if (IsEnabled(ASPNETCORE_DEBUG_FLAG_CONSOLE))
|
||||||
WriteFile(outputHandle, strOutput.QueryStr(), strOutput.QueryCB(), &nBytesWritten, nullptr);
|
{
|
||||||
|
WriteFileEncoded(GetConsoleOutputCP(), GetStdHandle(STD_OUTPUT_HANDLE), strOutput.QueryStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_logFile != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
SRWExclusiveLock lock(g_logFileLock);
|
||||||
|
|
||||||
|
SetFilePointer(g_logFile, 0, nullptr, FILE_END);
|
||||||
|
WriteFileEncoded(CP_UTF8, g_logFile, strOutput.QueryStr());
|
||||||
|
FlushFileBuffers(g_logFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
DebugPrintfW(
|
||||||
|
DWORD dwFlag,
|
||||||
|
const LPCWSTR szFormat,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
{
|
||||||
|
STACK_STRU (strCooked,256);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
if ( IsEnabled( dwFlag ) )
|
||||||
|
{
|
||||||
|
va_start( args, szFormat );
|
||||||
|
|
||||||
|
hr = strCooked.SafeVsnwprintf(szFormat, args );
|
||||||
|
|
||||||
|
va_end( args );
|
||||||
|
|
||||||
|
if (FAILED (hr))
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_logFile != INVALID_HANDLE_VALUE)
|
DebugPrintW( dwFlag, strCooked.QueryStr() );
|
||||||
{
|
}
|
||||||
SRWExclusiveLock lock(g_logFileLock);
|
}
|
||||||
|
|
||||||
SetFilePointer(g_logFile, 0, nullptr, FILE_END);
|
VOID
|
||||||
WriteFile(g_logFile, strOutput.QueryStr(), strOutput.QueryCB(), &nBytesWritten, nullptr);
|
DebugPrint(
|
||||||
FlushFileBuffers(g_logFile);
|
DWORD dwFlag,
|
||||||
}
|
const LPCSTR szString
|
||||||
|
)
|
||||||
|
{
|
||||||
|
STACK_STRU (strOutput, 256);
|
||||||
|
|
||||||
|
if ( IsEnabled( dwFlag ) )
|
||||||
|
{
|
||||||
|
strOutput.CopyA(szString);
|
||||||
|
DebugPrintW(dwFlag, strOutput.QueryStr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@
|
||||||
#define ASPNETCORE_DEBUG_FLAG_CONSOLE 0x00000008
|
#define ASPNETCORE_DEBUG_FLAG_CONSOLE 0x00000008
|
||||||
#define ASPNETCORE_DEBUG_FLAG_FILE 0x00000010
|
#define ASPNETCORE_DEBUG_FLAG_FILE 0x00000010
|
||||||
|
|
||||||
#define LOG_INFO(...) DebugPrint(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)
|
#define LOG_INFO(...) DebugPrintW(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)
|
||||||
#define LOG_INFOF(...) DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)
|
#define LOG_INFOF(...) DebugPrintfW(ASPNETCORE_DEBUG_FLAG_INFO, __VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_WARN(...) DebugPrint(ASPNETCORE_DEBUG_FLAG_WARNING, __VA_ARGS__)
|
#define LOG_WARN(...) DebugPrintW(ASPNETCORE_DEBUG_FLAG_WARNING, __VA_ARGS__)
|
||||||
#define LOG_WARNF(...) DebugPrintf(ASPNETCORE_DEBUG_FLAG_WARNING, __VA_ARGS__)
|
#define LOG_WARNF(...) DebugPrintfW(ASPNETCORE_DEBUG_FLAG_WARNING, __VA_ARGS__)
|
||||||
|
|
||||||
#define LOG_ERROR(...) DebugPrint(ASPNETCORE_DEBUG_FLAG_ERROR, __VA_ARGS__)
|
#define LOG_ERROR(...) DebugPrintW(ASPNETCORE_DEBUG_FLAG_ERROR, __VA_ARGS__)
|
||||||
#define LOG_ERRORF(...) DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, __VA_ARGS__)
|
#define LOG_ERRORF(...) DebugPrintfW(ASPNETCORE_DEBUG_FLAG_ERROR, __VA_ARGS__)
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
DebugInitialize(HMODULE hModule);
|
DebugInitialize(HMODULE hModule);
|
||||||
|
|
@ -37,6 +37,20 @@ IsEnabled(
|
||||||
DWORD dwFlag
|
DWORD dwFlag
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
DebugPrintW(
|
||||||
|
DWORD dwFlag,
|
||||||
|
LPCWSTR szString
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
DebugPrintfW(
|
||||||
|
DWORD dwFlag,
|
||||||
|
LPCWSTR szFormat,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
DebugPrint(
|
DebugPrint(
|
||||||
DWORD dwFlag,
|
DWORD dwFlag,
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,16 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
std::vector<std::wstring> &arguments
|
std::vector<std::wstring> &arguments
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOG_INFOF("Resolving hostfxr parameters for application: '%S' arguments: '%S' path: '%S'",
|
LOG_INFOF(L"Resolving hostfxr parameters for application: '%ls' arguments: '%ls' path: '%ls'",
|
||||||
processPath.c_str(),
|
processPath.c_str(),
|
||||||
applicationArguments.c_str(),
|
applicationArguments.c_str(),
|
||||||
applicationPhysicalPath.c_str());
|
applicationPhysicalPath.c_str());
|
||||||
|
arguments = std::vector<std::wstring>();
|
||||||
|
|
||||||
fs::path expandedProcessPath = Environment::ExpandEnvironmentVariables(processPath);
|
fs::path expandedProcessPath = Environment::ExpandEnvironmentVariables(processPath);
|
||||||
const auto expandedApplicationArguments = Environment::ExpandEnvironmentVariables(applicationArguments);
|
const auto expandedApplicationArguments = Environment::ExpandEnvironmentVariables(applicationArguments);
|
||||||
|
|
||||||
LOG_INFOF("Expanded hostfxr parameters for application: '%S' arguments: '%S'",
|
LOG_INFOF(L"Known dotnet.exe location: '%ls'", dotnetExePath.c_str());
|
||||||
expandedProcessPath.c_str(),
|
|
||||||
expandedApplicationArguments.c_str());
|
|
||||||
|
|
||||||
LOG_INFOF("Known dotnet.exe location: '%S'", dotnetExePath.c_str());
|
|
||||||
|
|
||||||
if (!expandedProcessPath.has_extension())
|
if (!expandedProcessPath.has_extension())
|
||||||
{
|
{
|
||||||
|
|
@ -50,7 +47,12 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
// Check if the absolute path is to dotnet or not.
|
// Check if the absolute path is to dotnet or not.
|
||||||
if (IsDotnetExecutable(expandedProcessPath))
|
if (IsDotnetExecutable(expandedProcessPath))
|
||||||
{
|
{
|
||||||
LOG_INFOF("Process path '%S' is dotnet, treating application as portable", expandedProcessPath.c_str());
|
LOG_INFOF(L"Process path '%ls' is dotnet, treating application as portable", expandedProcessPath.c_str());
|
||||||
|
|
||||||
|
if (applicationArguments.empty())
|
||||||
|
{
|
||||||
|
throw StartupParametersResolutionException(L"Application arguments are empty.");
|
||||||
|
}
|
||||||
|
|
||||||
if (dotnetExePath.empty())
|
if (dotnetExePath.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -59,16 +61,16 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
|
|
||||||
hostFxrDllPath = GetAbsolutePathToHostFxr(dotnetExePath);
|
hostFxrDllPath = GetAbsolutePathToHostFxr(dotnetExePath);
|
||||||
|
|
||||||
ParseHostfxrArguments(
|
arguments.push_back(dotnetExePath);
|
||||||
|
AppendArguments(
|
||||||
expandedApplicationArguments,
|
expandedApplicationArguments,
|
||||||
dotnetExePath,
|
|
||||||
applicationPhysicalPath,
|
applicationPhysicalPath,
|
||||||
arguments,
|
arguments,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_INFOF("Process path '%S' is not dotnet, treating application as standalone or portable with bootstrapper", expandedProcessPath.c_str());
|
LOG_INFOF(L"Process path '%ls' is not dotnet, treating application as standalone or portable with bootstrapper", expandedProcessPath.c_str());
|
||||||
|
|
||||||
auto executablePath = expandedProcessPath;
|
auto executablePath = expandedProcessPath;
|
||||||
|
|
||||||
|
|
@ -87,21 +89,23 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
auto applicationDllPath = executablePath;
|
auto applicationDllPath = executablePath;
|
||||||
applicationDllPath.replace_extension(".dll");
|
applicationDllPath.replace_extension(".dll");
|
||||||
|
|
||||||
LOG_INFOF("Checking application.dll at %S", applicationDllPath.c_str());
|
LOG_INFOF(L"Checking application.dll at '%ls'", applicationDllPath.c_str());
|
||||||
if (!is_regular_file(applicationDllPath))
|
if (!is_regular_file(applicationDllPath))
|
||||||
{
|
{
|
||||||
throw StartupParametersResolutionException(format(L"Application .dll was not found at %s", applicationDllPath.c_str()));
|
throw StartupParametersResolutionException(format(L"Application .dll was not found at %s", applicationDllPath.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll";
|
hostFxrDllPath = executablePath.parent_path() / "hostfxr.dll";
|
||||||
LOG_INFOF("Checking hostfxr.dll at %S", hostFxrDllPath.c_str());
|
LOG_INFOF(L"Checking hostfxr.dll at '%ls'", hostFxrDllPath.c_str());
|
||||||
if (is_regular_file(hostFxrDllPath))
|
if (is_regular_file(hostFxrDllPath))
|
||||||
{
|
{
|
||||||
LOG_INFOF("hostfxr.dll found app local at '%S', treating application as standalone", hostFxrDllPath.c_str());
|
LOG_INFOF(L"hostfxr.dll found app local at '%ls', treating application as standalone", hostFxrDllPath.c_str());
|
||||||
|
// For standalone apps we need .exe to be argv[0], dll would be discovered next to it
|
||||||
|
arguments.push_back(executablePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_INFOF("hostfxr.dll found app local at '%S', treating application as portable with launcher", hostFxrDllPath.c_str());
|
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
|
// passing "dotnet" here because we don't know where dotnet.exe should come from
|
||||||
// so trying all fallbacks is appropriate
|
// so trying all fallbacks is appropriate
|
||||||
|
|
@ -109,13 +113,15 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
{
|
{
|
||||||
dotnetExePath = GetAbsolutePathToDotnet(applicationPhysicalPath, L"dotnet");
|
dotnetExePath = GetAbsolutePathToDotnet(applicationPhysicalPath, L"dotnet");
|
||||||
}
|
}
|
||||||
executablePath = dotnetExePath;
|
|
||||||
hostFxrDllPath = GetAbsolutePathToHostFxr(dotnetExePath);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseHostfxrArguments(
|
AppendArguments(
|
||||||
applicationDllPath.generic_wstring() + L" " + expandedApplicationArguments,
|
expandedApplicationArguments,
|
||||||
executablePath,
|
|
||||||
applicationPhysicalPath,
|
applicationPhysicalPath,
|
||||||
arguments);
|
arguments);
|
||||||
}
|
}
|
||||||
|
|
@ -137,29 +143,49 @@ HOSTFXR_UTILITY::IsDotnetExecutable(const std::filesystem::path & dotnetPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HOSTFXR_UTILITY::ParseHostfxrArguments(
|
HOSTFXR_UTILITY::AppendArguments(
|
||||||
const std::wstring &applicationArguments,
|
const std::wstring &applicationArguments,
|
||||||
const fs::path &applicationExePath,
|
|
||||||
const fs::path &applicationPhysicalPath,
|
const fs::path &applicationPhysicalPath,
|
||||||
std::vector<std::wstring> &arguments,
|
std::vector<std::wstring> &arguments,
|
||||||
bool expandDllPaths
|
bool expandDllPaths
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOG_INFOF("Resolving hostfxr_main arguments application: '%S' arguments: '%S' path: %S", applicationExePath.c_str(), applicationArguments.c_str(), applicationPhysicalPath.c_str());
|
|
||||||
|
|
||||||
arguments = std::vector<std::wstring>();
|
|
||||||
arguments.push_back(applicationExePath);
|
|
||||||
|
|
||||||
if (applicationArguments.empty())
|
if (applicationArguments.empty())
|
||||||
{
|
{
|
||||||
throw StartupParametersResolutionException(L"Application arguments are empty.");
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't throw while trying to expand arguments
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
// Try to treat entire arguments section as a single path
|
||||||
|
if (expandDllPaths)
|
||||||
|
{
|
||||||
|
fs::path argumentAsPath = applicationArguments;
|
||||||
|
if (is_regular_file(argumentAsPath, ec))
|
||||||
|
{
|
||||||
|
LOG_INFOF(L"Treating '%ls' as a single path argument", applicationArguments.c_str());
|
||||||
|
arguments.push_back(argumentAsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argumentAsPath.is_relative())
|
||||||
|
{
|
||||||
|
argumentAsPath = applicationPhysicalPath / argumentAsPath;
|
||||||
|
if (is_regular_file(argumentAsPath, ec))
|
||||||
|
{
|
||||||
|
LOG_INFOF(L"Converted argument '%ls' to '%ls'", applicationArguments.c_str(), argumentAsPath.c_str());
|
||||||
|
arguments.push_back(argumentAsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int argc = 0;
|
int argc = 0;
|
||||||
auto pwzArgs = std::unique_ptr<LPWSTR[], LocalFreeDeleter>(CommandLineToArgvW(applicationArguments.c_str(), &argc));
|
auto pwzArgs = std::unique_ptr<LPWSTR[], LocalFreeDeleter>(CommandLineToArgvW(applicationArguments.c_str(), &argc));
|
||||||
if (!pwzArgs)
|
if (!pwzArgs)
|
||||||
{
|
{
|
||||||
throw StartupParametersResolutionException(format(L"Unable parse command line arguments '%s' or '%s'", applicationArguments.c_str()));
|
throw StartupParametersResolutionException(format(L"Unable parse command line arguments '%s'", applicationArguments.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int intArgsProcessed = 0; intArgsProcessed < argc; intArgsProcessed++)
|
for (int intArgsProcessed = 0; intArgsProcessed < argc; intArgsProcessed++)
|
||||||
|
|
@ -173,9 +199,9 @@ HOSTFXR_UTILITY::ParseHostfxrArguments(
|
||||||
if (argumentAsPath.is_relative())
|
if (argumentAsPath.is_relative())
|
||||||
{
|
{
|
||||||
argumentAsPath = applicationPhysicalPath / argumentAsPath;
|
argumentAsPath = applicationPhysicalPath / argumentAsPath;
|
||||||
if (exists(argumentAsPath))
|
if (is_regular_file(argumentAsPath, ec))
|
||||||
{
|
{
|
||||||
LOG_INFOF("Converted argument '%S' to %S", argument.c_str(), argumentAsPath.c_str());
|
LOG_INFOF(L"Converted argument '%ls' to '%ls'", argument.c_str(), argumentAsPath.c_str());
|
||||||
argument = argumentAsPath;
|
argument = argumentAsPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -183,11 +209,6 @@ HOSTFXR_UTILITY::ParseHostfxrArguments(
|
||||||
|
|
||||||
arguments.push_back(argument);
|
arguments.push_back(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < arguments.size(); i++)
|
|
||||||
{
|
|
||||||
LOG_INFOF("Argument[%d] = %S", i, arguments[i].c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The processPath ends with dotnet.exe or dotnet
|
// The processPath ends with dotnet.exe or dotnet
|
||||||
|
|
@ -199,7 +220,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
const fs::path & requestedPath
|
const fs::path & requestedPath
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOG_INFOF("Resolving absolute path to dotnet.exe from %S", requestedPath.c_str());
|
LOG_INFOF(L"Resolving absolute path to dotnet.exe from '%ls'", requestedPath.c_str());
|
||||||
|
|
||||||
auto processPath = requestedPath;
|
auto processPath = requestedPath;
|
||||||
if (processPath.is_relative())
|
if (processPath.is_relative())
|
||||||
|
|
@ -212,7 +233,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
//
|
//
|
||||||
if (is_regular_file(processPath))
|
if (is_regular_file(processPath))
|
||||||
{
|
{
|
||||||
LOG_INFOF("Found dotnet.exe at %S", processPath.c_str());
|
LOG_INFOF(L"Found dotnet.exe at '%ls'", processPath.c_str());
|
||||||
|
|
||||||
return processPath;
|
return processPath;
|
||||||
}
|
}
|
||||||
|
|
@ -223,7 +244,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
// Only do it if no path is specified
|
// Only do it if no path is specified
|
||||||
if (requestedPath.has_parent_path())
|
if (requestedPath.has_parent_path())
|
||||||
{
|
{
|
||||||
LOG_INFOF("Absolute path to dotnet.exe was not found at %S", requestedPath.c_str());
|
LOG_INFOF(L"Absolute path to dotnet.exe was not found at '%ls'", requestedPath.c_str());
|
||||||
|
|
||||||
throw StartupParametersResolutionException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str()));
|
throw StartupParametersResolutionException(format(L"Could not find dotnet.exe at '%s'", processPath.c_str()));
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +252,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
const auto dotnetViaWhere = InvokeWhereToFindDotnet();
|
const auto dotnetViaWhere = InvokeWhereToFindDotnet();
|
||||||
if (dotnetViaWhere.has_value())
|
if (dotnetViaWhere.has_value())
|
||||||
{
|
{
|
||||||
LOG_INFOF("Found dotnet.exe via where.exe invocation at %S", dotnetViaWhere.value().c_str());
|
LOG_INFOF(L"Found dotnet.exe via where.exe invocation at '%ls'", dotnetViaWhere.value().c_str());
|
||||||
|
|
||||||
return dotnetViaWhere.value();
|
return dotnetViaWhere.value();
|
||||||
}
|
}
|
||||||
|
|
@ -239,12 +260,12 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
|
||||||
const auto programFilesLocation = GetAbsolutePathToDotnetFromProgramFiles();
|
const auto programFilesLocation = GetAbsolutePathToDotnetFromProgramFiles();
|
||||||
if (programFilesLocation.has_value())
|
if (programFilesLocation.has_value())
|
||||||
{
|
{
|
||||||
LOG_INFOF("Found dotnet.exe in Program Files at %S", programFilesLocation.value().c_str());
|
LOG_INFOF(L"Found dotnet.exe in Program Files at '%ls'", programFilesLocation.value().c_str());
|
||||||
|
|
||||||
return programFilesLocation.value();
|
return programFilesLocation.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("dotnet.exe not found");
|
LOG_INFOF(L"dotnet.exe not found");
|
||||||
throw StartupParametersResolutionException(format(
|
throw StartupParametersResolutionException(format(
|
||||||
L"Could not find dotnet.exe at '%s' or using the system PATH environment variable."
|
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.",
|
" Check that a valid path to dotnet is on the PATH and the bitness of dotnet matches the bitness of the IIS worker process.",
|
||||||
|
|
@ -259,7 +280,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
|
||||||
std::vector<std::wstring> versionFolders;
|
std::vector<std::wstring> versionFolders;
|
||||||
const auto hostFxrBase = dotnetPath.parent_path() / "host" / "fxr";
|
const auto hostFxrBase = dotnetPath.parent_path() / "host" / "fxr";
|
||||||
|
|
||||||
LOG_INFOF("Resolving absolute path to hostfxr.dll from %S", dotnetPath.c_str());
|
LOG_INFOF(L"Resolving absolute path to hostfxr.dll from '%ls'", dotnetPath.c_str());
|
||||||
|
|
||||||
if (!is_directory(hostFxrBase))
|
if (!is_directory(hostFxrBase))
|
||||||
{
|
{
|
||||||
|
|
@ -281,7 +302,7 @@ HOSTFXR_UTILITY::GetAbsolutePathToHostFxr(
|
||||||
throw StartupParametersResolutionException(format(L"hostfxr.dll not found at '%s'", hostFxrPath.c_str()));
|
throw StartupParametersResolutionException(format(L"hostfxr.dll not found at '%s'", hostFxrPath.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("hostfxr.dll located at %S", hostFxrPath.c_str());
|
LOG_INFOF(L"hostfxr.dll located at '%ls'", hostFxrPath.c_str());
|
||||||
return hostFxrPath;
|
return hostFxrPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,7 +344,7 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet()
|
||||||
securityAttributes.lpSecurityDescriptor = NULL;
|
securityAttributes.lpSecurityDescriptor = NULL;
|
||||||
securityAttributes.bInheritHandle = TRUE;
|
securityAttributes.bInheritHandle = TRUE;
|
||||||
|
|
||||||
LOG_INFO("Invoking where.exe to find dotnet.exe");
|
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
|
// 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(!CreatePipe(&hStdOutReadPipe, &hStdOutWritePipe, &securityAttributes, 0));
|
||||||
|
|
@ -398,7 +419,7 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet()
|
||||||
|
|
||||||
FINISHED_IF_FAILED(struDotnetLocationsString.CopyA(pzFileContents, dwNumBytesRead));
|
FINISHED_IF_FAILED(struDotnetLocationsString.CopyA(pzFileContents, dwNumBytesRead));
|
||||||
|
|
||||||
LOG_INFOF("where.exe invocation returned: %S", struDotnetLocationsString.QueryStr());
|
LOG_INFOF(L"where.exe invocation returned: '%ls'", struDotnetLocationsString.QueryStr());
|
||||||
|
|
||||||
// Check the bitness of the currently running process
|
// Check the bitness of the currently running process
|
||||||
// matches the dotnet.exe found.
|
// matches the dotnet.exe found.
|
||||||
|
|
@ -417,7 +438,7 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet()
|
||||||
fIsCurrentProcess64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
|
fIsCurrentProcess64Bit = systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Current process bitness type detected as isX64=%d", fIsCurrentProcess64Bit);
|
LOG_INFOF(L"Current process bitness type detected as isX64=%d", fIsCurrentProcess64Bit);
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
|
|
@ -431,14 +452,14 @@ HOSTFXR_UTILITY::InvokeWhereToFindDotnet()
|
||||||
// \r\n is two wchars, so add 2 here.
|
// \r\n is two wchars, so add 2 here.
|
||||||
prevIndex = index + 2;
|
prevIndex = index + 2;
|
||||||
|
|
||||||
LOG_INFOF("Processing entry %S", struDotnetSubstring.QueryStr());
|
LOG_INFOF(L"Processing entry '%ls'", struDotnetSubstring.QueryStr());
|
||||||
|
|
||||||
if (LOG_LAST_ERROR_IF(!GetBinaryTypeW(struDotnetSubstring.QueryStr(), &dwBinaryType)))
|
if (LOG_LAST_ERROR_IF(!GetBinaryTypeW(struDotnetSubstring.QueryStr(), &dwBinaryType)))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Binary type %d", dwBinaryType);
|
LOG_INFOF(L"Binary type %d", dwBinaryType);
|
||||||
|
|
||||||
if (fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
|
if (fIsCurrentProcess64Bit == (dwBinaryType == SCS_64BIT_BINARY))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,8 @@ public:
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
ParseHostfxrArguments(
|
AppendArguments(
|
||||||
const std::wstring &arugments,
|
const std::wstring &arugments,
|
||||||
const std::filesystem::path &exePath,
|
|
||||||
const std::filesystem::path &applicationPhysicalPath,
|
const std::filesystem::path &applicationPhysicalPath,
|
||||||
std::vector<std::wstring> &arguments,
|
std::vector<std::wstring> &arguments,
|
||||||
bool expandDllPaths = false
|
bool expandDllPaths = false
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@ HRESULT HOSTFXR_OPTIONS::Create(
|
||||||
knownDotnetLocation,
|
knownDotnetLocation,
|
||||||
arguments);
|
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<HOSTFXR_OPTIONS>(knownDotnetLocation, hostFxrDllPath, arguments);
|
ppWrapper = std::make_unique<HOSTFXR_OPTIONS>(knownDotnetLocation, hostFxrDllPath, arguments);
|
||||||
}
|
}
|
||||||
catch (HOSTFXR_UTILITY::StartupParametersResolutionException &resolutionException)
|
catch (HOSTFXR_UTILITY::StartupParametersResolutionException &resolutionException)
|
||||||
|
|
|
||||||
|
|
@ -443,7 +443,7 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
|
||||||
FINISHED_IF_FAILED(SetEnvironementVariablesOnWorkerProcess());
|
FINISHED_IF_FAILED(SetEnvironementVariablesOnWorkerProcess());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("Starting managed application");
|
LOG_INFO(L"Starting managed application");
|
||||||
|
|
||||||
if (m_pLoggerProvider == NULL)
|
if (m_pLoggerProvider == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -547,12 +547,12 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Managed application exited with code %d", m_ProcessExitCode);
|
LOG_INFOF(L"Managed application exited with code %d", m_ProcessExitCode);
|
||||||
}
|
}
|
||||||
__except(GetExceptionCode() != 0)
|
__except(GetExceptionCode() != 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
LOG_INFOF("Managed threw an exception %d", GetExceptionCode());
|
LOG_INFOF(L"Managed threw an exception %d", GetExceptionCode());
|
||||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
|
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
|
||||||
{
|
{
|
||||||
LOG_INFOF("Starting app_offline monitoring in application %S", m_applicationPath.c_str());
|
LOG_INFOF(L"Starting app_offline monitoring in application '%ls'", m_applicationPath.c_str());
|
||||||
HRESULT hr = StartMonitoringAppOflineImpl();
|
HRESULT hr = StartMonitoringAppOflineImpl();
|
||||||
|
|
||||||
if (FAILED_LOG(hr))
|
if (FAILED_LOG(hr))
|
||||||
|
|
@ -56,7 +56,7 @@ void AppOfflineTrackingApplication::OnAppOffline()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFOF("Received app_offline notification in application %S", m_applicationPath.c_str());
|
LOG_INFOF(L"Received app_offline notification in application '%ls'", m_applicationPath.c_str());
|
||||||
EventLog::Info(
|
EventLog::Info(
|
||||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
||||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ Win32 error
|
||||||
DWORD dwErrorStatus;
|
DWORD dwErrorStatus;
|
||||||
ULONG_PTR completionKey;
|
ULONG_PTR completionKey;
|
||||||
|
|
||||||
LOG_INFO("Starting file watcher thread");
|
LOG_INFO(L"Starting file watcher thread");
|
||||||
pFileMonitor = (FILE_WATCHER*)pvArg;
|
pFileMonitor = (FILE_WATCHER*)pvArg;
|
||||||
DBG_ASSERT(pFileMonitor != NULL);
|
DBG_ASSERT(pFileMonitor != NULL);
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ Win32 error
|
||||||
|
|
||||||
pFileMonitor->m_fThreadExit = TRUE;
|
pFileMonitor->m_fThreadExit = TRUE;
|
||||||
|
|
||||||
LOG_INFO("Stopping file watcher thread");
|
LOG_INFO(L"Stopping file watcher thread");
|
||||||
ExitThread(0);
|
ExitThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
|
||||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
@ -37,6 +38,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||||
return (IISDeploymentResult)await _deployer.DeployAsync();
|
return (IISDeploymentResult)await _deployer.DeployAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual async Task<IISDeploymentResult> StartAsync(IISDeploymentParameters parameters)
|
||||||
|
{
|
||||||
|
var result = await DeployAsync(parameters);
|
||||||
|
await result.AssertStarts();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
StopServer(false);
|
StopServer(false);
|
||||||
|
|
|
||||||
|
|
@ -65,12 +65,15 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
{
|
{
|
||||||
foreach (DirectoryInfo directoryInfo in source.GetDirectories())
|
foreach (DirectoryInfo directoryInfo in source.GetDirectories())
|
||||||
{
|
{
|
||||||
CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
|
if (directoryInfo.FullName != target.FullName)
|
||||||
|
{
|
||||||
|
CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logger.LogDebug($"Processing {target.FullName}");
|
logger?.LogDebug($"Processing {target.FullName}");
|
||||||
foreach (FileInfo fileInfo in source.GetFiles())
|
foreach (FileInfo fileInfo in source.GetFiles())
|
||||||
{
|
{
|
||||||
logger.LogDebug($" Copying {fileInfo.Name}");
|
logger?.LogDebug($" Copying {fileInfo.Name}");
|
||||||
var destFileName = Path.Combine(target.FullName, fileInfo.Name);
|
var destFileName = Path.Combine(target.FullName, fileInfo.Name);
|
||||||
fileInfo.CopyTo(destFileName);
|
fileInfo.CopyTo(destFileName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,64 +11,58 @@
|
||||||
TEST(ParseHostFxrArguments, BasicHostFxrArguments)
|
TEST(ParseHostFxrArguments, BasicHostFxrArguments)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> bstrArray;
|
std::vector<std::wstring> bstrArray;
|
||||||
PCWSTR exeStr = L"C:/Program Files/dotnet.exe";
|
|
||||||
|
|
||||||
HOSTFXR_UTILITY::ParseHostfxrArguments(
|
HOSTFXR_UTILITY::AppendArguments(
|
||||||
L"exec \"test.dll\"", // args
|
L"exec \"test.dll\"", // args
|
||||||
exeStr, // exe path
|
|
||||||
L"invalid", // physical path to application
|
L"invalid", // physical path to application
|
||||||
bstrArray); // args array.
|
bstrArray); // args array.
|
||||||
|
|
||||||
EXPECT_EQ(3, bstrArray.size());
|
EXPECT_EQ(2, bstrArray.size());
|
||||||
ASSERT_STREQ(exeStr, bstrArray[0].c_str());
|
ASSERT_STREQ(L"exec", bstrArray[0].c_str());
|
||||||
ASSERT_STREQ(L"exec", bstrArray[1].c_str());
|
ASSERT_STREQ(L"test.dll", bstrArray[1].c_str());
|
||||||
ASSERT_STREQ(L"test.dll", bstrArray[2].c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, NoExecProvided)
|
TEST(ParseHostFxrArguments, NoExecProvided)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> bstrArray;
|
std::vector<std::wstring> bstrArray;
|
||||||
PCWSTR exeStr = L"C:/Program Files/dotnet.exe";
|
|
||||||
|
|
||||||
HOSTFXR_UTILITY::ParseHostfxrArguments(
|
HOSTFXR_UTILITY::AppendArguments(
|
||||||
L"test.dll", // args
|
L"test.dll", // args
|
||||||
exeStr, // exe path
|
|
||||||
L"ignored", // physical path to application
|
L"ignored", // physical path to application
|
||||||
bstrArray); // args array.
|
bstrArray); // args array.
|
||||||
|
|
||||||
EXPECT_EQ(DWORD(2), bstrArray.size());
|
EXPECT_EQ(1, bstrArray.size());
|
||||||
ASSERT_STREQ(exeStr, bstrArray[0].c_str());
|
ASSERT_STREQ(L"test.dll", bstrArray[0].c_str());
|
||||||
ASSERT_STREQ(L"test.dll", bstrArray[1].c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, ConvertDllToAbsolutePath)
|
TEST(ParseHostFxrArguments, ConvertDllToAbsolutePath)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> bstrArray;
|
std::vector<std::wstring> bstrArray;
|
||||||
PCWSTR exeStr = L"C:/Program Files/dotnet.exe";
|
|
||||||
// we need to use existing dll so let's use ntdll that we know exists everywhere
|
// we need to use existing dll so let's use ntdll that we know exists everywhere
|
||||||
auto system32 = Environment::ExpandEnvironmentVariables(L"%WINDIR%\\System32");
|
auto system32 = Environment::ExpandEnvironmentVariables(L"%WINDIR%\\System32");
|
||||||
HOSTFXR_UTILITY::ParseHostfxrArguments(
|
HOSTFXR_UTILITY::AppendArguments(
|
||||||
L"exec \"ntdll.dll\"", // args
|
L"exec \"ntdll.dll\"", // args
|
||||||
exeStr, // exe path
|
|
||||||
system32, // physical path to application
|
system32, // physical path to application
|
||||||
bstrArray, // args array.
|
bstrArray, // args array.
|
||||||
true); // expandDllPaths
|
true); // expandDllPaths
|
||||||
|
|
||||||
EXPECT_EQ(DWORD(3), bstrArray.size());
|
EXPECT_EQ(2, bstrArray.size());
|
||||||
ASSERT_STREQ(exeStr, bstrArray[0].c_str());
|
ASSERT_STREQ(L"exec", bstrArray[0].c_str());
|
||||||
ASSERT_STREQ(L"exec", bstrArray[1].c_str());
|
ASSERT_STREQ((system32 + L"\\ntdll.dll").c_str(), bstrArray[1].c_str());
|
||||||
ASSERT_STREQ((system32 + L"\\ntdll.dll").c_str(), bstrArray[2].c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ParseHostFxrArguments, ProvideNoArgs_InvalidArgs)
|
TEST(ParseHostFxrArguments, ProvideNoArgs_InvalidArgs)
|
||||||
{
|
{
|
||||||
std::vector<std::wstring> bstrArray;
|
std::vector<std::wstring> bstrArray;
|
||||||
PCWSTR exeStr = L"C:/Program Files/dotnet.exe";
|
std::filesystem::path struHostFxrDllLocation;
|
||||||
|
std::filesystem::path struExeLocation;
|
||||||
|
|
||||||
ASSERT_THROW(HOSTFXR_UTILITY::ParseHostfxrArguments(
|
EXPECT_THROW(HOSTFXR_UTILITY::GetHostFxrParameters(
|
||||||
L"", // args
|
L"dotnet", // processPath
|
||||||
exeStr, // exe path
|
L"some\\path", // application physical path, ignored.
|
||||||
L"ignored", // physical path to application
|
L"", //arguments
|
||||||
|
struHostFxrDllLocation,
|
||||||
|
struExeLocation,
|
||||||
bstrArray), // args array.
|
bstrArray), // args array.
|
||||||
HOSTFXR_UTILITY::StartupParametersResolutionException);
|
HOSTFXR_UTILITY::StartupParametersResolutionException);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
public async Task ExpandEnvironmentVariableInWebConfig()
|
public async Task ExpandEnvironmentVariableInWebConfig()
|
||||||
{
|
{
|
||||||
// Point to dotnet installed in user profile.
|
// Point to dotnet installed in user profile.
|
||||||
await AssertStarts(
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
deploymentParameters =>
|
deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation;
|
||||||
{
|
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", "%DotnetPath%"));
|
||||||
deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation;
|
await StartAsync(deploymentParameters);
|
||||||
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", "%DotnetPath%"));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
|
|
@ -68,26 +65,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task StartsWithDotnetLocationWithoutExe()
|
public async Task StartsWithDotnetLocationWithoutExe()
|
||||||
{
|
{
|
||||||
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf("."));
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
|
|
||||||
await AssertStarts(
|
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf("."));
|
||||||
deploymentParameters =>
|
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
|
||||||
{
|
|
||||||
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
|
await StartAsync(deploymentParameters);
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task StartsWithDotnetLocationUppercase()
|
public async Task StartsWithDotnetLocationUppercase()
|
||||||
{
|
{
|
||||||
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
|
|
||||||
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")).ToUpperInvariant();
|
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")).ToUpperInvariant();
|
||||||
await AssertStarts(
|
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
|
||||||
deploymentParameters =>
|
|
||||||
{
|
await StartAsync(deploymentParameters);
|
||||||
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
|
|
@ -95,32 +89,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
[InlineData("dotnet.EXE")]
|
[InlineData("dotnet.EXE")]
|
||||||
public async Task StartsWithDotnetOnThePath(string path)
|
public async Task StartsWithDotnetOnThePath(string path)
|
||||||
{
|
{
|
||||||
await AssertStarts(
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
deploymentParameters =>
|
|
||||||
{
|
deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation);
|
||||||
deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation);
|
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path));
|
||||||
deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path));
|
|
||||||
}
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
);
|
await deploymentResult.AssertStarts();
|
||||||
|
|
||||||
// Verify that in this scenario where.exe was invoked only once by shim and request handler uses cached value
|
// 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")));
|
Assert.Equal(1, TestSink.Writes.Count(w => w.Message.Contains("Invoking where.exe to find dotnet.exe")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AssertStarts(Action<IISDeploymentParameters> preDeploy = null)
|
|
||||||
{
|
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
|
||||||
|
|
||||||
preDeploy?.Invoke(deploymentParameters);
|
|
||||||
|
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
|
||||||
|
|
||||||
var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
|
|
||||||
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
Assert.Equal("Hello World", responseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TestMatrix TestVariants
|
public static TestMatrix TestVariants
|
||||||
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
=> TestMatrix.ForServers(DeployerSelector.ServerType)
|
||||||
.WithTfms(Tfm.NetCoreApp22)
|
.WithTfms(Tfm.NetCoreApp22)
|
||||||
|
|
@ -132,13 +112,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
public async Task HelloWorld(TestVariant variant)
|
public async Task HelloWorld(TestVariant variant)
|
||||||
{
|
{
|
||||||
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
|
var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true);
|
||||||
|
await StartAsync(deploymentParameters);
|
||||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
|
||||||
|
|
||||||
var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld");
|
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
Assert.Equal("Hello World", responseText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
|
|
@ -194,7 +168,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
|
|
||||||
[ConditionalTheory]
|
[ConditionalTheory]
|
||||||
[MemberData(nameof(InvalidConfigTransformationsScenarios))]
|
[MemberData(nameof(InvalidConfigTransformationsScenarios))]
|
||||||
public async Task StartsWithWebConfigVariationsPortable(string scenario)
|
public async Task ReportsWebConfigAuthoringErrors(string scenario)
|
||||||
{
|
{
|
||||||
var (expectedError, action) = InvalidConfigTransformations[scenario];
|
var (expectedError, action) = InvalidConfigTransformations[scenario];
|
||||||
var iisDeploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
var iisDeploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
|
|
@ -227,5 +201,148 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
));
|
));
|
||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, Func<IISDeploymentParameters, string>> PortableConfigTransformations = InitPortableWebConfigTransformations();
|
||||||
|
public static IEnumerable<object[]> PortableConfigTransformationsScenarios => PortableConfigTransformations.ToTheoryData();
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(PortableConfigTransformationsScenarios))]
|
||||||
|
public async Task StartsWithWebConfigVariationsPortable(string scenario)
|
||||||
|
{
|
||||||
|
var action = PortableConfigTransformations[scenario];
|
||||||
|
var iisDeploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
|
var expectedArguments = action(iisDeploymentParameters);
|
||||||
|
var result = await DeployAsync(iisDeploymentParameters);
|
||||||
|
Assert.Equal(expectedArguments, await result.HttpClient.GetStringAsync("/CommandLineArgs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<string, Func<IISDeploymentParameters, string>> InitPortableWebConfigTransformations()
|
||||||
|
{
|
||||||
|
var dictionary = new Dictionary<string, Func<IISDeploymentParameters, string>>();
|
||||||
|
var pathWithSpace = "\u03c0 \u2260 3\u00b714";
|
||||||
|
|
||||||
|
dictionary.Add("App in bin subdirectory full path to dll using exec and quotes",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, "bin");
|
||||||
|
TransformArguments(parameters, (arguments, root) => "exec " + Path.Combine(root, "bin", arguments));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in subdirectory with space",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, pathWithSpace);
|
||||||
|
TransformArguments(parameters, (arguments, root) => Path.Combine(pathWithSpace, arguments));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in subdirectory with space and full path to dll",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, pathWithSpace);
|
||||||
|
TransformArguments(parameters, (arguments, root) => Path.Combine(root, pathWithSpace, arguments));
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in bin subdirectory with space full path to dll using exec and quotes",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, pathWithSpace);
|
||||||
|
TransformArguments(parameters, (arguments, root) => "exec \"" + Path.Combine(root, pathWithSpace, arguments) + "\" extra arguments");
|
||||||
|
return "extra|arguments";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in bin subdirectory and quoted argument",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, "bin");
|
||||||
|
TransformArguments(parameters, (arguments, root) => Path.Combine("bin", arguments) + " \"extra argument\"");
|
||||||
|
return "extra argument";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in bin subdirectory full path to dll",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, "bin");
|
||||||
|
TransformArguments(parameters, (arguments, root) => Path.Combine(root, "bin", arguments) + " extra arguments");
|
||||||
|
return "extra|arguments";
|
||||||
|
});
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Dictionary<string, Func<IISDeploymentParameters, string>> StandaloneConfigTransformations = InitStandaloneConfigTransformations();
|
||||||
|
public static IEnumerable<object[]> StandaloneConfigTransformationsScenarios => StandaloneConfigTransformations.ToTheoryData();
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[MemberData(nameof(StandaloneConfigTransformationsScenarios))]
|
||||||
|
public async Task StartsWithWebConfigVariationsStandalone(string scenario)
|
||||||
|
{
|
||||||
|
var action = StandaloneConfigTransformations[scenario];
|
||||||
|
var iisDeploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||||
|
iisDeploymentParameters.ApplicationType = ApplicationType.Standalone;
|
||||||
|
var expectedArguments = action(iisDeploymentParameters);
|
||||||
|
var result = await DeployAsync(iisDeploymentParameters);
|
||||||
|
Assert.Equal(expectedArguments, await result.HttpClient.GetStringAsync("/CommandLineArgs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<string, Func<IISDeploymentParameters, string>> InitStandaloneConfigTransformations()
|
||||||
|
{
|
||||||
|
var dictionary = new Dictionary<string, Func<IISDeploymentParameters, string>>();
|
||||||
|
var pathWithSpace = "\u03c0 \u2260 3\u00b714";
|
||||||
|
|
||||||
|
dictionary.Add("App in subdirectory",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, pathWithSpace);
|
||||||
|
TransformPath(parameters, (path, root) => Path.Combine(pathWithSpace, path));
|
||||||
|
TransformArguments(parameters, (arguments, root) => "\"additional argument\"");
|
||||||
|
return "additional argument";
|
||||||
|
});
|
||||||
|
|
||||||
|
dictionary.Add("App in bin subdirectory full path",
|
||||||
|
parameters => {
|
||||||
|
MoveApplication(parameters, pathWithSpace);
|
||||||
|
TransformPath(parameters, (path, root) => Path.Combine(root, pathWithSpace, path));
|
||||||
|
TransformArguments(parameters, (arguments, root) => "additional arguments");
|
||||||
|
return "additional|arguments";
|
||||||
|
});
|
||||||
|
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveApplication(
|
||||||
|
IISDeploymentParameters parameters,
|
||||||
|
string subdirectory)
|
||||||
|
{
|
||||||
|
parameters.WebConfigActionList.Add((config, contentRoot) =>
|
||||||
|
{
|
||||||
|
var source = new DirectoryInfo(contentRoot);
|
||||||
|
var subDirectoryPath = source.CreateSubdirectory(subdirectory);
|
||||||
|
|
||||||
|
// Copy everything into a subfolder
|
||||||
|
Helpers.CopyFiles(source, subDirectoryPath, null);
|
||||||
|
// Cleanup files
|
||||||
|
foreach (var fileSystemInfo in source.GetFiles())
|
||||||
|
{
|
||||||
|
fileSystemInfo.Delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TransformPath(IISDeploymentParameters parameters, Func<string, string, string> transformation)
|
||||||
|
{
|
||||||
|
parameters.WebConfigActionList.Add(
|
||||||
|
(config, contentRoot) =>
|
||||||
|
{
|
||||||
|
var aspNetCoreElement = config.Descendants("aspNetCore").Single();
|
||||||
|
aspNetCoreElement.SetAttributeValue("processPath", transformation((string)aspNetCoreElement.Attribute("processPath"), contentRoot));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TransformArguments(IISDeploymentParameters parameters, Func<string, string, string> transformation)
|
||||||
|
{
|
||||||
|
parameters.WebConfigActionList.Add(
|
||||||
|
(config, contentRoot) =>
|
||||||
|
{
|
||||||
|
var aspNetCoreElement = config.Descendants("aspNetCore").Single();
|
||||||
|
aspNetCoreElement.SetAttributeValue("arguments", transformation((string)aspNetCoreElement.Attribute("arguments"), contentRoot));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -46,7 +47,7 @@ namespace IISTestSite
|
||||||
private async Task HostingEnvironment(HttpContext context)
|
private async Task HostingEnvironment(HttpContext context)
|
||||||
{
|
{
|
||||||
var hostingEnv = context.RequestServices.GetService<IHostingEnvironment>();
|
var hostingEnv = context.RequestServices.GetService<IHostingEnvironment>();
|
||||||
|
|
||||||
await context.Response.WriteAsync("ContentRootPath "+hostingEnv.ContentRootPath + Environment.NewLine);
|
await context.Response.WriteAsync("ContentRootPath "+hostingEnv.ContentRootPath + Environment.NewLine);
|
||||||
await context.Response.WriteAsync("WebRootPath "+hostingEnv.WebRootPath + Environment.NewLine);
|
await context.Response.WriteAsync("WebRootPath "+hostingEnv.WebRootPath + Environment.NewLine);
|
||||||
await context.Response.WriteAsync("CurrentDirectory "+Environment.CurrentDirectory);
|
await context.Response.WriteAsync("CurrentDirectory "+Environment.CurrentDirectory);
|
||||||
|
|
@ -762,5 +763,10 @@ namespace IISTestSite
|
||||||
}
|
}
|
||||||
await context.Response.WriteAsync("Response End");
|
await context.Response.WriteAsync("Response End");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CommandLineArgs(HttpContext context)
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync(string.Join("|", Environment.GetCommandLineArgs().Skip(1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue