Split handler resolution from application info (#1177)
This commit is contained in:
parent
e6330ab19b
commit
8361b8cfa9
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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,19 +33,25 @@ public:
|
||||||
return m_struInfoKey.QueryStr();
|
return m_struInfoKey.QueryStr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STRU*
|
||||||
|
QueryConfigPath()
|
||||||
|
{
|
||||||
|
return &m_struConfigPath;
|
||||||
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
~APPLICATION_INFO();
|
~APPLICATION_INFO();
|
||||||
|
|
||||||
static
|
static
|
||||||
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 :
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
|
||||||
|
|
||||||
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
|
||||||
|
|
||||||
|
|
||||||
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
|
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
|
||||||
{
|
{
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -109,10 +110,15 @@ namespace TestSites
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ProcessId(HttpContext context)
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync(Process.GetCurrentProcess().Id.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue