Split handler resolution from application info (#1177)

This commit is contained in:
Pavel Krymets 2018-08-09 11:32:51 -07:00 committed by GitHub
parent e6330ab19b
commit 8361b8cfa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 543 additions and 415 deletions

View File

@ -229,6 +229,7 @@
<ClInclude Include="aspnetcore_shim_config.h" /> <ClInclude Include="aspnetcore_shim_config.h" />
<ClInclude Include="globalmodule.h" /> <ClInclude Include="globalmodule.h" />
<ClInclude Include="applicationmanager.h" /> <ClInclude Include="applicationmanager.h" />
<ClInclude Include="HandlerResolver.h" />
<ClInclude Include="proxymodule.h" /> <ClInclude Include="proxymodule.h" />
<ClInclude Include="ServerErrorApplication.h" /> <ClInclude Include="ServerErrorApplication.h" />
<ClInclude Include="ServerErrorHandler.h" /> <ClInclude Include="ServerErrorHandler.h" />
@ -240,6 +241,7 @@
<ClCompile Include="aspnetcore_shim_config.cpp" /> <ClCompile Include="aspnetcore_shim_config.cpp" />
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
<ClCompile Include="globalmodule.cpp" /> <ClCompile Include="globalmodule.cpp" />
<ClCompile Include="HandlerResolver.cpp" />
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>

View File

@ -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<HOSTFXR_OPTIONS> 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<PFN_ASPNETCORE_CREATE_APPLICATION>(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<hostfxr_get_native_search_directories_fn>(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;
}

View File

@ -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 <memory>
#include "iapplication.h"
#include <string>
#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<ModuleHandleTraits> m_hRequestHandlerDll;
HandleWrapper<ModuleHandleTraits> m_hHostFxrDll;
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication;
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
};

View File

@ -17,18 +17,6 @@
#include "ServerErrorApplication.h" #include "ServerErrorApplication.h"
#include "AppOfflineApplication.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() APPLICATION_INFO::~APPLICATION_INFO()
{ {
ShutDownApplication(); ShutDownApplication();
@ -36,13 +24,13 @@ APPLICATION_INFO::~APPLICATION_INFO()
HRESULT HRESULT
APPLICATION_INFO::Initialize( APPLICATION_INFO::Initialize(
_In_ IHttpApplication &pApplication _In_ IHttpApplication &pApplication,
HandlerResolver * pHandlerResolver
) )
{ {
m_pConfiguration.reset(new ASPNETCORE_SHIM_CONFIG()); m_handlerResolver = pHandlerResolver;
RETURN_IF_FAILED(m_pConfiguration->Populate(&m_pServer, &pApplication)); RETURN_IF_FAILED(m_struConfigPath.Copy(pApplication.GetAppConfigPath()));
RETURN_IF_FAILED(m_struInfoKey.Copy(pApplication.GetApplicationId())); RETURN_IF_FAILED(m_struInfoKey.Copy(pApplication.GetApplicationId()));
return S_OK; return S_OK;
} }
@ -84,20 +72,15 @@ APPLICATION_INFO::GetOrCreateApplication(
else else
{ {
STRU struExeLocation; STRU struExeLocation;
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation)); PFN_ASPNETCORE_CREATE_APPLICATION pfnAspNetCoreCreateApplication;
FINISHED_IF_FAILED(m_handlerResolver->GetApplicationFactory(httpApplication, struExeLocation, &pfnAspNetCoreCreateApplication));
if (m_pfnAspNetCoreCreateApplication == NULL)
{
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
}
std::array<APPLICATION_PARAMETER, 1> parameters { std::array<APPLICATION_PARAMETER, 1> parameters {
{"InProcessExeLocation", struExeLocation.QueryStr()} {"InProcessExeLocation", struExeLocation.QueryStr()}
}; };
LOG_INFO("Creating handler application"); LOG_INFO("Creating handler application");
IAPPLICATION * newApplication; IAPPLICATION * newApplication;
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication( FINISHED_IF_FAILED(pfnAspNetCoreCreateApplication(
&m_pServer, &m_pServer,
&httpApplication, &httpApplication,
parameters.data(), parameters.data(),
@ -130,266 +113,6 @@ Finished:
return hr; 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<HOSTFXR_OPTIONS> 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 VOID
APPLICATION_INFO::RecycleApplication() APPLICATION_INFO::RecycleApplication()
{ {

View File

@ -9,31 +9,20 @@
#include "aspnetcore_shim_config.h" #include "aspnetcore_shim_config.h"
#include "iapplication.h" #include "iapplication.h"
#include "SRWSharedLock.h" #include "SRWSharedLock.h"
#include "HandlerResolver.h"
#define API_BUFFER_TOO_SMALL 0x80008098 #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; extern BOOL g_fRecycleProcessCalled;
class APPLICATION_INFO class APPLICATION_INFO
{ {
public: public:
APPLICATION_INFO(_In_ IHttpServer &pServer) : APPLICATION_INFO(IHttpServer &pServer) :
m_pServer(pServer), m_pServer(pServer),
m_cRefs(1), m_cRefs(1),
m_fValid(FALSE), m_handlerResolver(nullptr)
m_pConfiguration(nullptr),
m_pfnAspNetCoreCreateApplication(NULL)
{ {
InitializeSRWLock(&m_applicationLock); InitializeSRWLock(&m_applicationLock);
} }
@ -44,6 +33,12 @@ public:
return m_struInfoKey.QueryStr(); return m_struInfoKey.QueryStr();
} }
STRU*
QueryConfigPath()
{
return &m_struConfigPath;
}
virtual virtual
~APPLICATION_INFO(); ~APPLICATION_INFO();
@ -51,12 +46,12 @@ public:
void void
StaticInitialize() StaticInitialize()
{ {
InitializeSRWLock(&s_requestHandlerLoadLock);
} }
HRESULT HRESULT
Initialize( Initialize(
_In_ IHttpApplication &pApplication IHttpApplication &pApplication,
HandlerResolver *pHandlerResolver
); );
VOID 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 VOID
RecycleApplication(); RecycleApplication();
@ -105,31 +82,17 @@ public:
); );
private: 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); static DWORD WINAPI DoRecycleApplication(LPVOID lpParam);
mutable LONG m_cRefs; mutable LONG m_cRefs;
STRU m_struConfigPath;
STRU m_struInfoKey; STRU m_struInfoKey;
BOOL m_fValid;
SRWLOCK m_applicationLock; SRWLOCK m_applicationLock;
IHttpServer &m_pServer; IHttpServer &m_pServer;
PFN_ASPNETCORE_CREATE_APPLICATION m_pfnAspNetCoreCreateApplication; HandlerResolver *m_handlerResolver;
std::unique_ptr<ASPNETCORE_SHIM_CONFIG> m_pConfiguration;
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> m_pApplication; std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> 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 : class APPLICATION_INFO_HASH :

View File

@ -27,10 +27,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
APPLICATION_INFO *pApplicationInfo = NULL; APPLICATION_INFO *pApplicationInfo = NULL;
BOOL fMixedHostingModelError = FALSE;
BOOL fDuplicatedInProcessApp = FALSE;
PCWSTR pszApplicationId = NULL; PCWSTR pszApplicationId = NULL;
APP_HOSTING_MODEL hostingModel = HOSTING_UNKNOWN;
STACK_STRU ( strEventMsg, 256 ); STACK_STRU ( strEventMsg, 256 );
@ -80,34 +77,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
pApplicationInfo = new APPLICATION_INFO(m_pHttpServer); pApplicationInfo = new APPLICATION_INFO(m_pHttpServer);
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication)); FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication, &m_handlerResolver));
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(m_pApplicationInfoHash->InsertRecord(pApplicationInfo)); FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
*ppApplicationInfo = pApplicationInfo; *ppApplicationInfo = pApplicationInfo;
@ -115,26 +85,6 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
} }
Finished: 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) if (pApplicationInfo != NULL)
{ {
pApplicationInfo->DereferenceApplicationInfo(); pApplicationInfo->DereferenceApplicationInfo();
@ -160,7 +110,7 @@ APPLICATION_MANAGER::FindConfigChangedApplication(
// Config Change context contains the original config path that changed // Config Change context contains the original config path that changed
// and a multiStr containing // and a multiStr containing
CONFIG_CHANGE_CONTEXT* pContext = static_cast<CONFIG_CHANGE_CONTEXT*>(pvContext); CONFIG_CHANGE_CONTEXT* pContext = static_cast<CONFIG_CHANGE_CONTEXT*>(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 // check if the application path contains our app/subapp by seeing if the config path
// starts with the notification path. // starts with the notification path.

View File

@ -85,10 +85,10 @@ public:
} }
} }
static HRESULT StaticInitialize(IHttpServer& pHttpServer) static HRESULT StaticInitialize(HMODULE hModule, IHttpServer& pHttpServer)
{ {
assert(!sm_pApplicationManager); assert(!sm_pApplicationManager);
sm_pApplicationManager = new APPLICATION_MANAGER(pHttpServer); sm_pApplicationManager = new APPLICATION_MANAGER(hModule, pHttpServer);
RETURN_IF_FAILED(sm_pApplicationManager->Initialize()); RETURN_IF_FAILED(sm_pApplicationManager->Initialize());
APPLICATION_INFO::StaticInitialize(); APPLICATION_INFO::StaticInitialize();
@ -110,19 +110,21 @@ public:
} }
private: private:
APPLICATION_MANAGER(IHttpServer& pHttpServer) : APPLICATION_MANAGER(HMODULE hModule, IHttpServer& pHttpServer) :
m_pApplicationInfoHash(NULL), m_pApplicationInfoHash(NULL),
m_hostingModel(HOSTING_UNKNOWN), m_hostingModel(HOSTING_UNKNOWN),
m_fDebugInitialize(FALSE), m_fDebugInitialize(FALSE),
m_pHttpServer(pHttpServer) m_pHttpServer(pHttpServer),
m_handlerResolver(hModule, pHttpServer)
{ {
InitializeSRWLock(&m_srwLock); InitializeSRWLock(&m_srwLock);
} }
APPLICATION_INFO_HASH *m_pApplicationInfoHash; APPLICATION_INFO_HASH *m_pApplicationInfoHash;
static APPLICATION_MANAGER *sm_pApplicationManager; static APPLICATION_MANAGER *sm_pApplicationManager;
SRWLOCK m_srwLock; SRWLOCK m_srwLock {};
APP_HOSTING_MODEL m_hostingModel; APP_HOSTING_MODEL m_hostingModel;
BOOL m_fDebugInitialize; BOOL m_fDebugInitialize;
IHttpServer &m_pHttpServer; IHttpServer &m_pHttpServer;
HandlerResolver m_handlerResolver;
}; };

