diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
index 3c64a0dee2..10633c1854 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
+++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj
@@ -229,6 +229,7 @@
+
@@ -240,6 +241,7 @@
+
Create
Create
diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
new file mode 100644
index 0000000000..d01d944c5c
--- /dev/null
+++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
@@ -0,0 +1,271 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+#include "HandlerResolver.h"
+#include "exceptions.h"
+#include "utility.h"
+#include "SRWExclusiveLock.h"
+#include "applicationinfo.h"
+#include "EventLog.h"
+#include "hostfxr_utility.h"
+#include "GlobalVersionUtility.h"
+#include "HandleWrapper.h"
+
+const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
+const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
+
+HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
+ : m_hModule(hModule),
+ m_pServer(pServer),
+ m_fAspnetcoreRHLoadResult(S_FALSE),
+ m_loadedApplicationHostingModel(HOSTING_UNKNOWN),
+ m_hRequestHandlerDll(nullptr),
+ m_pfnAspNetCoreCreateApplication(nullptr)
+{
+ InitializeSRWLock(&m_requestHandlerLoadLock);
+}
+
+HRESULT
+HandlerResolver::LoadRequestHandlerAssembly(STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration)
+{
+ HRESULT hr;
+ STACK_STRU(struFileName, MAX_PATH);
+ PCWSTR pstrHandlerDllName;
+ if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+ {
+ pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
+ }
+ else
+ {
+ pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
+ }
+
+ // Try to see if RH is already loaded, use GetModuleHandleEx to increment ref count
+ if (!GetModuleHandleEx(0, pstrHandlerDllName, &m_hRequestHandlerDll))
+ {
+ if (pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+ {
+ std::unique_ptr options;
+
+ RETURN_IF_FAILED(HOSTFXR_OPTIONS::Create(
+ NULL,
+ pConfiguration->QueryProcessPath()->QueryStr(),
+ pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
+ pConfiguration->QueryArguments()->QueryStr(),
+ g_hEventLog,
+ options));
+
+ RETURN_IF_FAILED(location.Copy(options->GetExeLocation()));
+
+ if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName)))
+ {
+ UTILITY::LogEventF(g_hEventLog,
+ EVENTLOG_ERROR_TYPE,
+ ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
+ ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG,
+ struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr());
+
+ return hr;
+ }
+ }
+ else
+ {
+ if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pConfiguration, pstrHandlerDllName, &struFileName)))
+ {
+ UTILITY::LogEventF(g_hEventLog,
+ EVENTLOG_ERROR_TYPE,
+ ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
+ ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
+ struFileName.IsEmpty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : struFileName.QueryStr());
+
+ return hr;
+ }
+ }
+
+ LOG_INFOF("Loading request handler: %S", struFileName.QueryStr());
+
+ m_hRequestHandlerDll = LoadLibraryW(struFileName.QueryStr());
+ RETURN_LAST_ERROR_IF_NULL(m_hRequestHandlerDll);
+ }
+
+ m_pfnAspNetCoreCreateApplication = reinterpret_cast(GetProcAddress(m_hRequestHandlerDll, "CreateApplication"));
+
+ RETURN_LAST_ERROR_IF_NULL(m_pfnAspNetCoreCreateApplication);
+
+ return S_OK;
+}
+
+HRESULT
+HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION * pfnCreateApplication)
+{
+ ASPNETCORE_SHIM_CONFIG pConfiguration;
+ RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
+
+ if (m_fAspnetcoreRHLoadResult == S_FALSE)
+ {
+ SRWExclusiveLock lock(m_requestHandlerLoadLock);
+ if (m_fAspnetcoreRHLoadResult == S_FALSE)
+ {
+ m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
+ m_loadedApplicationId = pApplication.GetApplicationId();
+ LOG_IF_FAILED(m_fAspnetcoreRHLoadResult = LoadRequestHandlerAssembly(location, &pConfiguration));
+ }
+ }
+
+ // Mixed hosting models
+ if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
+ {
+ UTILITY::LogEventF(g_hEventLog,
+ EVENTLOG_ERROR_TYPE,
+ ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
+ ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
+ pApplication.GetApplicationId(),
+ pConfiguration.QueryHostingModel());
+
+ return E_FAIL;
+ }
+ // Multiple in-process apps
+ else if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId())
+ {
+ UTILITY::LogEventF(g_hEventLog,
+ EVENTLOG_ERROR_TYPE,
+ ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
+ ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG,
+ pApplication.GetApplicationId());
+
+ return E_FAIL;
+ }
+
+ *pfnCreateApplication = m_pfnAspNetCoreCreateApplication;
+ return m_fAspnetcoreRHLoadResult;
+}
+
+HRESULT
+HandlerResolver::FindNativeAssemblyFromGlobalLocation(
+ ASPNETCORE_SHIM_CONFIG * pConfiguration,
+ PCWSTR pstrHandlerDllName,
+ STRU* struFilename
+)
+{
+ try
+ {
+ std::wstring modulePath = GlobalVersionUtility::GetModuleName(m_hModule);
+
+ modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
+
+ std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
+ pConfiguration->QueryHandlerVersion()->QueryStr(),
+ pstrHandlerDllName
+ );
+
+ RETURN_IF_FAILED(struFilename->Copy(retval.c_str()));
+ }
+ catch (...)
+ {
+ STRU struEvent;
+ if (SUCCEEDED(struEvent.Copy(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG)))
+ {
+ UTILITY::LogEvent(g_hEventLog,
+ EVENTLOG_INFORMATION_TYPE,
+ ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
+ struEvent.QueryStr());
+ }
+
+ return OBSERVE_CAUGHT_EXCEPTION();
+ }
+
+ return S_OK;
+}
+
+//
+// Tries to find aspnetcorerh.dll from the application
+// Calls into hostfxr.dll to find it.
+// Will leave hostfxr.dll loaded as it will be used again to call hostfxr_main.
+//
+HRESULT
+HandlerResolver::FindNativeAssemblyFromHostfxr(
+ HOSTFXR_OPTIONS* hostfxrOptions,
+ PCWSTR libraryName,
+ STRU* struFilename
+)
+{
+ STRU struApplicationFullPath;
+ STRU struNativeSearchPaths;
+ STRU struNativeDllLocation;
+ INT intIndex = -1;
+ INT intPrevIndex = 0;
+ BOOL fFound = FALSE;
+ DWORD dwBufferSize = 1024 * 10;
+ DWORD dwRequiredBufferSize = 0;
+
+ DBG_ASSERT(struFilename != NULL);
+
+ RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()));
+
+ auto pFnHostFxrSearchDirectories = reinterpret_cast(GetProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"));
+
+ RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories);
+ RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
+
+ while (TRUE)
+ {
+ auto intHostFxrExitCode = pFnHostFxrSearchDirectories(
+ hostfxrOptions->GetArgc(),
+ hostfxrOptions->GetArgv(),
+ struNativeSearchPaths.QueryStr(),
+ dwBufferSize,
+ &dwRequiredBufferSize
+ );
+
+ if (intHostFxrExitCode == 0)
+ {
+ break;
+ }
+ else if (dwRequiredBufferSize > dwBufferSize)
+ {
+ dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
+
+ RETURN_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
+ }
+ else
+ {
+ // Log "Error finding native search directories from aspnetcore application.
+ return E_UNEXPECTED;
+ }
+ }
+
+ RETURN_IF_FAILED(struNativeSearchPaths.SyncWithBuffer());
+
+ fFound = FALSE;
+
+ // The native search directories are semicolon delimited.
+ // Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
+ while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
+ {
+ RETURN_IF_FAILED(struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex));
+
+ if (!struNativeDllLocation.EndsWith(L"\\"))
+ {
+ RETURN_IF_FAILED(struNativeDllLocation.Append(L"\\"));
+ }
+
+ RETURN_IF_FAILED(struNativeDllLocation.Append(libraryName));
+
+ if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
+ {
+ RETURN_IF_FAILED(struFilename->Copy(struNativeDllLocation));
+ fFound = TRUE;
+ break;
+ }
+
+ intPrevIndex = intIndex + 1;
+ }
+
+ if (!fFound)
+ {
+ return HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND);
+ }
+
+ return S_OK;
+}
+
diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
new file mode 100644
index 0000000000..ad257afef4
--- /dev/null
+++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
@@ -0,0 +1,49 @@
+// 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 "aspnetcore_shim_config.h"
+#include "hostfxroptions.h"
+#include
+#include "iapplication.h"
+#include
+#include "HandleWrapper.h"
+
+typedef
+HRESULT
+(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
+ _In_ IHttpServer *pServer,
+ _In_ IHttpApplication *pHttpApplication,
+ _In_ APPLICATION_PARAMETER *pParameters,
+ _In_ DWORD nParameters,
+ _Out_ IAPPLICATION **pApplication
+ );
+
+class HandlerResolver
+{
+public:
+ HandlerResolver(HMODULE hModule, IHttpServer &pServer);
+ HRESULT GetApplicationFactory(IHttpApplication &pApplication, STRU& location, PFN_ASPNETCORE_CREATE_APPLICATION *pfnCreateApplication);
+
+private:
+ HRESULT LoadRequestHandlerAssembly(STRU& location, ASPNETCORE_SHIM_CONFIG * pConfiguration);
+ HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG * pConfiguration, PCWSTR libraryName, STRU* location);
+ HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location);
+
+ HMODULE m_hModule;
+ IHttpServer &m_pServer;
+
+ SRWLOCK m_requestHandlerLoadLock {};
+ // S_FALSE - not loaded, S_OK - loaded, everything else - error
+ HRESULT m_fAspnetcoreRHLoadResult;
+ std::wstring m_loadedApplicationId;
+ APP_HOSTING_MODEL m_loadedApplicationHostingModel;
+ HandleWrapper m_hRequestHandlerDll;
+ HandleWrapper m_hHostFxrDll;
+
+ PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
+
+ static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
+ static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
+};
+
diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp
index 3ac7246ca9..bad9c25e4b 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp
@@ -17,18 +17,6 @@
#include "ServerErrorApplication.h"
#include "AppOfflineApplication.h"
-extern HINSTANCE g_hModule;
-
-const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
-const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
-
-SRWLOCK APPLICATION_INFO::s_requestHandlerLoadLock {};
-bool APPLICATION_INFO::s_fAspnetcoreRHAssemblyLoaded = false;
-bool APPLICATION_INFO::s_fAspnetcoreRHLoadedError = false;
-HMODULE APPLICATION_INFO::s_hAspnetCoreRH = nullptr;
-
-PFN_ASPNETCORE_CREATE_APPLICATION APPLICATION_INFO::s_pfnAspNetCoreCreateApplication = nullptr;
-
APPLICATION_INFO::~APPLICATION_INFO()
{
ShutDownApplication();
@@ -36,13 +24,13 @@ APPLICATION_INFO::~APPLICATION_INFO()
HRESULT
APPLICATION_INFO::Initialize(
- _In_ IHttpApplication &pApplication
+ _In_ IHttpApplication &pApplication,
+ HandlerResolver * pHandlerResolver
)
{
- m_pConfiguration.reset(new ASPNETCORE_SHIM_CONFIG());
- RETURN_IF_FAILED(m_pConfiguration->Populate(&m_pServer, &pApplication));
+ m_handlerResolver = pHandlerResolver;
+ RETURN_IF_FAILED(m_struConfigPath.Copy(pApplication.GetAppConfigPath()));
RETURN_IF_FAILED(m_struInfoKey.Copy(pApplication.GetApplicationId()));
-
return S_OK;
}
@@ -84,20 +72,15 @@ APPLICATION_INFO::GetOrCreateApplication(
else
{
STRU struExeLocation;
- FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
-
- if (m_pfnAspNetCoreCreateApplication == NULL)
- {
- FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
- }
-
+ PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication;
+ FINISHED_IF_FAILED(m_handlerResolver->GetApplicationFactory(httpApplication, struExeLocation, &pfnAspNetCoreCreateApplication));
std::array parameters {
{"InProcessExeLocation", struExeLocation.QueryStr()}
};
LOG_INFO("Creating handler application");
IAPPLICATION * newApplication;
- FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
+ FINISHED_IF_FAILED(pfnAspNetCoreCreateApplication(
&m_pServer,
&httpApplication,
parameters.data(),
@@ -130,266 +113,6 @@ Finished:
return hr;
}
-HRESULT
-APPLICATION_INFO::FindRequestHandlerAssembly(STRU& location)
-{
- HRESULT hr = S_OK;
- PCWSTR pstrHandlerDllName;
- STACK_STRU(struFileName, 256);
-
- if (s_fAspnetcoreRHLoadedError)
- {
- FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
- }
- else if (!s_fAspnetcoreRHAssemblyLoaded)
- {
- SRWExclusiveLock lock(s_requestHandlerLoadLock);
- if (s_fAspnetcoreRHLoadedError)
- {
- FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
- }
- if (s_fAspnetcoreRHAssemblyLoaded)
- {
- FINISHED(S_OK);
- }
-
- if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
- {
- pstrHandlerDllName = s_pwzAspnetcoreInProcessRequestHandlerName;
- }
- else
- {
- pstrHandlerDllName = s_pwzAspnetcoreOutOfProcessRequestHandlerName;
- }
-
- // Try to see if RH is already loaded
- s_hAspnetCoreRH = GetModuleHandle(pstrHandlerDllName);
-
- if (s_hAspnetCoreRH == NULL)
- {
- if (m_pConfiguration->QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
- {
- std::unique_ptr options;
-
- FINISHED_IF_FAILED(HOSTFXR_OPTIONS::Create(
- NULL,
- m_pConfiguration->QueryProcessPath()->QueryStr(),
- m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
- m_pConfiguration->QueryArguments()->QueryStr(),
- g_hEventLog,
- options));
-
- FINISHED_IF_FAILED(location.Copy(options->GetExeLocation()));
-
- if (FAILED_LOG(hr = FindNativeAssemblyFromHostfxr(options.get(), pstrHandlerDllName, &struFileName)))
- {
- UTILITY::LogEventF(g_hEventLog,
- EVENTLOG_ERROR_TYPE,
- ASPNETCORE_EVENT_INPROCESS_RH_MISSING,
- ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG,
- struFileName.IsEmpty() ? s_pwzAspnetcoreInProcessRequestHandlerName : struFileName.QueryStr());
-
- FINISHED(hr);
- }
- }
- else
- {
- if (FAILED_LOG(hr = FindNativeAssemblyFromGlobalLocation(pstrHandlerDllName, &struFileName)))
- {
- UTILITY::LogEventF(g_hEventLog,
- EVENTLOG_ERROR_TYPE,
- ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
- ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG,
- struFileName.IsEmpty() ? s_pwzAspnetcoreOutOfProcessRequestHandlerName : struFileName.QueryStr());
-
- FINISHED(hr);
- }
- }
-
- LOG_INFOF("Loading request handler: %S", struFileName.QueryStr());
-
- s_hAspnetCoreRH = LoadLibraryW(struFileName.QueryStr());
-
- if (s_hAspnetCoreRH == NULL)
- {
- FINISHED(HRESULT_FROM_WIN32(GetLastError()));
- }
- }
-
- s_pfnAspNetCoreCreateApplication = (PFN_ASPNETCORE_CREATE_APPLICATION)
- GetProcAddress(s_hAspnetCoreRH, "CreateApplication");
- if (s_pfnAspNetCoreCreateApplication == NULL)
- {
- FINISHED(HRESULT_FROM_WIN32(GetLastError()));
- }
-
- s_fAspnetcoreRHAssemblyLoaded = TRUE;
- }
-
-Finished:
- //
- // Question: we remember the load failure so that we will not try again.
- // User needs to check whether the fuction pointer is NULL
- //
- m_pfnAspNetCoreCreateApplication = s_pfnAspNetCoreCreateApplication;
-
- if (!s_fAspnetcoreRHLoadedError && FAILED(hr))
- {
- s_fAspnetcoreRHLoadedError = TRUE;
- }
- return hr;
-}
-
-HRESULT
-APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(
- PCWSTR pstrHandlerDllName,
- STRU* struFilename
-)
-{
- HRESULT hr = S_OK;
-
- try
- {
- std::wstring modulePath = GlobalVersionUtility::GetModuleName(g_hModule);
-
- modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
-
- std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
- m_pConfiguration->QueryHandlerVersion()->QueryStr(),
- pstrHandlerDllName
- );
-
- RETURN_IF_FAILED(struFilename->Copy(retval.c_str()));
- }
- catch (std::exception& e)
- {
- STRU struEvent;
- if (SUCCEEDED(struEvent.Copy(ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG))
- && SUCCEEDED(struEvent.AppendA(e.what())))
- {
- UTILITY::LogEvent(g_hEventLog,
- EVENTLOG_INFORMATION_TYPE,
- ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING,
- struEvent.QueryStr());
- }
-
- hr = E_FAIL;
- }
- catch (...)
- {
- hr = E_FAIL;
- }
-
- return hr;
-}
-
-//
-// Tries to find aspnetcorerh.dll from the application
-// Calls into hostfxr.dll to find it.
-// Will leave hostfxr.dll loaded as it will be used again to call hostfxr_main.
-//
-HRESULT
-APPLICATION_INFO::FindNativeAssemblyFromHostfxr(
- HOSTFXR_OPTIONS* hostfxrOptions,
- PCWSTR libraryName,
- STRU* struFilename
-)
-{
- HRESULT hr = S_OK;
- STRU struApplicationFullPath;
- STRU struNativeSearchPaths;
- STRU struNativeDllLocation;
- HMODULE hmHostFxrDll = NULL;
- INT intHostFxrExitCode = 0;
- INT intIndex = -1;
- INT intPrevIndex = 0;
- BOOL fFound = FALSE;
- DWORD dwBufferSize = 1024 * 10;
- DWORD dwRequiredBufferSize = 0;
-
- DBG_ASSERT(struFilename != NULL);
-
- FINISHED_LAST_ERROR_IF_NULL(hmHostFxrDll = LoadLibraryW(hostfxrOptions->GetHostFxrLocation()));
-
- hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = (hostfxr_get_native_search_directories_fn)
- GetProcAddress(hmHostFxrDll, "hostfxr_get_native_search_directories");
-
- if (pFnHostFxrSearchDirectories == NULL)
- {
- // Host fxr version is incorrect (need a higher version).
- // TODO log error
- FINISHED(E_FAIL);
- }
-
- FINISHED_IF_FAILED(hr = struNativeSearchPaths.Resize(dwBufferSize));
-
- while (TRUE)
- {
- intHostFxrExitCode = pFnHostFxrSearchDirectories(
- hostfxrOptions->GetArgc(),
- hostfxrOptions->GetArgv(),
- struNativeSearchPaths.QueryStr(),
- dwBufferSize,
- &dwRequiredBufferSize
- );
-
- if (intHostFxrExitCode == 0)
- {
- break;
- }
- else if (dwRequiredBufferSize > dwBufferSize)
- {
- dwBufferSize = dwRequiredBufferSize + 1; // for null terminator
-
- FINISHED_IF_FAILED(struNativeSearchPaths.Resize(dwBufferSize));
- }
- else
- {
- // Log "Error finding native search directories from aspnetcore application.
- FINISHED(E_FAIL);
- }
- }
-
- FINISHED_IF_FAILED(struNativeSearchPaths.SyncWithBuffer());
-
- fFound = FALSE;
-
- // The native search directories are semicolon delimited.
- // Split on semicolons, append aspnetcorerh.dll, and check if the file exists.
- while ((intIndex = struNativeSearchPaths.IndexOf(L";", intPrevIndex)) != -1)
- {
- FINISHED_IF_FAILED(struNativeDllLocation.Copy(&struNativeSearchPaths.QueryStr()[intPrevIndex], intIndex - intPrevIndex));
-
- if (!struNativeDllLocation.EndsWith(L"\\"))
- {
- FINISHED_IF_FAILED(struNativeDllLocation.Append(L"\\"));
- }
-
- FINISHED_IF_FAILED(struNativeDllLocation.Append(libraryName));
-
- if (UTILITY::CheckIfFileExists(struNativeDllLocation.QueryStr()))
- {
- FINISHED_IF_FAILED(struFilename->Copy(struNativeDllLocation));
- fFound = TRUE;
- break;
- }
-
- intPrevIndex = intIndex + 1;
- }
-
- if (!fFound)
- {
- FINISHED(E_FAIL);
- }
-
-Finished:
- if (FAILED(hr) && hmHostFxrDll != NULL)
- {
- FreeLibrary(hmHostFxrDll);
- }
- return hr;
-}
-
VOID
APPLICATION_INFO::RecycleApplication()
{
diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
index 989120a538..ddf3e23aaa 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h
@@ -9,31 +9,20 @@
#include "aspnetcore_shim_config.h"
#include "iapplication.h"
#include "SRWSharedLock.h"
+#include "HandlerResolver.h"
#define API_BUFFER_TOO_SMALL 0x80008098
-typedef
-HRESULT
-(WINAPI * PFN_ASPNETCORE_CREATE_APPLICATION)(
- _In_ IHttpServer *pServer,
- _In_ IHttpApplication *pHttpApplication,
- _In_ APPLICATION_PARAMETER *pParameters,
- _In_ DWORD nParameters,
- _Out_ IAPPLICATION **pApplication
- );
-
extern BOOL g_fRecycleProcessCalled;
class APPLICATION_INFO
{
public:
- APPLICATION_INFO(_In_ IHttpServer &pServer) :
+ APPLICATION_INFO(IHttpServer &pServer) :
m_pServer(pServer),
m_cRefs(1),
- m_fValid(FALSE),
- m_pConfiguration(nullptr),
- m_pfnAspNetCoreCreateApplication(NULL)
+ m_handlerResolver(nullptr)
{
InitializeSRWLock(&m_applicationLock);
}
@@ -44,19 +33,25 @@ public:
return m_struInfoKey.QueryStr();
}
+ STRU*
+ QueryConfigPath()
+ {
+ return &m_struConfigPath;
+ }
+
virtual
~APPLICATION_INFO();
-
- static
+
+ static
void
StaticInitialize()
{
- InitializeSRWLock(&s_requestHandlerLoadLock);
}
HRESULT
Initialize(
- _In_ IHttpApplication &pApplication
+ IHttpApplication &pApplication,
+ HandlerResolver *pHandlerResolver
);
VOID
@@ -74,24 +69,6 @@ public:
}
}
- BOOL
- IsValid()
- {
- return m_fValid;
- }
-
- VOID
- MarkValid()
- {
- m_fValid = TRUE;
- }
-
- ASPNETCORE_SHIM_CONFIG*
- QueryConfig()
- {
- return m_pConfiguration.get();
- }
-
VOID
RecycleApplication();
@@ -105,31 +82,17 @@ public:
);
private:
- HRESULT FindRequestHandlerAssembly(STRU& location);
- HRESULT FindNativeAssemblyFromGlobalLocation(PCWSTR libraryName, STRU* location);
- HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS* hostfxrOptions, PCWSTR libraryName, STRU* location);
static DWORD WINAPI DoRecycleApplication(LPVOID lpParam);
mutable LONG m_cRefs;
+ STRU m_struConfigPath;
STRU m_struInfoKey;
- BOOL m_fValid;
SRWLOCK m_applicationLock;
IHttpServer &m_pServer;
- PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
-
- std::unique_ptr m_pConfiguration;
+ HandlerResolver *m_handlerResolver;
+
std::unique_ptr m_pApplication;
-
-
- static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
- static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
-
- static SRWLOCK s_requestHandlerLoadLock;
- static bool s_fAspnetcoreRHAssemblyLoaded;
- static bool s_fAspnetcoreRHLoadedError;
- static HMODULE s_hAspnetCoreRH;
- static PFN_ASPNETCORE_CREATE_APPLICATION s_pfnAspNetCoreCreateApplication;
};
class APPLICATION_INFO_HASH :
diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
index 20030594fb..1c5862a339 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
@@ -27,10 +27,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
{
HRESULT hr = S_OK;
APPLICATION_INFO *pApplicationInfo = NULL;
- BOOL fMixedHostingModelError = FALSE;
- BOOL fDuplicatedInProcessApp = FALSE;
PCWSTR pszApplicationId = NULL;
- APP_HOSTING_MODEL hostingModel = HOSTING_UNKNOWN;
STACK_STRU ( strEventMsg, 256 );
@@ -80,34 +77,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
pApplicationInfo = new APPLICATION_INFO(m_pHttpServer);
- FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication));
-
- hostingModel = pApplicationInfo->QueryConfig()->QueryHostingModel();
-
- if (m_pApplicationInfoHash->Count() == 0)
- {
- m_hostingModel = hostingModel;
- pApplicationInfo->MarkValid();
- }
- else
- {
- if (hostingModel == HOSTING_OUT_PROCESS && hostingModel == m_hostingModel)
- {
- pApplicationInfo->MarkValid();
- }
- else
- {
- if (hostingModel != m_hostingModel)
- {
- fMixedHostingModelError = TRUE;
- }
- else
- {
- fDuplicatedInProcessApp = TRUE;
- }
- }
- }
-
+ FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication, &m_handlerResolver));
FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
*ppApplicationInfo = pApplicationInfo;
@@ -115,26 +85,6 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
}
Finished:
- // log the error
- if (fDuplicatedInProcessApp)
- {
- UTILITY::LogEventF(g_hEventLog,
- EVENTLOG_ERROR_TYPE,
- ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP,
- ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG,
- pszApplicationId);
-
- }
- else if (fMixedHostingModelError)
- {
- UTILITY::LogEventF(g_hEventLog,
- EVENTLOG_ERROR_TYPE,
- ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
- ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
- pszApplicationId,
- hostingModel);
- }
-
if (pApplicationInfo != NULL)
{
pApplicationInfo->DereferenceApplicationInfo();
@@ -160,7 +110,7 @@ APPLICATION_MANAGER::FindConfigChangedApplication(
// Config Change context contains the original config path that changed
// and a multiStr containing
CONFIG_CHANGE_CONTEXT* pContext = static_cast(pvContext);
- STRU* pstruConfigPath = pEntry->QueryConfig()->QueryConfigPath();
+ STRU* pstruConfigPath = pEntry->QueryConfigPath();
// check if the application path contains our app/subapp by seeing if the config path
// starts with the notification path.
diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.h b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
index f01df15844..165f3c9d3e 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
@@ -85,10 +85,10 @@ public:
}
}
- static HRESULT StaticInitialize(IHttpServer& pHttpServer)
+ static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
{
assert(!sm_pApplicationManager);
- sm_pApplicationManager = new APPLICATION_MANAGER(pHttpServer);
+ sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
RETURN_IF_FAILED(sm_pApplicationManager->Initialize());
APPLICATION_INFO::StaticInitialize();
@@ -110,19 +110,21 @@ public:
}
private:
- APPLICATION_MANAGER(IHttpServer& pHttpServer) :
+ APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
m_pApplicationInfoHash(NULL),
m_hostingModel(HOSTING_UNKNOWN),
m_fDebugInitialize(FALSE),
- m_pHttpServer(pHttpServer)
+ m_pHttpServer(pHttpServer),
+ m_handlerResolver(hModule, pHttpServer)
{
InitializeSRWLock(&m_srwLock);
}
APPLICATION_INFO_HASH *m_pApplicationInfoHash;
static APPLICATION_MANAGER *sm_pApplicationManager;
- SRWLOCK m_srwLock;
+ SRWLOCK m_srwLock {};
APP_HOSTING_MODEL m_hostingModel;
BOOL m_fDebugInitialize;
IHttpServer &m_pHttpServer;
+ HandlerResolver m_handlerResolver;
};
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
index 4cb6b222cf..6785bac95a 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
@@ -20,13 +20,14 @@ ASPNETCORE_SHIM_CONFIG::Populate(
CComPtr pAspNetCoreElement;
pAdminManager = pHttpServer->GetAdminManager();
- RETURN_IF_FAILED(m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath()));
RETURN_IF_FAILED(m_struApplicationPhysicalPath.Copy(pHttpApplication->GetApplicationPhysicalPath()));
const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION;
+ const CComBSTR applicationConfigPath = pHttpApplication->GetAppConfigPath();
+
RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection,
- m_struConfigPath.QueryStr(),
+ applicationConfigPath,
&pAspNetCoreElement));
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h
index 5229f95b79..a8f96db425 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h
+++ b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.h
@@ -38,12 +38,6 @@ public:
return &m_struApplicationPhysicalPath;
}
- STRU*
- QueryConfigPath()
- {
- return &m_struConfigPath;
- }
-
STRU*
QueryProcessPath()
{
@@ -78,7 +72,6 @@ private:
STRU m_struArguments;
STRU m_struProcessPath;
STRU m_struApplicationPhysicalPath;
- STRU m_struConfigPath;
APP_HOSTING_MODEL m_hostingModel;
STRU m_struHostFxrLocation;
STRU m_struHandlerVersion;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
index 0526d1ccab..10f178ae70 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
@@ -16,6 +16,7 @@ DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2.dll");
HANDLE g_hEventLog = NULL;
BOOL g_fRecycleProcessCalled = FALSE;
BOOL g_fInShutdown = FALSE;
+HINSTANCE g_hServerModule;
VOID
StaticCleanup()
@@ -40,6 +41,7 @@ BOOL WINAPI DllMain(HMODULE hModule,
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
+ g_hServerModule = hModule;
DisableThreadLibraryCalls(hModule);
DebugInitialize(hModule);
break;
@@ -157,7 +159,7 @@ HRESULT
pFactory = NULL;
- FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(*pHttpServer));
+ FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(g_hServerModule, *pHttpServer));
pGlobalModule = NULL;
diff --git a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
index 1f0ed72db1..2d9fe9150c 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
@@ -89,13 +89,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
pHttpContext,
&m_pApplicationInfo));
- if (!m_pApplicationInfo->IsValid())
- {
- // Application cannot be started due to wrong hosting mode
- // the error should already been logged to window event log for the first request
- FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
- }
-
DBG_ASSERT(pHttpContext);
std::unique_ptr pApplication;
diff --git a/src/AspNetCoreModuleV2/CommonLib/HandleWrapper.h b/src/AspNetCoreModuleV2/CommonLib/HandleWrapper.h
index 67f980dfd4..6764f4c14d 100644
--- a/src/AspNetCoreModuleV2/CommonLib/HandleWrapper.h
+++ b/src/AspNetCoreModuleV2/CommonLib/HandleWrapper.h
@@ -19,6 +19,13 @@ struct NullHandleTraits
static void Close(HANDLE handle) { CloseHandle(handle); }
};
+struct ModuleHandleTraits
+{
+ using HandleType = HMODULE;
+ static constexpr HMODULE DefaultHandle = NULL;
+ static void Close(HMODULE handle) { FreeModule(handle); }
+};
+
template
class HandleWrapper
{
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/XElementExtensions.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/XElementExtensions.cs
index 45ed897019..35d1b013cd 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/XElementExtensions.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/XElementExtensions.cs
@@ -7,7 +7,7 @@ using System.Xml.Linq;
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{
- internal static class XElementExtensions
+ public static class XElementExtensions
{
public static XElement RequiredElement(this XElement element, string name)
{
diff --git a/test/Common.FunctionalTests/MultiApplicationTests.cs b/test/Common.FunctionalTests/MultiApplicationTests.cs
new file mode 100644
index 0000000000..df9bb035f9
--- /dev/null
+++ b/test/Common.FunctionalTests/MultiApplicationTests.cs
@@ -0,0 +1,141 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
+using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
+using Microsoft.AspNetCore.Testing.xunit;
+using Microsoft.Extensions.Logging;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
+{
+ [Collection(PublishedSitesCollection.Name)]
+ public class MultiApplicationTests : IISFunctionalTestBase
+ {
+ private readonly PublishedSitesFixture _fixture;
+
+ private PublishedApplication _publishedApplication;
+ private PublishedApplication _rootApplication;
+
+ public MultiApplicationTests(PublishedSitesFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [ConditionalFact]
+ public async Task RunsTwoOutOfProcessApps()
+ {
+ var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true);
+ parameters.ServerConfigActionList.Add(DuplicateApplication);
+ var result = await DeployAsync(parameters);
+ var id1 = await result.HttpClient.GetStringAsync("/app1/ProcessId");
+ var id2 = await result.HttpClient.GetStringAsync("/app2/ProcessId");
+ Assert.NotEqual(id2, id1);
+ }
+
+ [ConditionalFact]
+ public async Task FailsAndLogsWhenRunningTwoInProcessApps()
+ {
+ var parameters = _fixture.GetBaseDeploymentParameters(HostingModel.InProcess, publish: true);
+ parameters.ServerConfigActionList.Add(DuplicateApplication);
+ var result = await DeployAsync(parameters);
+ var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld");
+ var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld");
+ Assert.Equal(200, (int)result1.StatusCode);
+ Assert.Equal(500, (int)result2.StatusCode);
+ StopServer();
+ EventLogHelpers.VerifyEventLogEvent(TestSink, "Only one inprocess application is allowed per IIS application pool");
+ }
+
+ [ConditionalTheory]
+ [InlineData(HostingModel.OutOfProcess)]
+ [InlineData(HostingModel.InProcess)]
+ public async Task FailsAndLogsEventLogForMixedHostingModel(HostingModel firstApp)
+ {
+ var parameters = _fixture.GetBaseDeploymentParameters(firstApp, publish: true);
+ parameters.ServerConfigActionList.Add(DuplicateApplication);
+ var result = await DeployAsync(parameters);
+
+ // Modify hosting model of other app to be the opposite
+ var otherApp = firstApp == HostingModel.InProcess ? HostingModel.OutOfProcess : HostingModel.InProcess;
+ SetHostingModel(_publishedApplication.Path, otherApp);
+
+ var result1 = await result.HttpClient.GetAsync("/app1/HelloWorld");
+ var result2 = await result.HttpClient.GetAsync("/app2/HelloWorld");
+ Assert.Equal(200, (int)result1.StatusCode);
+ Assert.Equal(500, (int)result2.StatusCode);
+ StopServer();
+ EventLogHelpers.VerifyEventLogEvent(TestSink, "Mixed hosting model is not supported.");
+ }
+
+ private void SetHostingModel(string directory, HostingModel model)
+ {
+ var webConfigLocation = GetWebConfigLocation(directory);
+ XDocument webConfig = XDocument.Load(webConfigLocation);
+ webConfig.Root
+ .GetOrAdd("system.webServer")
+ .GetOrAdd("aspNetCore")
+ .SetAttributeValue("hostingModel", model.ToString());
+ webConfig.Save(webConfigLocation);
+ }
+
+ private void DuplicateApplication(XElement config, string contentRoot)
+ {
+ var siteElement = config
+ .RequiredElement("system.applicationHost")
+ .RequiredElement("sites")
+ .RequiredElement("site");
+
+ var application = siteElement
+ .RequiredElement("application");
+
+ application.SetAttributeValue("path", "/app1");
+
+ var source = new DirectoryInfo(contentRoot);
+
+ var destination = new DirectoryInfo(contentRoot + "anotherApp");
+ destination.Create();
+ Helpers.CopyFiles(source, destination, Logger);
+
+ _publishedApplication = new PublishedApplication(destination.FullName, Logger);
+
+ var newApplication = new XElement(application);
+ newApplication.SetAttributeValue("path", "/app2");
+ newApplication.RequiredElement("virtualDirectory")
+ .SetAttributeValue("physicalPath", destination.FullName);
+
+ siteElement.Add(newApplication);
+
+ // IIS Express requires root application to exist
+ var rootApplicationDirectory = new DirectoryInfo(contentRoot + "rootApp");
+ rootApplicationDirectory.Create();
+
+ _rootApplication = new PublishedApplication(rootApplicationDirectory.FullName, Logger);
+ File.WriteAllText(GetWebConfigLocation(rootApplicationDirectory.FullName), "");
+
+ var rootApplication = new XElement(application);
+ rootApplication.SetAttributeValue("path", "/");
+ rootApplication.RequiredElement("virtualDirectory")
+ .SetAttributeValue("physicalPath", rootApplicationDirectory.FullName);
+
+ siteElement.Add(rootApplication);
+ }
+
+ private static string GetWebConfigLocation(string siteRoot)
+ {
+ return Path.Combine(siteRoot, "web.config");
+ }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+ _rootApplication.Dispose();
+ _publishedApplication.Dispose();
+ }
+ }
+}
diff --git a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs
index 1d53ba6843..7729b4359b 100644
--- a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs
+++ b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs
@@ -12,7 +12,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public static void VerifyEventLogEvent(ITestSink testSink, string expectedRegexMatchString)
{
var eventLogRegex = new Regex($"Event Log: {expectedRegexMatchString}");
- Assert.Contains(testSink.Writes, context => eventLogRegex.IsMatch(context.Message));
+
+ int count = 0;
+ foreach (var context in testSink.Writes)
+ {
+ if (eventLogRegex.IsMatch(context.Message))
+ {
+ count++;
+ }
+ }
+ Assert.Equal(1, count);
}
}
}
diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs
index 73d48fd6ca..2781da1944 100644
--- a/test/Common.FunctionalTests/Utilities/Helpers.cs
+++ b/test/Common.FunctionalTests/Utilities/Helpers.cs
@@ -11,6 +11,7 @@ using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing;
+using Microsoft.Extensions.Logging;
using Xunit;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
@@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
-
+
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
{
@@ -57,5 +58,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
await Task.WhenAll(tasks);
}
+
+ public static void CopyFiles(DirectoryInfo source, DirectoryInfo target, ILogger logger)
+ {
+ foreach (DirectoryInfo directoryInfo in source.GetDirectories())
+ {
+ CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
+ }
+ logger.LogDebug($"Processing {target.FullName}");
+ foreach (FileInfo fileInfo in source.GetFiles())
+ {
+ logger.LogDebug($" Copying {fileInfo.Name}");
+ var destFileName = Path.Combine(target.FullName, fileInfo.Name);
+ fileInfo.CopyTo(destFileName);
+ }
+ }
}
}
diff --git a/test/WebSites/OutOfProcessWebSite/Startup.cs b/test/WebSites/OutOfProcessWebSite/Startup.cs
index be44480891..059b5a1264 100644
--- a/test/WebSites/OutOfProcessWebSite/Startup.cs
+++ b/test/WebSites/OutOfProcessWebSite/Startup.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@@ -109,10 +110,15 @@ namespace TestSites
private async Task HostingEnvironment(HttpContext context)
{
var hostingEnv = context.RequestServices.GetService();
-
+
await context.Response.WriteAsync("ContentRootPath "+hostingEnv.ContentRootPath + Environment.NewLine);
await context.Response.WriteAsync("WebRootPath "+hostingEnv.WebRootPath + Environment.NewLine);
await context.Response.WriteAsync("CurrentDirectory "+Environment.CurrentDirectory);
}
+
+ private async Task ProcessId(HttpContext context)
+ {
+ await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
+ }
}
}