View File

@ -20,13 +20,14 @@ ASPNETCORE_SHIM_CONFIG::Populate(
CComPtr<IAppHostElement> pAspNetCoreElement; CComPtr<IAppHostElement> pAspNetCoreElement;
pAdminManager = pHttpServer->GetAdminManager(); pAdminManager = pHttpServer->GetAdminManager();
RETURN_IF_FAILED(m_struConfigPath.Copy(pHttpApplication->GetAppConfigPath()));
RETURN_IF_FAILED(m_struApplicationPhysicalPath.Copy(pHttpApplication->GetApplicationPhysicalPath())); RETURN_IF_FAILED(m_struApplicationPhysicalPath.Copy(pHttpApplication->GetApplicationPhysicalPath()));
const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION; const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION;
const CComBSTR applicationConfigPath = pHttpApplication->GetAppConfigPath();
RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection, RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection,
m_struConfigPath.QueryStr(), applicationConfigPath,
&pAspNetCoreElement)); &pAspNetCoreElement));
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement, RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,

View File

@ -38,12 +38,6 @@ public:
return &m_struApplicationPhysicalPath; return &m_struApplicationPhysicalPath;
} }
STRU*
QueryConfigPath()
{
return &m_struConfigPath;
}
STRU* STRU*
QueryProcessPath() QueryProcessPath()
{ {
@ -78,7 +72,6 @@ private:
STRU m_struArguments; STRU m_struArguments;
STRU m_struProcessPath; STRU m_struProcessPath;
STRU m_struApplicationPhysicalPath; STRU m_struApplicationPhysicalPath;
STRU m_struConfigPath;
APP_HOSTING_MODEL m_hostingModel; APP_HOSTING_MODEL m_hostingModel;
STRU m_struHostFxrLocation; STRU m_struHostFxrLocation;
STRU m_struHandlerVersion; STRU m_struHandlerVersion;

View File

@ -16,6 +16,7 @@ DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2.dll");
HANDLE g_hEventLog = NULL; HANDLE g_hEventLog = NULL;
BOOL g_fRecycleProcessCalled = FALSE; BOOL g_fRecycleProcessCalled = FALSE;
BOOL g_fInShutdown = FALSE; BOOL g_fInShutdown = FALSE;
HINSTANCE g_hServerModule;
VOID VOID
StaticCleanup() StaticCleanup()
@ -40,6 +41,7 @@ BOOL WINAPI DllMain(HMODULE hModule,
switch (ul_reason_for_call) switch (ul_reason_for_call)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
g_hServerModule = hModule;
DisableThreadLibraryCalls(hModule); DisableThreadLibraryCalls(hModule);
DebugInitialize(hModule); DebugInitialize(hModule);
break; break;
@ -157,7 +159,7 @@ HRESULT
pFactory = NULL; pFactory = NULL;
FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(*pHttpServer)); FINISHED_IF_FAILED(APPLICATION_MANAGER::StaticInitialize(g_hServerModule, *pHttpServer));
pGlobalModule = NULL; pGlobalModule = NULL;

View File

@ -89,13 +89,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
pHttpContext, pHttpContext,
&m_pApplicationInfo)); &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); DBG_ASSERT(pHttpContext);
std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication; std::unique_ptr<IAPPLICATION, IAPPLICATION_DELETER> pApplication;

View File

@ -19,6 +19,13 @@ struct NullHandleTraits
static void Close(HANDLE handle) { CloseHandle(handle); } 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<typename traits> template<typename traits>
class HandleWrapper class HandleWrapper
{ {

View File

@ -7,7 +7,7 @@ using System.Xml.Linq;
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{ {
internal static class XElementExtensions public static class XElementExtensions
{ {
public static XElement RequiredElement(this XElement element, string name) public static XElement RequiredElement(this XElement element, string name)
{ {

View File

@ -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), "<configuration></configuration>");
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();
}
}
}

View File

@ -12,7 +12,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public static void VerifyEventLogEvent(ITestSink testSink, string expectedRegexMatchString) public static void VerifyEventLogEvent(ITestSink testSink, string expectedRegexMatchString)
{ {
var eventLogRegex = new Regex($"Event Log: {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);
} }
} }
} }

View File

@ -11,6 +11,7 @@ using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
@ -57,5 +58,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
await Task.WhenAll(tasks); 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);
}
}
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -114,5 +115,10 @@ namespace TestSites
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);
} }
private async Task ProcessId(HttpContext context)
{
await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
}
} }
} }