Merge pull request #1321 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
c86f308a3a
|
|
@ -19,6 +19,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<AspNetCoreModuleHostingModel>inprocess</AspNetCoreModuleHostingModel>
|
||||
<AspNetCoreHostingModel>inprocess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#define FileDescription "IIS AspNetCore Module. Commit: " CommitHash
|
||||
#define FileDescription "IIS ASP.NET Core Module. Commit: " CommitHash
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@
|
|||
<ClInclude Include="applicationinfo.h" />
|
||||
<ClInclude Include="AppOfflineApplication.h" />
|
||||
<ClInclude Include="AppOfflineHandler.h" />
|
||||
<ClInclude Include="aspnetcore_shim_config.h" />
|
||||
<ClInclude Include="ShimOptions.h" />
|
||||
<ClInclude Include="globalmodule.h" />
|
||||
<ClInclude Include="applicationmanager.h" />
|
||||
<ClInclude Include="HandlerResolver.h" />
|
||||
|
|
@ -246,7 +246,7 @@
|
|||
<ClCompile Include="applicationmanager.cpp" />
|
||||
<ClCompile Include="AppOfflineApplication.cpp" />
|
||||
<ClCompile Include="AppOfflineHandler.cpp" />
|
||||
<ClCompile Include="aspnetcore_shim_config.cpp" />
|
||||
<ClCompile Include="ShimOptions.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="globalmodule.cpp" />
|
||||
<ClCompile Include="HandlerResolver.cpp" />
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "file_utility.h"
|
||||
#include "LoggingHelpers.h"
|
||||
#include "resources.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
#include "WebConfigConfigurationSource.h"
|
||||
|
||||
const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
|
||||
const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
|
||||
|
|
@ -25,7 +27,7 @@ HandlerResolver::HandlerResolver(HMODULE hModule, IHttpServer &pServer)
|
|||
}
|
||||
|
||||
HRESULT
|
||||
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
||||
HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory)
|
||||
{
|
||||
HRESULT hr;
|
||||
PCWSTR pstrHandlerDllName;
|
||||
|
|
@ -65,7 +67,7 @@ HandlerResolver::LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPN
|
|||
RETURN_IF_FAILED(LoggingHelpers::CreateLoggingProvider(
|
||||
pConfiguration.QueryStdoutLogEnabled(),
|
||||
!m_pServer.IsCommandLineLaunch(),
|
||||
pConfiguration.QueryStdoutLogFile()->QueryStr(),
|
||||
pConfiguration.QueryStdoutLogFile().c_str(),
|
||||
pApplication.GetApplicationPhysicalPath(),
|
||||
outputManager));
|
||||
|
||||
|
|
@ -129,20 +131,20 @@ HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::uniq
|
|||
{
|
||||
try
|
||||
{
|
||||
ASPNETCORE_SHIM_CONFIG pConfiguration;
|
||||
RETURN_IF_FAILED(pConfiguration.Populate(&m_pServer, &pApplication));
|
||||
const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pApplication);
|
||||
ShimOptions options(configurationSource);
|
||||
|
||||
SRWExclusiveLock lock(m_requestHandlerLoadLock);
|
||||
if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN)
|
||||
{
|
||||
// Mixed hosting models
|
||||
if (m_loadedApplicationHostingModel != pConfiguration.QueryHostingModel())
|
||||
if (m_loadedApplicationHostingModel != options.QueryHostingModel())
|
||||
{
|
||||
EventLog::Error(
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR,
|
||||
ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG,
|
||||
pApplication.GetApplicationId(),
|
||||
pConfiguration.QueryHostingModel());
|
||||
options.QueryHostingModel());
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
|
@ -158,11 +160,20 @@ HandlerResolver::GetApplicationFactory(IHttpApplication &pApplication, std::uniq
|
|||
}
|
||||
}
|
||||
|
||||
m_loadedApplicationHostingModel = pConfiguration.QueryHostingModel();
|
||||
m_loadedApplicationHostingModel = options.QueryHostingModel();
|
||||
m_loadedApplicationId = pApplication.GetApplicationId();
|
||||
RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, pConfiguration, pApplicationFactory));
|
||||
RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory));
|
||||
|
||||
}
|
||||
catch(ConfigurationLoadException &ex)
|
||||
{
|
||||
EventLog::Error(
|
||||
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
|
||||
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
|
||||
ex.get_message().c_str());
|
||||
|
||||
RETURN_HR(E_FAIL);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
|
|
@ -178,7 +189,7 @@ void HandlerResolver::ResetHostingModel()
|
|||
|
||||
HRESULT
|
||||
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
|
||||
ASPNETCORE_SHIM_CONFIG& pConfiguration,
|
||||
ShimOptions& pConfiguration,
|
||||
PCWSTR pstrHandlerDllName,
|
||||
std::wstring& handlerDllPath
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#include "aspnetcore_shim_config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "ShimOptions.h"
|
||||
#include "hostfxroptions.h"
|
||||
#include "HandleWrapper.h"
|
||||
#include "ApplicationFactory.h"
|
||||
|
|
@ -18,8 +18,8 @@ public:
|
|||
void ResetHostingModel();
|
||||
|
||||
private:
|
||||
HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ASPNETCORE_SHIM_CONFIG& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
|
||||
HRESULT FindNativeAssemblyFromGlobalLocation(ASPNETCORE_SHIM_CONFIG& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
|
||||
HRESULT LoadRequestHandlerAssembly(IHttpApplication &pApplication, ShimOptions& pConfiguration, std::unique_ptr<ApplicationFactory>& pApplicationFactory);
|
||||
HRESULT FindNativeAssemblyFromGlobalLocation(ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath);
|
||||
HRESULT FindNativeAssemblyFromHostfxr(HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath);
|
||||
|
||||
HMODULE m_hModule;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class PollingAppOfflineApplication: public APPLICATION
|
|||
{
|
||||
public:
|
||||
PollingAppOfflineApplication(IHttpApplication& pApplication, PollingAppOfflineApplicationMode mode)
|
||||
:
|
||||
: APPLICATION(pApplication),
|
||||
m_ulLastCheckTime(0),
|
||||
m_appOfflineLocation(GetAppOfflineLocation(pApplication)),
|
||||
m_fAppOfflineFound(false),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "ShimOptions.h"
|
||||
|
||||
#include "StringHelpers.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
|
||||
#define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion"
|
||||
|
||||
ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) :
|
||||
m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_fStdoutLogEnabled(false)
|
||||
{
|
||||
auto const section = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION);
|
||||
auto hostingModel = section->GetString(CS_ASPNETCORE_HOSTING_MODEL).value_or(L"");
|
||||
|
||||
if (hostingModel.empty() || equals_ignore_case(hostingModel, CS_ASPNETCORE_HOSTING_MODEL_OUTOFPROCESS))
|
||||
{
|
||||
m_hostingModel = HOSTING_OUT_PROCESS;
|
||||
}
|
||||
else if (equals_ignore_case(hostingModel, CS_ASPNETCORE_HOSTING_MODEL_INPROCESS))
|
||||
{
|
||||
m_hostingModel = HOSTING_IN_PROCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigurationLoadException(format(
|
||||
L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" "
|
||||
"or hostingModel=\"outofprocess\" in the web.config file.", hostingModel.c_str()));
|
||||
}
|
||||
|
||||
if (m_hostingModel == HOSTING_OUT_PROCESS)
|
||||
{
|
||||
const auto handlerSettings = section->GetKeyValuePairs(CS_ASPNETCORE_HANDLER_SETTINGS);
|
||||
m_strHandlerVersion = find_element(handlerSettings, CS_ASPNETCORE_HANDLER_VERSION).value_or(std::wstring());
|
||||
}
|
||||
|
||||
m_strProcessPath = section->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH);
|
||||
m_strArguments = section->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT);
|
||||
m_fStdoutLogEnabled = section->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
|
||||
m_struStdoutLogFile = section->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// 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 <string>
|
||||
#include "ConfigurationSource.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
enum APP_HOSTING_MODEL
|
||||
{
|
||||
HOSTING_UNKNOWN = 0,
|
||||
HOSTING_IN_PROCESS,
|
||||
HOSTING_OUT_PROCESS
|
||||
};
|
||||
|
||||
class ShimOptions: NonCopyable
|
||||
{
|
||||
public:
|
||||
const std::wstring&
|
||||
QueryProcessPath() const
|
||||
{
|
||||
return m_strProcessPath;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryArguments() const
|
||||
{
|
||||
return m_strArguments;
|
||||
}
|
||||
|
||||
APP_HOSTING_MODEL
|
||||
QueryHostingModel() const
|
||||
{
|
||||
return m_hostingModel;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryHandlerVersion() const
|
||||
{
|
||||
return m_strHandlerVersion;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryStdoutLogEnabled() const
|
||||
{
|
||||
return m_fStdoutLogEnabled;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryStdoutLogFile() const
|
||||
{
|
||||
return m_struStdoutLogFile;
|
||||
}
|
||||
|
||||
ShimOptions(const ConfigurationSource &configurationSource);
|
||||
|
||||
private:
|
||||
std::wstring m_strArguments;
|
||||
std::wstring m_strProcessPath;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
std::wstring m_strHandlerVersion;
|
||||
std::wstring m_struStdoutLogFile;
|
||||
bool m_fStdoutLogEnabled;
|
||||
};
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "hostfxroptions.h"
|
||||
#include "aspnetcore_shim_config.h"
|
||||
#include "iapplication.h"
|
||||
#include "SRWSharedLock.h"
|
||||
#include "HandlerResolver.h"
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "aspnetcore_shim_config.h"
|
||||
|
||||
#include "EventLog.h"
|
||||
#include "config_utility.h"
|
||||
#include "ahutil.h"
|
||||
|
||||
HRESULT
|
||||
ASPNETCORE_SHIM_CONFIG::Populate(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpApplication *pHttpApplication
|
||||
)
|
||||
{
|
||||
STACK_STRU(strHostingModel, 12);
|
||||
CComPtr<IAppHostElement> pAspNetCoreElement;
|
||||
|
||||
IAppHostAdminManager *pAdminManager = pHttpServer->GetAdminManager();
|
||||
const CComBSTR bstrAspNetCoreSection = CS_ASPNETCORE_SECTION;
|
||||
const CComBSTR applicationConfigPath = pHttpApplication->GetAppConfigPath();
|
||||
|
||||
RETURN_IF_FAILED(pAdminManager->GetAdminSection(bstrAspNetCoreSection,
|
||||
applicationConfigPath,
|
||||
&pAspNetCoreElement));
|
||||
|
||||
CComBSTR struProcessPath;
|
||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_EXE_PATH,
|
||||
&struProcessPath));
|
||||
m_strProcessPath = struProcessPath;
|
||||
|
||||
// Swallow this error for backward compatibility
|
||||
// Use default behavior for empty string
|
||||
GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_HOSTING_MODEL,
|
||||
&strHostingModel);
|
||||
|
||||
if (strHostingModel.IsEmpty() || strHostingModel.Equals(L"outofprocess", TRUE))
|
||||
{
|
||||
m_hostingModel = HOSTING_OUT_PROCESS;
|
||||
}
|
||||
else if (strHostingModel.Equals(L"inprocess", TRUE))
|
||||
{
|
||||
m_hostingModel = HOSTING_IN_PROCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// block unknown hosting value
|
||||
EventLog::Error(
|
||||
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR,
|
||||
ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG,
|
||||
strHostingModel.QueryStr());
|
||||
RETURN_HR(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
CComBSTR struArguments;
|
||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_PROCESS_ARGUMENTS,
|
||||
&struArguments));
|
||||
|
||||
m_strArguments = struArguments;
|
||||
|
||||
if (m_hostingModel == HOSTING_OUT_PROCESS)
|
||||
{
|
||||
STRU struHandlerVersion;
|
||||
RETURN_IF_FAILED(ConfigUtility::FindHandlerVersion(pAspNetCoreElement, struHandlerVersion));
|
||||
m_strHandlerVersion = struHandlerVersion.QueryStr();
|
||||
}
|
||||
|
||||
|
||||
RETURN_IF_FAILED(GetElementBoolProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_ENABLED,
|
||||
&m_fStdoutLogEnabled));
|
||||
RETURN_IF_FAILED(GetElementStringProperty(pAspNetCoreElement,
|
||||
CS_ASPNETCORE_STDOUT_LOG_FILE,
|
||||
&m_struStdoutLogFile));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
#include <httpserv.h>
|
||||
|
||||
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
||||
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
||||
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
|
||||
|
||||
enum APP_HOSTING_MODEL
|
||||
{
|
||||
HOSTING_UNKNOWN = 0,
|
||||
HOSTING_IN_PROCESS,
|
||||
HOSTING_OUT_PROCESS
|
||||
};
|
||||
|
||||
class ASPNETCORE_SHIM_CONFIG
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
~ASPNETCORE_SHIM_CONFIG() = default;
|
||||
|
||||
HRESULT
|
||||
Populate(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpApplication *pHttpApplication
|
||||
);
|
||||
|
||||
std::wstring&
|
||||
QueryProcessPath()
|
||||
{
|
||||
return m_strProcessPath;
|
||||
}
|
||||
|
||||
std::wstring&
|
||||
QueryArguments()
|
||||
{
|
||||
return m_strArguments;
|
||||
}
|
||||
|
||||
APP_HOSTING_MODEL
|
||||
QueryHostingModel()
|
||||
{
|
||||
return m_hostingModel;
|
||||
}
|
||||
|
||||
std::wstring&
|
||||
QueryHandlerVersion()
|
||||
{
|
||||
return m_strHandlerVersion;
|
||||
}
|
||||
|
||||
BOOL
|
||||
QueryStdoutLogEnabled()
|
||||
{
|
||||
return m_fStdoutLogEnabled;
|
||||
}
|
||||
|
||||
STRU*
|
||||
QueryStdoutLogFile()
|
||||
{
|
||||
return &m_struStdoutLogFile;
|
||||
}
|
||||
|
||||
ASPNETCORE_SHIM_CONFIG() :
|
||||
m_hostingModel(HOSTING_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::wstring m_strArguments;
|
||||
std::wstring m_strProcessPath;
|
||||
APP_HOSTING_MODEL m_hostingModel;
|
||||
std::wstring m_strHandlerVersion;
|
||||
BOOL m_fStdoutLogEnabled;
|
||||
STRU m_struStdoutLogFile;
|
||||
};
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#define FileDescription "IIS AspNetCore Module V2. Commit: " CommitHash
|
||||
#define FileDescription "IIS ASP.NET Core Module V2. Commit: " CommitHash
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -195,6 +195,9 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="application.h" />
|
||||
<ClInclude Include="ConfigurationLoadException.h" />
|
||||
<ClInclude Include="ConfigurationSection.h" />
|
||||
<ClInclude Include="ConfigurationSource.h" />
|
||||
<ClInclude Include="config_utility.h" />
|
||||
<ClInclude Include="Environment.h" />
|
||||
<ClInclude Include="EventLog.h" />
|
||||
|
|
@ -211,6 +214,7 @@
|
|||
<ClInclude Include="IOutputManager.h" />
|
||||
<ClInclude Include="irequesthandler.h" />
|
||||
<ClInclude Include="LoggingHelpers.h" />
|
||||
<ClInclude Include="NonCopyable.h" />
|
||||
<ClInclude Include="NullOutputManager.h" />
|
||||
<ClInclude Include="PipeOutputManager.h" />
|
||||
<ClInclude Include="StdWrapper.h" />
|
||||
|
|
@ -221,8 +225,12 @@
|
|||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="StringHelpers.h" />
|
||||
<ClInclude Include="sttimer.h" />
|
||||
<ClInclude Include="WebConfigConfigurationSection.h" />
|
||||
<ClInclude Include="WebConfigConfigurationSource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ConfigurationSection.cpp" />
|
||||
<ClCompile Include="ConfigurationSource.cpp" />
|
||||
<ClCompile Include="debugutil.cpp" />
|
||||
<ClCompile Include="Environment.cpp" />
|
||||
<ClCompile Include="EventLog.cpp" />
|
||||
|
|
@ -245,6 +253,8 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StringHelpers.cpp" />
|
||||
<ClCompile Include="WebConfigConfigurationSection.cpp" />
|
||||
<ClCompile Include="WebConfigConfigurationSource.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IISLib\IISLib.vcxproj">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
// 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 <string>
|
||||
|
||||
class ConfigurationLoadException: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
ConfigurationLoadException(std::wstring msg)
|
||||
: runtime_error("Configuration load exception has occured"), message(std::move(msg))
|
||||
{
|
||||
}
|
||||
|
||||
std::wstring get_message() const { return message; }
|
||||
|
||||
private:
|
||||
std::wstring message;
|
||||
};
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "ConfigurationSection.h"
|
||||
|
||||
#include "StringHelpers.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
|
||||
std::wstring ConfigurationSection::GetRequiredString(const std::wstring& name) const
|
||||
{
|
||||
auto result = GetString(name);
|
||||
if (!result.has_value() || result.value().empty())
|
||||
{
|
||||
ThrowRequiredException(name);
|
||||
}
|
||||
return result.value();
|
||||
}
|
||||
|
||||
bool ConfigurationSection::GetRequiredBool(const std::wstring& name) const
|
||||
{
|
||||
auto result = GetBool(name);
|
||||
if (!result.has_value())
|
||||
{
|
||||
ThrowRequiredException(name);
|
||||
}
|
||||
return result.value();
|
||||
}
|
||||
|
||||
DWORD ConfigurationSection::GetRequiredTimespan(const std::wstring& name) const
|
||||
{
|
||||
auto result = GetTimespan(name);
|
||||
if (!result.has_value())
|
||||
{
|
||||
ThrowRequiredException(name);
|
||||
}
|
||||
return result.value();
|
||||
}
|
||||
|
||||
void ConfigurationSection::ThrowRequiredException(const std::wstring& name)
|
||||
{
|
||||
throw ConfigurationLoadException(format(L"Attribute '%s' is required.", name.c_str()));
|
||||
}
|
||||
|
||||
std::optional<std::wstring> find_element(const std::vector<std::pair<std::wstring, std::wstring>>& pairs, const std::wstring& name)
|
||||
{
|
||||
const auto iter = std::find_if(
|
||||
pairs.begin(),
|
||||
pairs.end(),
|
||||
[&](const std::pair<std::wstring, std::wstring>& pair) { return equals_ignore_case(pair.first, name); });
|
||||
|
||||
if (iter == pairs.end())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional(iter->second);
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// 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 <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "NonCopyable.h"
|
||||
|
||||
#define CS_ASPNETCORE_COLLECTION_ITEM_NAME L"name"
|
||||
#define CS_ASPNETCORE_COLLECTION_ITEM_VALUE L"value"
|
||||
#define CS_ASPNETCORE_ENVIRONMENT_VARIABLES L"environmentVariables"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_FILE L"stdoutLogFile"
|
||||
#define CS_ASPNETCORE_STDOUT_LOG_ENABLED L"stdoutLogEnabled"
|
||||
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
|
||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS L"arguments"
|
||||
#define CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT L""
|
||||
#define CS_ASPNETCORE_HOSTING_MODEL_OUTOFPROCESS L"outofprocess"
|
||||
#define CS_ASPNETCORE_HOSTING_MODEL_INPROCESS L"inprocess"
|
||||
#define CS_ASPNETCORE_HOSTING_MODEL L"hostingModel"
|
||||
#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
|
||||
#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
|
||||
#define CS_ENABLED L"enabled"
|
||||
|
||||
class ConfigurationSection: NonCopyable
|
||||
{
|
||||
public:
|
||||
ConfigurationSection() = default;
|
||||
virtual ~ConfigurationSection() = default;
|
||||
virtual std::optional<std::wstring> GetString(const std::wstring& name) const = 0;
|
||||
virtual std::optional<bool> GetBool(const std::wstring& name) const = 0;
|
||||
virtual std::optional<DWORD> GetTimespan(const std::wstring& name) const = 0;
|
||||
|
||||
std::wstring GetRequiredString(const std::wstring& name) const;
|
||||
bool GetRequiredBool(const std::wstring& name) const;
|
||||
DWORD GetRequiredTimespan(const std::wstring& name) const;
|
||||
|
||||
virtual std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const = 0;
|
||||
|
||||
protected:
|
||||
static void ThrowRequiredException(const std::wstring& name);
|
||||
};
|
||||
|
||||
std::optional<std::wstring> find_element(const std::vector<std::pair<std::wstring, std::wstring>>& pairs, const std::wstring& name);
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "ConfigurationSource.h"
|
||||
|
||||
#include "StringHelpers.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
|
||||
std::shared_ptr<ConfigurationSection> ConfigurationSource::GetRequiredSection(const std::wstring& name) const
|
||||
{
|
||||
auto section = GetSection(name);
|
||||
if (!section)
|
||||
{
|
||||
throw ConfigurationLoadException(format(L"Unable to get required configuration section '%s'. Possible reason is web.config authoring error.", name.c_str()));
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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 <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "NonCopyable.h"
|
||||
#include "ConfigurationSection.h"
|
||||
|
||||
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
|
||||
#define CS_WINDOWS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/windowsAuthentication"
|
||||
#define CS_BASIC_AUTHENTICATION_SECTION L"system.webServer/security/authentication/basicAuthentication"
|
||||
#define CS_ANONYMOUS_AUTHENTICATION_SECTION L"system.webServer/security/authentication/anonymousAuthentication"
|
||||
|
||||
class ConfigurationSource: NonCopyable
|
||||
{
|
||||
public:
|
||||
ConfigurationSource() = default;
|
||||
virtual ~ConfigurationSource() = default;
|
||||
virtual std::shared_ptr<ConfigurationSection> GetSection(const std::wstring& name) const = 0;
|
||||
std::shared_ptr<ConfigurationSection> GetRequiredSection(const std::wstring& name) const;
|
||||
};
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include <array>
|
||||
#include "EventLog.h"
|
||||
#include "debugutil.h"
|
||||
#include "StringHelpers.h"
|
||||
|
||||
extern HANDLE g_hEventLog;
|
||||
|
||||
|
|
@ -13,6 +15,19 @@ EventLog::LogEvent(
|
|||
_In_ LPCWSTR pstrMsg
|
||||
)
|
||||
{
|
||||
// Static locals to avoid getting the process ID and string multiple times.
|
||||
// Effectively have the same semantics as global variables, except initialized
|
||||
// on first occurence.
|
||||
static const auto processIdString = GetProcessIdString();
|
||||
static const auto versionInfoString = GetVersionInfoString();
|
||||
|
||||
std::array<LPCWSTR, 3> eventLogDataStrings
|
||||
{
|
||||
pstrMsg,
|
||||
processIdString.c_str(),
|
||||
versionInfoString.c_str()
|
||||
};
|
||||
|
||||
if (g_hEventLog != NULL)
|
||||
{
|
||||
ReportEventW(g_hEventLog,
|
||||
|
|
@ -20,9 +35,9 @@ EventLog::LogEvent(
|
|||
0, // wCategory
|
||||
dwEventId,
|
||||
NULL, // lpUserSid
|
||||
1, // wNumStrings
|
||||
3, // wNumStrings
|
||||
0, // dwDataSize,
|
||||
&pstrMsg,
|
||||
eventLogDataStrings.data(),
|
||||
NULL // lpRawData
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
class NonCopyable {
|
||||
public:
|
||||
NonCopyable() = default;
|
||||
NonCopyable(const NonCopyable&) = default;
|
||||
NonCopyable& operator=(const NonCopyable&) = default;
|
||||
};
|
||||
|
|
@ -13,3 +13,8 @@ bool ends_with(const std::wstring &source, const std::wstring &suffix, bool igno
|
|||
const auto offset = source.length() - suffix.length();
|
||||
return CSTR_EQUAL == CompareStringOrdinal(source.c_str() + offset, static_cast<int>(suffix.length()), suffix.c_str(), static_cast<int>(suffix.length()), ignoreCase);
|
||||
}
|
||||
|
||||
bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2)
|
||||
{
|
||||
return CSTR_EQUAL == CompareStringOrdinal(s1.c_str(), static_cast<int>(s1.length()), s2.c_str(), static_cast<int>(s2.length()), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
[[nodiscard]]
|
||||
bool ends_with(const std::wstring &source, const std::wstring &suffix, bool ignoreCase = false);
|
||||
|
||||
[[nodiscard]]
|
||||
bool equals_ignore_case(const std::wstring& s1, const std::wstring& s2);
|
||||
|
||||
template<typename ... Args>
|
||||
[[nodiscard]]
|
||||
std::wstring format(const std::wstring& format, Args ... args)
|
||||
|
|
@ -18,3 +21,13 @@ std::wstring format(const std::wstring& format, Args ... args)
|
|||
return std::wstring(formattedBuffer.get(), formattedBuffer.get() + size - 1);
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
[[nodiscard]]
|
||||
std::string format(const std::string& format, Args ... args)
|
||||
{
|
||||
const size_t size = snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra char for '\0'
|
||||
std::unique_ptr<char[]> formattedBuffer(new char[size]);
|
||||
snprintf(formattedBuffer.get(), size, format.c_str(), args ... );
|
||||
return std::string(formattedBuffer.get(), formattedBuffer.get() + size - 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "WebConfigConfigurationSection.h"
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "ahutil.h"
|
||||
|
||||
std::optional<std::wstring> WebConfigConfigurationSection::GetString(const std::wstring& name) const
|
||||
{
|
||||
CComBSTR result;
|
||||
if (FAILED_LOG(GetElementStringProperty(m_element, name.c_str(), &result.m_str)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional(std::wstring(result));
|
||||
}
|
||||
|
||||
std::optional<bool> WebConfigConfigurationSection::GetBool(const std::wstring& name) const
|
||||
{
|
||||
bool result;
|
||||
if (FAILED_LOG(GetElementBoolProperty(m_element, name.c_str(), &result)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional(result);
|
||||
}
|
||||
|
||||
std::optional<DWORD> WebConfigConfigurationSection::GetTimespan(const std::wstring& name) const
|
||||
{
|
||||
ULONGLONG result;
|
||||
if (FAILED_LOG(GetElementRawTimeSpanProperty(m_element, name.c_str(), &result)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::make_optional(static_cast<DWORD>(result / 10000ull));
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::wstring, std::wstring>> WebConfigConfigurationSection::GetKeyValuePairs(const std::wstring& name) const
|
||||
{
|
||||
std::vector<std::pair<std::wstring, std::wstring>> pairs;
|
||||
HRESULT findElementResult;
|
||||
CComPtr<IAppHostElement> element = nullptr;
|
||||
CComPtr<IAppHostElementCollection> elementCollection = nullptr;
|
||||
CComPtr<IAppHostElement> collectionEntry = nullptr;
|
||||
ENUM_INDEX index{};
|
||||
|
||||
if (FAILED_LOG(GetElementChildByName(m_element, name.c_str(), &element)))
|
||||
{
|
||||
return pairs;
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(element->get_Collection(&elementCollection));
|
||||
THROW_IF_FAILED(findElementResult = FindFirstElement(elementCollection, &index, &collectionEntry));
|
||||
|
||||
while (findElementResult != S_FALSE)
|
||||
{
|
||||
CComBSTR strHandlerName;
|
||||
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_NAME, &strHandlerName.m_str)))
|
||||
{
|
||||
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_NAME);
|
||||
}
|
||||
|
||||
CComBSTR strHandlerValue;
|
||||
if (LOG_IF_FAILED(GetElementStringProperty(collectionEntry, CS_ASPNETCORE_COLLECTION_ITEM_VALUE, &strHandlerValue.m_str)))
|
||||
{
|
||||
ThrowRequiredException(CS_ASPNETCORE_COLLECTION_ITEM_VALUE);
|
||||
}
|
||||
|
||||
pairs.emplace_back(strHandlerName, strHandlerValue);
|
||||
|
||||
collectionEntry.Release();
|
||||
|
||||
THROW_IF_FAILED(findElementResult = FindNextElement(elementCollection, &index, &collectionEntry));
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// 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 <atlcomcli.h>
|
||||
#include <optional>
|
||||
#include "ConfigurationSection.h"
|
||||
|
||||
class WebConfigConfigurationSection: public ConfigurationSection
|
||||
{
|
||||
public:
|
||||
WebConfigConfigurationSection(IAppHostElement* pElement)
|
||||
: m_element(pElement)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<std::wstring> GetString(const std::wstring& name) const override;
|
||||
std::optional<bool> GetBool(const std::wstring& name) const override;
|
||||
std::optional<DWORD> GetTimespan(const std::wstring& name) const override;
|
||||
std::vector<std::pair<std::wstring, std::wstring>> GetKeyValuePairs(const std::wstring& name) const override;
|
||||
|
||||
private:
|
||||
CComPtr<IAppHostElement> m_element;
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "WebConfigConfigurationSource.h"
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "WebConfigConfigurationSection.h"
|
||||
|
||||
std::shared_ptr<ConfigurationSection> WebConfigConfigurationSource::GetSection(const std::wstring& name) const
|
||||
{
|
||||
const CComBSTR bstrAspNetCoreSection = name.c_str();
|
||||
const CComBSTR applicationConfigPath = m_application.GetAppConfigPath();
|
||||
|
||||
IAppHostElement* sectionElement;
|
||||
if (LOG_IF_FAILED(m_manager->GetAdminSection(bstrAspNetCoreSection, applicationConfigPath, §ionElement)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<WebConfigConfigurationSection>(sectionElement);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// 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 <atlcomcli.h>
|
||||
#include "ConfigurationSection.h"
|
||||
#include "ConfigurationSource.h"
|
||||
|
||||
class WebConfigConfigurationSource: public ConfigurationSource
|
||||
{
|
||||
public:
|
||||
WebConfigConfigurationSource(IAppHostAdminManager *pAdminManager, IHttpApplication &pHttpApplication)
|
||||
: m_manager(pAdminManager),
|
||||
m_application(pHttpApplication)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<ConfigurationSection> GetSection(const std::wstring& name) const override;
|
||||
|
||||
private:
|
||||
CComPtr<IAppHostAdminManager> m_manager;
|
||||
IHttpApplication &m_application;
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "iapplication.h"
|
||||
#include "ntassert.h"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
|
@ -20,11 +21,15 @@ public:
|
|||
return m_fStopCalled ? APPLICATION_STATUS::RECYCLED : APPLICATION_STATUS::RUNNING;
|
||||
}
|
||||
|
||||
APPLICATION()
|
||||
APPLICATION(const IHttpApplication& pHttpApplication)
|
||||
: m_fStopCalled(false),
|
||||
m_cRefs(1)
|
||||
m_cRefs(1),
|
||||
m_applicationPhysicalPath(pHttpApplication.GetApplicationPhysicalPath()),
|
||||
m_applicationConfigPath(pHttpApplication.GetAppConfigPath()),
|
||||
m_applicationId(pHttpApplication.GetApplicationId())
|
||||
{
|
||||
InitializeSRWLock(&m_stateLock);
|
||||
m_applicationVirtualPath = ToVirtualPath(m_applicationConfigPath);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -69,10 +74,58 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryApplicationId() const
|
||||
{
|
||||
return m_applicationId;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryApplicationPhysicalPath() const
|
||||
{
|
||||
return m_applicationPhysicalPath;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryApplicationVirtualPath() const
|
||||
{
|
||||
return m_applicationVirtualPath;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryConfigPath() const
|
||||
{
|
||||
return m_applicationConfigPath;
|
||||
}
|
||||
|
||||
protected:
|
||||
SRWLOCK m_stateLock;
|
||||
SRWLOCK m_stateLock {};
|
||||
bool m_fStopCalled;
|
||||
|
||||
private:
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
std::wstring m_applicationPhysicalPath;
|
||||
std::wstring m_applicationVirtualPath;
|
||||
std::wstring m_applicationConfigPath;
|
||||
std::wstring m_applicationId;
|
||||
|
||||
static std::wstring ToVirtualPath(const std::wstring& configurationPath)
|
||||
{
|
||||
auto segments = 0;
|
||||
auto position = configurationPath.find('/');
|
||||
// Skip first 4 segments of config path
|
||||
while (segments != 3 && position != std::wstring::npos)
|
||||
{
|
||||
segments++;
|
||||
position = configurationPath.find('/', position + 1);
|
||||
}
|
||||
|
||||
if (position != std::wstring::npos)
|
||||
{
|
||||
return configurationPath.substr(position);
|
||||
}
|
||||
|
||||
return L"/";
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ Language=English
|
|||
.
|
||||
|
||||
Messageid=1034
|
||||
SymbolicName=ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR
|
||||
SymbolicName=ASPNETCORE_CONFIGURATION_LOAD_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "exceptions.h"
|
||||
#include "atlbase.h"
|
||||
#include "config_utility.h"
|
||||
#include "StringHelpers.h"
|
||||
|
||||
inline HANDLE g_logFile = INVALID_HANDLE_VALUE;
|
||||
inline HMODULE g_hModule;
|
||||
|
|
@ -21,43 +22,72 @@ inline SRWLOCK g_logFileLock;
|
|||
HRESULT
|
||||
PrintDebugHeader()
|
||||
{
|
||||
DWORD verHandle = 0;
|
||||
UINT size = 0;
|
||||
LPVOID lpBuffer = NULL;
|
||||
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "Initializing logs for %S. %S. %S.",
|
||||
GetModuleName().c_str(),
|
||||
GetProcessIdString().c_str(),
|
||||
GetVersionInfoString().c_str()
|
||||
);
|
||||
|
||||
WCHAR path[MAX_PATH];
|
||||
RETURN_LAST_ERROR_IF(!GetModuleFileName(g_hModule, path, sizeof(path)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
DWORD verSize = GetFileVersionInfoSize(path, &verHandle);
|
||||
RETURN_LAST_ERROR_IF(verSize == 0);
|
||||
std::wstring
|
||||
GetProcessIdString()
|
||||
{
|
||||
return format(L"Process Id: %u.", GetCurrentProcessId());
|
||||
}
|
||||
|
||||
// Allocate memory to hold data structure returned by GetFileVersionInfo
|
||||
std::vector<BYTE> verData(verSize);
|
||||
|
||||
RETURN_LAST_ERROR_IF(!GetFileVersionInfo(path, verHandle, verSize, verData.data()));
|
||||
RETURN_LAST_ERROR_IF(!VerQueryValue(verData.data(), L"\\", &lpBuffer, &size));
|
||||
|
||||
auto verInfo = reinterpret_cast<VS_FIXEDFILEINFO *>(lpBuffer);
|
||||
// Check result signature
|
||||
if (verInfo->dwSignature == VS_FFI_SIGNATURE)
|
||||
std::wstring
|
||||
GetVersionInfoString()
|
||||
{
|
||||
auto func = [](std::wstring& res)
|
||||
{
|
||||
DWORD verHandle = 0;
|
||||
UINT size = 0;
|
||||
LPVOID lpBuffer = NULL;
|
||||
|
||||
auto path = GetModuleName();
|
||||
|
||||
DWORD verSize = GetFileVersionInfoSize(path.c_str(), &verHandle);
|
||||
RETURN_LAST_ERROR_IF(verSize == 0);
|
||||
|
||||
// Allocate memory to hold data structure returned by GetFileVersionInfo
|
||||
std::vector<BYTE> verData(verSize);
|
||||
|
||||
RETURN_LAST_ERROR_IF(!GetFileVersionInfo(path.c_str(), verHandle, verSize, verData.data()));
|
||||
RETURN_LAST_ERROR_IF(!VerQueryValue(verData.data(), L"\\", &lpBuffer, &size));
|
||||
|
||||
auto verInfo = reinterpret_cast<VS_FIXEDFILEINFO *>(lpBuffer);
|
||||
if (verInfo->dwSignature != VS_FFI_SIGNATURE)
|
||||
{
|
||||
RETURN_IF_FAILED(E_FAIL);
|
||||
}
|
||||
|
||||
LPVOID pvProductName = NULL;
|
||||
unsigned int iProductNameLen = 0;
|
||||
RETURN_LAST_ERROR_IF(!VerQueryValue(verData.data(), _T("\\StringFileInfo\\040904b0\\FileDescription"), &pvProductName, &iProductNameLen));
|
||||
|
||||
// Major, minor are stored in dwFileVersionMS field and patch, build in dwFileVersionLS field as pair of 32 bit numbers
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_INFO, "Initializing logs for %S. ProcessId: %d. File Version: %d.%d.%d.%d. Description: %S",
|
||||
path,
|
||||
GetCurrentProcessId(),
|
||||
( verInfo->dwFileVersionMS >> 16 ) & 0xffff,
|
||||
( verInfo->dwFileVersionMS >> 0 ) & 0xffff,
|
||||
( verInfo->dwFileVersionLS >> 16 ) & 0xffff,
|
||||
( verInfo->dwFileVersionLS >> 0 ) & 0xffff,
|
||||
pvProductName
|
||||
);
|
||||
}
|
||||
res = format(L"File Version: %d.%d.%d.%d. Description: %s",
|
||||
(verInfo->dwFileVersionMS >> 16) & 0xffff,
|
||||
(verInfo->dwFileVersionMS >> 0) & 0xffff,
|
||||
(verInfo->dwFileVersionLS >> 16) & 0xffff,
|
||||
(verInfo->dwFileVersionLS >> 0) & 0xffff,
|
||||
pvProductName);
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
return S_OK;
|
||||
std::wstring versionInfoString;
|
||||
|
||||
return func(versionInfoString) == S_OK ? versionInfoString : L"";
|
||||
}
|
||||
|
||||
std::wstring
|
||||
GetModuleName()
|
||||
{
|
||||
WCHAR path[MAX_PATH];
|
||||
LOG_LAST_ERROR_IF(GetModuleFileName(g_hModule, path, sizeof(path)));
|
||||
return path;
|
||||
}
|
||||
|
||||
void SetDebugFlags(const std::wstring &debugValue)
|
||||
|
|
|
|||
|
|
@ -49,3 +49,12 @@ DebugPrintf(
|
|||
LPCSTR szFormat,
|
||||
...
|
||||
);
|
||||
|
||||
std::wstring
|
||||
GetProcessIdString();
|
||||
|
||||
std::wstring
|
||||
GetVersionInfoString();
|
||||
|
||||
std::wstring
|
||||
GetModuleName();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <system_error>
|
||||
|
||||
#include "debugutil.h"
|
||||
#include "StringHelpers.h"
|
||||
|
||||
#define LOCATION_INFO_ENABLED TRUE
|
||||
|
||||
|
|
@ -26,10 +27,11 @@
|
|||
#endif
|
||||
|
||||
#define OBSERVE_CAUGHT_EXCEPTION() CaughtExceptionHResult(LOCATION_INFO);
|
||||
#define RETURN_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
|
||||
|
||||
#define RETURN_HR(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); } return __hrRet; } while (0, 0)
|
||||
#define RETURN_LAST_ERROR() do { return LogLastError(LOCATION_INFO); } while (0, 0)
|
||||
#define RETURN_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { LogHResultFailed(LOCATION_INFO, __hrRet); return __hrRet; }} while (0, 0)
|
||||
#define RETURN_CAUGHT_EXCEPTION() return CaughtExceptionHResult(LOCATION_INFO);
|
||||
#define RETURN_LAST_ERROR_IF(condition) do { if (condition) { return LogLastError(LOCATION_INFO); }} while (0, 0)
|
||||
#define RETURN_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { return LogLastError(LOCATION_INFO); }} while (0, 0)
|
||||
|
||||
|
|
@ -39,6 +41,11 @@
|
|||
#define FINISHED_LAST_ERROR_IF(condition) do { if (condition) { hr = LogLastError(LOCATION_INFO); goto Finished; }} while (0, 0)
|
||||
#define FINISHED_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { hr = LogLastError(LOCATION_INFO); goto Finished; }} while (0, 0)
|
||||
|
||||
#define THROW_LAST_ERROR() do { ThrowResultException(LogLastError(LOCATION_INFO)); } while (0, 0)
|
||||
#define THROW_IF_FAILED(hr) do { HRESULT __hrRet = hr; if (FAILED(__hrRet)) { ThrowResultException(LOCATION_INFO, __hrRet); }} while (0, 0)
|
||||
#define THROW_LAST_ERROR_IF(condition) do { if (condition) { ThrowResultException(LogLastError(LOCATION_INFO)); }} while (0, 0)
|
||||
#define THROW_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { ThrowResultException(LogLastError(LOCATION_INFO)); }} while (0, 0)
|
||||
|
||||
#define THROW_IF_NULL_ALLOC(ptr) Throw_IfNullAlloc(ptr)
|
||||
|
||||
#define CATCH_RETURN() catch (...) { RETURN_CAUGHT_EXCEPTION(); }
|
||||
|
|
@ -48,6 +55,22 @@
|
|||
#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr))
|
||||
#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr))
|
||||
|
||||
|
||||
class ResultException: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit ResultException(HRESULT hr, LOCATION_ARGUMENTS_ONLY) :
|
||||
runtime_error(format("HRESULT 0x%x returned at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY)),
|
||||
m_hr(hr)
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT GetResult() const { return m_hr; }
|
||||
|
||||
private:
|
||||
HRESULT m_hr;
|
||||
};
|
||||
|
||||
__declspec(noinline) inline VOID ReportUntypedException(LOCATION_ARGUMENTS_ONLY)
|
||||
{
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, LOCATION_FORMAT "Unhandled non-standard exception", LOCATION_CALL_ONLY);
|
||||
|
|
@ -75,7 +98,7 @@
|
|||
|
||||
__declspec(noinline) inline VOID ReportException(LOCATION_ARGUMENTS std::exception& exception)
|
||||
{
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Exception : %s caught at" LOCATION_FORMAT, exception.what(), LOCATION_CALL_ONLY);
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Exception '%s' caught at " LOCATION_FORMAT, exception.what(), LOCATION_CALL_ONLY);
|
||||
}
|
||||
|
||||
__declspec(noinline) inline HRESULT LogHResultFailed(LOCATION_ARGUMENTS HRESULT hr)
|
||||
|
|
@ -97,10 +120,10 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
|
|||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch (std::system_error& exception)
|
||||
catch (ResultException& exception)
|
||||
{
|
||||
ReportException(LOCATION_CALL exception);
|
||||
return exception.code().value();
|
||||
return exception.GetResult();
|
||||
}
|
||||
catch (std::exception& exception)
|
||||
{
|
||||
|
|
@ -114,6 +137,13 @@ __declspec(noinline) inline HRESULT CaughtExceptionHResult(LOCATION_ARGUMENTS_ON
|
|||
}
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
__declspec(noinline) inline void ThrowResultException(LOCATION_ARGUMENTS HRESULT hr)
|
||||
{
|
||||
DebugPrintf(ASPNETCORE_DEBUG_FLAG_ERROR, "Throwing ResultException for HRESULT 0x%x at " LOCATION_FORMAT, hr, LOCATION_CALL_ONLY);
|
||||
throw ResultException(hr, LOCATION_CALL_ONLY);
|
||||
}
|
||||
|
||||
template <typename PointerT> auto Throw_IfNullAlloc(PointerT pointer)
|
||||
{
|
||||
if (pointer == nullptr)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ HOSTFXR_UTILITY::ParseHostfxrArguments(
|
|||
auto pwzArgs = std::unique_ptr<LPWSTR[], LocalFreeDeleter>(CommandLineToArgvW(applicationArguments.c_str(), &argc));
|
||||
if (!pwzArgs)
|
||||
{
|
||||
throw StartupParametersResolutionException(format(L"Unable parse command line argumens '%s' or '%s'", applicationArguments.c_str()));
|
||||
throw StartupParametersResolutionException(format(L"Unable parse command line arguments '%s' or '%s'", applicationArguments.c_str()));
|
||||
}
|
||||
|
||||
for (int intArgsProcessed = 0; intArgsProcessed < argc; intArgsProcessed++)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#define ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG L"Application '%s' has shutdown."
|
||||
#define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool."
|
||||
#define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)."
|
||||
#define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file."
|
||||
#define ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG L"Configuration load error. %s"
|
||||
#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'."
|
||||
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
|
||||
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x'. Please check the stderr logs for more information."
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
#include "stringu.h"
|
||||
#include<Windows.h>
|
||||
|
||||
HRESULT
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "InProcessOptions.h"
|
||||
|
||||
InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSource) :
|
||||
m_fStdoutLogEnabled(false),
|
||||
m_fWindowsAuthEnabled(false),
|
||||
m_fBasicAuthEnabled(false),
|
||||
m_fAnonymousAuthEnabled(false),
|
||||
m_dwStartupTimeLimitInMS(INFINITE),
|
||||
m_dwShutdownTimeLimitInMS(INFINITE)
|
||||
{
|
||||
auto const aspNetCoreSection = configurationSource.GetRequiredSection(CS_ASPNETCORE_SECTION);
|
||||
m_strArguments = aspNetCoreSection->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT);
|
||||
m_strProcessPath = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH);
|
||||
m_fStdoutLogEnabled = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
|
||||
m_struStdoutLogFile = aspNetCoreSection->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE);
|
||||
m_fDisableStartUpErrorPage = aspNetCoreSection->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE);
|
||||
m_environmentVariables = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_ENVIRONMENT_VARIABLES);
|
||||
|
||||
const auto basicAuthSection = configurationSource.GetSection(CS_BASIC_AUTHENTICATION_SECTION);
|
||||
m_fBasicAuthEnabled = basicAuthSection && basicAuthSection->GetBool(CS_ENABLED).value_or(false);
|
||||
|
||||
const auto windowsAuthSection = configurationSource.GetSection(CS_WINDOWS_AUTHENTICATION_SECTION);
|
||||
m_fWindowsAuthEnabled = windowsAuthSection && windowsAuthSection->GetBool(CS_ENABLED).value_or(false);
|
||||
|
||||
const auto anonAuthSection = configurationSource.GetSection(CS_ANONYMOUS_AUTHENTICATION_SECTION);
|
||||
m_fAnonymousAuthEnabled = anonAuthSection && anonAuthSection->GetBool(CS_ENABLED).value_or(false);
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// 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 <string>
|
||||
#include "ConfigurationSource.h"
|
||||
|
||||
class InProcessOptions: NonCopyable
|
||||
{
|
||||
public:
|
||||
const std::wstring&
|
||||
QueryProcessPath() const
|
||||
{
|
||||
return m_strProcessPath;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryArguments() const
|
||||
{
|
||||
return m_strArguments;
|
||||
}
|
||||
|
||||
bool
|
||||
QueryStdoutLogEnabled() const
|
||||
{
|
||||
return m_fStdoutLogEnabled;
|
||||
}
|
||||
|
||||
const std::wstring&
|
||||
QueryStdoutLogFile() const
|
||||
{
|
||||
return m_struStdoutLogFile;
|
||||
}
|
||||
|
||||
bool
|
||||
QueryDisableStartUpErrorPage() const
|
||||
{
|
||||
return m_fDisableStartUpErrorPage;
|
||||
}
|
||||
|
||||
bool
|
||||
QueryWindowsAuthEnabled() const
|
||||
{
|
||||
return m_fWindowsAuthEnabled;
|
||||
}
|
||||
|
||||
bool
|
||||
QueryBasicAuthEnabled() const
|
||||
{
|
||||
return m_fBasicAuthEnabled;
|
||||
}
|
||||
|
||||
bool
|
||||
QueryAnonymousAuthEnabled() const
|
||||
{
|
||||
return m_fAnonymousAuthEnabled;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryStartupTimeLimitInMS() const
|
||||
{
|
||||
return m_dwStartupTimeLimitInMS;
|
||||
}
|
||||
|
||||
DWORD
|
||||
QueryShutdownTimeLimitInMS() const
|
||||
{
|
||||
return m_dwShutdownTimeLimitInMS;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::wstring, std::wstring>>&
|
||||
QueryEnvironmentVariables() const
|
||||
{
|
||||
return m_environmentVariables;
|
||||
}
|
||||
|
||||
InProcessOptions(const ConfigurationSource &configurationSource);
|
||||
|
||||
private:
|
||||
std::wstring m_strArguments;
|
||||
std::wstring m_strProcessPath;
|
||||
std::wstring m_struStdoutLogFile;
|
||||
bool m_fStdoutLogEnabled;
|
||||
bool m_fDisableStartUpErrorPage;
|
||||
bool m_fWindowsAuthEnabled;
|
||||
bool m_fBasicAuthEnabled;
|
||||
bool m_fAnonymousAuthEnabled;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
std::vector<std::pair<std::wstring, std::wstring>> m_environmentVariables;
|
||||
|
||||
protected:
|
||||
InProcessOptions() = default;
|
||||
};
|
||||
|
|
@ -228,6 +228,7 @@
|
|||
<ClInclude Include="inprocessapplication.h" />
|
||||
<ClInclude Include="InProcessApplicationBase.h" />
|
||||
<ClInclude Include="inprocesshandler.h" />
|
||||
<ClInclude Include="InProcessOptions.h" />
|
||||
<ClInclude Include="ShuttingDownApplication.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="StartupExceptionApplication.h" />
|
||||
|
|
@ -238,6 +239,7 @@
|
|||
<ClCompile Include="inprocessapplication.cpp" />
|
||||
<ClCompile Include="InProcessApplicationBase.cpp" />
|
||||
<ClCompile Include="inprocesshandler.cpp" />
|
||||
<ClCompile Include="InProcessOptions.cpp" />
|
||||
<ClCompile Include="managedexports.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
#include "resources.h"
|
||||
#include "exceptions.h"
|
||||
#include "ShuttingDownApplication.h"
|
||||
#include "InProcessOptions.h"
|
||||
#include "EventLog.h"
|
||||
#include "WebConfigConfigurationSource.h"
|
||||
#include "ConfigurationLoadException.h"
|
||||
|
||||
DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2_inprocess.dll");
|
||||
|
||||
|
|
@ -106,13 +110,12 @@ CreateApplication(
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||
const WebConfigConfigurationSource configurationSource(pServer->GetAdminManager(), *pHttpApplication);
|
||||
auto pConfig = std::make_unique<InProcessOptions>(configurationSource);
|
||||
|
||||
BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
|
||||
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(*pServer, *pHttpApplication, std::move(pRequestHandlerConfig), pParameters, nParameters);
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(*pServer, *pHttpApplication, std::move(pConfig), pParameters, nParameters);
|
||||
|
||||
// never create two inprocess applications in one process
|
||||
g_fInProcessApplicationCreated = true;
|
||||
|
|
@ -130,6 +133,15 @@ CreateApplication(
|
|||
*ppApplication = pApplication.release();
|
||||
}
|
||||
}
|
||||
catch(ConfigurationLoadException &ex)
|
||||
{
|
||||
EventLog::Error(
|
||||
ASPNETCORE_CONFIGURATION_LOAD_ERROR,
|
||||
ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG,
|
||||
ex.get_message().c_str());
|
||||
|
||||
RETURN_HR(E_FAIL);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
|
|||
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
std::unique_ptr<InProcessOptions> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters) :
|
||||
InProcessApplicationBase(pHttpServer, pApplication),
|
||||
|
|
@ -108,14 +108,14 @@ Finished:
|
|||
EventLog::Warn(
|
||||
ASPNETCORE_EVENT_GRACEFUL_SHUTDOWN_FAILURE,
|
||||
ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG,
|
||||
m_pConfig->QueryConfigPath()->QueryStr());
|
||||
QueryConfigPath().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
EventLog::Info(
|
||||
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL,
|
||||
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG,
|
||||
m_pConfig->QueryConfigPath()->QueryStr());
|
||||
QueryConfigPath().c_str());
|
||||
}
|
||||
|
||||
InProcessApplicationBase::StopInternal(fServerInitiated);
|
||||
|
|
@ -212,7 +212,7 @@ IN_PROCESS_APPLICATION::SetCallbackHandles(
|
|||
EventLog::Info(
|
||||
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS,
|
||||
ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG,
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr());
|
||||
QueryApplicationPhysicalPath().c_str());
|
||||
SetEvent(m_pInitalizeEvent);
|
||||
m_fInitialized = TRUE;
|
||||
}
|
||||
|
|
@ -334,8 +334,8 @@ Finished:
|
|||
EventLog::Error(
|
||||
ASPNETCORE_EVENT_LOAD_CLR_FALIURE,
|
||||
ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG,
|
||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
QueryApplicationId().c_str(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
hr);
|
||||
}
|
||||
DereferenceApplication();
|
||||
|
|
@ -365,11 +365,21 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
|
|||
VOID
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
auto variables = m_pConfig->QueryEnvironmentVariables();
|
||||
auto inputTable = std::unique_ptr<ENVIRONMENT_VAR_HASH, ENVIRONMENT_VAR_HASH_DELETER>(new ENVIRONMENT_VAR_HASH());
|
||||
RETURN_IF_FAILED(inputTable->Initialize(37 /*prime*/));
|
||||
// Copy environment variables to old style hash table
|
||||
for (auto & variable : variables)
|
||||
{
|
||||
auto pNewEntry = std::unique_ptr<ENVIRONMENT_VAR_ENTRY, ENVIRONMENT_VAR_ENTRY_DELETER>(new ENVIRONMENT_VAR_ENTRY());
|
||||
RETURN_IF_FAILED(pNewEntry->Initialize((variable.first + L"=").c_str(), variable.second.c_str()));
|
||||
RETURN_IF_FAILED(inputTable->InsertRecord(pNewEntry.get()));
|
||||
}
|
||||
|
||||
ENVIRONMENT_VAR_HASH* pHashTable = NULL;
|
||||
std::unique_ptr<ENVIRONMENT_VAR_HASH, ENVIRONMENT_VAR_HASH_DELETER> table;
|
||||
RETURN_IF_FAILED(hr = ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
m_pConfig->QueryEnvironmentVariables(),
|
||||
RETURN_IF_FAILED(ENVIRONMENT_VAR_HELPERS::InitEnvironmentVariablesTable(
|
||||
inputTable.get(),
|
||||
m_pConfig->QueryWindowsAuthEnabled(),
|
||||
m_pConfig->QueryBasicAuthEnabled(),
|
||||
m_pConfig->QueryAnonymousAuthEnabled(),
|
||||
|
|
@ -377,11 +387,13 @@ IN_PROCESS_APPLICATION::SetEnvironementVariablesOnWorkerProcess(
|
|||
|
||||
table.reset(pHashTable);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
table->Apply(ENVIRONMENT_VAR_HELPERS::AppendEnvironmentVariables, &hr);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
table->Apply(ENVIRONMENT_VAR_HELPERS::SetEnvironmentVariables, &hr);
|
||||
RETURN_IF_FAILED(hr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -422,9 +434,9 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
|
|||
|
||||
FINISHED_IF_FAILED(hr = HOSTFXR_OPTIONS::Create(
|
||||
m_struExeLocation.QueryStr(),
|
||||
m_pConfig->QueryProcessPath()->QueryStr(),
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
m_pConfig->QueryArguments()->QueryStr(),
|
||||
m_pConfig->QueryProcessPath().c_str(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
m_pConfig->QueryArguments().c_str(),
|
||||
hostFxrOptions
|
||||
));
|
||||
hostFxrOptions->GetArguments(hostfxrArgc, hostfxrArgv);
|
||||
|
|
@ -438,8 +450,8 @@ IN_PROCESS_APPLICATION::ExecuteApplication(
|
|||
FINISHED_IF_FAILED(hr = LoggingHelpers::CreateLoggingProvider(
|
||||
m_pConfig->QueryStdoutLogEnabled(),
|
||||
!m_pHttpServer.IsCommandLineLaunch(),
|
||||
m_pConfig->QueryStdoutLogFile()->QueryStr(),
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
m_pConfig->QueryStdoutLogFile().c_str(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
m_pLoggerProvider));
|
||||
|
||||
LOG_IF_FAILED(m_pLoggerProvider->Start());
|
||||
|
|
@ -502,8 +514,8 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
|
|||
EventLog::Error(
|
||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT,
|
||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG,
|
||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
QueryApplicationId().c_str(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
hr,
|
||||
struStdMsg.QueryStr());
|
||||
}
|
||||
|
|
@ -513,8 +525,8 @@ IN_PROCESS_APPLICATION::LogErrorsOnMainExit(
|
|||
EventLog::Error(
|
||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT,
|
||||
ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG,
|
||||
m_pConfig->QueryApplicationPath()->QueryStr(),
|
||||
m_pConfig->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
QueryApplicationId().c_str(),
|
||||
QueryApplicationPhysicalPath().c_str(),
|
||||
hr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "IOutputManager.h"
|
||||
#include "InProcessOptions.h"
|
||||
|
||||
class IN_PROCESS_HANDLER;
|
||||
typedef REQUEST_NOTIFICATION_STATUS(WINAPI * PFN_REQUEST_HANDLER) (IN_PROCESS_HANDLER* pInProcessHandler, void* pvRequestHandlerContext);
|
||||
|
|
@ -18,7 +18,7 @@ public:
|
|||
IN_PROCESS_APPLICATION(
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
std::unique_ptr<InProcessOptions> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters);
|
||||
|
||||
|
|
@ -97,10 +97,10 @@ public:
|
|||
return m_struExeLocation.QueryStr();
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig()
|
||||
const InProcessOptions&
|
||||
QueryConfig() const
|
||||
{
|
||||
return m_pConfig.get();
|
||||
return *m_pConfig.get();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -146,7 +146,7 @@ private:
|
|||
volatile BOOL m_fShutdownCalledFromManaged;
|
||||
BOOL m_fInitialized;
|
||||
MANAGED_APPLICATION_STATUS m_status;
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
std::unique_ptr<InProcessOptions> m_pConfig;
|
||||
|
||||
static IN_PROCESS_APPLICATION* s_Application;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#define FileDescription "IIS ASP.NET Core Module Request Handler. Commit: " CommitHash
|
||||
#define FileDescription "IIS ASP.NET Core Module V2 Request Handler. Commit: " CommitHash
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -187,11 +187,11 @@ http_get_application_properties(
|
|||
auto pConfiguration = pInProcessApplication->QueryConfig();
|
||||
|
||||
pIISCofigurationData->pInProcessApplication = pInProcessApplication;
|
||||
pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pConfiguration->QueryApplicationPhysicalPath()->QueryStr());
|
||||
pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pConfiguration->QueryApplicationVirtualPath()->QueryStr());
|
||||
pIISCofigurationData->fWindowsAuthEnabled = pConfiguration->QueryWindowsAuthEnabled();
|
||||
pIISCofigurationData->fBasicAuthEnabled = pConfiguration->QueryBasicAuthEnabled();
|
||||
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration->QueryAnonymousAuthEnabled();
|
||||
pIISCofigurationData->pwzFullApplicationPath = SysAllocString(pInProcessApplication->QueryApplicationPhysicalPath().c_str());
|
||||
pIISCofigurationData->pwzVirtualApplicationPath = SysAllocString(pInProcessApplication->QueryApplicationVirtualPath().c_str());
|
||||
pIISCofigurationData->fWindowsAuthEnabled = pConfiguration.QueryWindowsAuthEnabled();
|
||||
pIISCofigurationData->fBasicAuthEnabled = pConfiguration.QueryBasicAuthEnabled();
|
||||
pIISCofigurationData->fAnonymousAuthEnable = pConfiguration.QueryAnonymousAuthEnabled();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#define FileDescription "IIS ASP.NET Core Module Request Handler. Commit: " CommitHash
|
||||
#define FileDescription "IIS ASP.NET Core Module V2 Request Handler. Commit: " CommitHash
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class AppOfflineTrackingApplication: public APPLICATION
|
|||
{
|
||||
public:
|
||||
AppOfflineTrackingApplication(const IHttpApplication& application)
|
||||
: APPLICATION(),
|
||||
: APPLICATION(application),
|
||||
m_applicationPath(application.GetApplicationPhysicalPath()),
|
||||
m_fileWatcher(nullptr),
|
||||
m_fAppOfflineProcessed(false)
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ public:
|
|||
{
|
||||
HRESULT hr = S_OK;
|
||||
if (FAILED(hr = _strName.Copy(pszName)) ||
|
||||
FAILED(hr = _strValue.Copy(pszValue)))
|
||||
FAILED(hr = _strValue.Copy(pszValue)))
|
||||
{
|
||||
}
|
||||
return hr;
|
||||
return hr;
|
||||
}
|
||||
|
||||
VOID
|
||||
VOID
|
||||
Reference() const
|
||||
{
|
||||
InterlockedIncrement(&_cRefs);
|
||||
|
|
@ -139,3 +139,11 @@ struct ENVIRONMENT_VAR_HASH_DELETER
|
|||
delete hashTable;
|
||||
}
|
||||
};
|
||||
|
||||
struct ENVIRONMENT_VAR_ENTRY_DELETER
|
||||
{
|
||||
void operator ()(ENVIRONMENT_VAR_ENTRY* entry) const
|
||||
{
|
||||
entry->Dereference();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ using Xunit;
|
|||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
[Collection(IISTestSiteCollection.Name)]
|
||||
public class EnvironmentVariableTests
|
||||
public class EnvironmentVariableTests: FixtureLoggedTest
|
||||
{
|
||||
private readonly IISTestSiteFixture _fixture;
|
||||
|
||||
public EnvironmentVariableTests(IISTestSiteFixture fixture)
|
||||
public EnvironmentVariableTests(IISTestSiteFixture fixture): base(fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
|
|
|
|||
|
|
@ -200,8 +200,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
var logContents = streamReader.ReadToEnd();
|
||||
Assert.Contains("[aspnetcorev2.dll]", logContents);
|
||||
Assert.Contains("[aspnetcorev2_inprocess.dll]", logContents);
|
||||
Assert.Contains("Description: IIS AspNetCore Module V2. Commit:", logContents);
|
||||
Assert.Contains("Description: IIS ASP.NET Core Module Request Handler. Commit:", logContents);
|
||||
Assert.Contains("Description: IIS ASP.NET Core Module V2. Commit:", logContents);
|
||||
Assert.Contains("Description: IIS ASP.NET Core Module V2 Request Handler. Commit:", logContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||
{
|
||||
public class EventLogHelpers
|
||||
{
|
||||
private static readonly Regex EventLogRegex = new Regex("Event Log: (?<EventLogMessage>.+?)End Event Log Message.", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
|
||||
public static void VerifyEventLogEvent(IISDeploymentResult deploymentResult, ITestSink testSink, string expectedRegexMatchString)
|
||||
{
|
||||
Assert.True(deploymentResult.HostProcess.HasExited);
|
||||
|
|
@ -36,6 +43,43 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
Assert.True(count > 0, $"'{expectedRegexMatchString}' didn't match any event log messaged");
|
||||
Assert.True(count < 2, $"'{expectedRegexMatchString}' matched more then one event log message");
|
||||
|
||||
var eventLog = new EventLog("Application");
|
||||
|
||||
// Perf: only get the last 20 events from the event log.
|
||||
// Eventlog is already sorted based on time of event in ascending time.
|
||||
// Add results in reverse order.
|
||||
var expectedRegexEventLog = new Regex(expectedRegexMatchString);
|
||||
var processIdString = $"Process Id: {deploymentResult.HostProcess.Id}.";
|
||||
|
||||
for (var i = eventLog.Entries.Count - 1; i >= eventLog.Entries.Count - 20; i--)
|
||||
{
|
||||
var eventLogEntry = eventLog.Entries[i];
|
||||
if (eventLogEntry.ReplacementStrings == null ||
|
||||
eventLogEntry.ReplacementStrings.Length < 3)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ReplacementStings == EventData collection in EventLog
|
||||
// This is unaffected if event providers are not registered correctly
|
||||
if (eventLogEntry.Source == AncmVersionToMatch(deploymentResult) &&
|
||||
processIdString == eventLogEntry.ReplacementStrings[1] &&
|
||||
expectedRegex.IsMatch(eventLogEntry.ReplacementStrings[0]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.True(false, $"'{expectedRegexMatchString}' didn't match any event log messaged.");
|
||||
}
|
||||
|
||||
private static string AncmVersionToMatch(IISDeploymentResult deploymentResult)
|
||||
{
|
||||
return "IIS " +
|
||||
(deploymentResult.DeploymentParameters.ServerType == ServerType.IISExpress ? "Express " : "") +
|
||||
"AspNetCore Module" +
|
||||
(deploymentResult.DeploymentParameters.AncmVersion == AncmVersion.AspNetCoreModuleV2 ? " V2" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
|
@ -133,5 +134,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
await verificationAction();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> ToTheoryData<T>(this Dictionary<string, T> dictionary)
|
||||
{
|
||||
return dictionary.Keys.Select(k => new[] { k });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "InProcessOptions.h"
|
||||
|
||||
class MockProperty : public IAppHostProperty
|
||||
{
|
||||
|
|
@ -176,20 +177,14 @@ public:
|
|||
MOCK_METHOD0(GetModuleContextContainer, IHttpModuleContextContainer* ());
|
||||
};
|
||||
|
||||
class MockRequestHandlerConfig : public REQUESTHANDLER_CONFIG
|
||||
class MockInProcessOptions : public InProcessOptions
|
||||
{
|
||||
public:
|
||||
static
|
||||
MockRequestHandlerConfig*
|
||||
MockInProcessOptions*
|
||||
CreateConfig()
|
||||
{
|
||||
return new MockRequestHandlerConfig;
|
||||
}
|
||||
|
||||
private:
|
||||
MockRequestHandlerConfig()
|
||||
{
|
||||
|
||||
return new MockInProcessOptions;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,13 @@ namespace InprocessTests
|
|||
ON_CALL(application, GetApplicationPhysicalPath())
|
||||
.WillByDefault(testing::Return(L"Some path"));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<REQUESTHANDLER_CONFIG>(MockRequestHandlerConfig::CreateConfig());
|
||||
ON_CALL(application, GetAppConfigPath())
|
||||
.WillByDefault(testing::Return(L""));
|
||||
|
||||
ON_CALL(application, GetApplicationId())
|
||||
.WillByDefault(testing::Return(L""));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<InProcessOptions>(MockInProcessOptions::CreateConfig());
|
||||
|
||||
std::wstring exePath(L"hello");
|
||||
|
||||
|
|
@ -36,4 +42,44 @@ namespace InprocessTests
|
|||
|
||||
ASSERT_STREQ(app->QueryExeLocation(), L"hello");
|
||||
}
|
||||
|
||||
TEST(InProcessTest, GeneratesVirtualPath)
|
||||
{
|
||||
MockHttpServer server;
|
||||
NiceMock<MockHttpApplication> application;
|
||||
|
||||
ON_CALL(application, GetApplicationPhysicalPath())
|
||||
.WillByDefault(testing::Return(L"Some path"));
|
||||
|
||||
ON_CALL(application, GetAppConfigPath())
|
||||
.WillByDefault(testing::Return(L"SECTION1/SECTION2/SECTION3/SECTION4/SECTION5"));
|
||||
|
||||
ON_CALL(application, GetApplicationId())
|
||||
.WillByDefault(testing::Return(L""));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<InProcessOptions>(MockInProcessOptions::CreateConfig());
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, application, std::move(requestHandlerConfig), nullptr, 0);
|
||||
|
||||
ASSERT_STREQ(app->QueryApplicationVirtualPath().c_str(), L"/SECTION5");
|
||||
}
|
||||
|
||||
TEST(InProcessTest, GeneratesVirtualPathForDefaultApp)
|
||||
{
|
||||
MockHttpServer server;
|
||||
NiceMock<MockHttpApplication> application;
|
||||
|
||||
ON_CALL(application, GetApplicationPhysicalPath())
|
||||
.WillByDefault(testing::Return(L"Some path"));
|
||||
|
||||
ON_CALL(application, GetAppConfigPath())
|
||||
.WillByDefault(testing::Return(L"SECTION1/SECTION2/SECTION3/SECTION4"));
|
||||
|
||||
ON_CALL(application, GetApplicationId())
|
||||
.WillByDefault(testing::Return(L""));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<InProcessOptions>(MockInProcessOptions::CreateConfig());
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, application, std::move(requestHandlerConfig), nullptr, 0);
|
||||
|
||||
ASSERT_STREQ(app->QueryApplicationVirtualPath().c_str(), L"/");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
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;
|
||||
|
|
@ -185,5 +187,45 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Unknown hosting model 'bogus'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file.");
|
||||
}
|
||||
|
||||
|
||||
private static Dictionary<string, (string, Action<XElement>)> InvalidConfigTransformations = InitInvalidConfigTransformations();
|
||||
public static IEnumerable<object[]> InvalidConfigTransformationsScenarios => InvalidConfigTransformations.ToTheoryData();
|
||||
|
||||
[ConditionalTheory]
|
||||
[MemberData(nameof(InvalidConfigTransformationsScenarios))]
|
||||
public async Task StartsWithWebConfigVariationsPortable(string scenario)
|
||||
{
|
||||
var (expectedError, action) = InvalidConfigTransformations[scenario];
|
||||
var iisDeploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true);
|
||||
iisDeploymentParameters.WebConfigActionList.Add((element, _) => action(element));
|
||||
var deploymentResult = await DeployAsync(iisDeploymentParameters);
|
||||
var result = await deploymentResult.HttpClient.GetAsync("/HelloWorld");
|
||||
Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode);
|
||||
|
||||
StopServer();
|
||||
EventLogHelpers.VerifyEventLogEvent(deploymentResult, TestSink, "Configuration load error. " + expectedError);
|
||||
}
|
||||
|
||||
public static Dictionary<string, (string, Action<XElement>)> InitInvalidConfigTransformations()
|
||||
{
|
||||
var dictionary = new Dictionary<string, (string, Action<XElement>)>();
|
||||
dictionary.Add("Empty process path",
|
||||
(
|
||||
"Attribute 'processPath' is required.",
|
||||
element => element.Descendants("aspNetCore").Single().SetAttributeValue("processPath", "")
|
||||
));
|
||||
dictionary.Add("Unknown hostingModel",
|
||||
(
|
||||
"Unknown hosting model 'asdf'.",
|
||||
element => element.Descendants("aspNetCore").Single().SetAttributeValue("hostingModel", "asdf")
|
||||
));
|
||||
dictionary.Add("environmentVariables with add",
|
||||
(
|
||||
"Unable to get required configuration section 'system.webServer/aspNetCore'. Possible reason is web.config authoring error.",
|
||||
element => element.Descendants("aspNetCore").Single().GetOrAdd("environmentVariables").GetOrAdd("add")
|
||||
));
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<Project>
|
||||
<Import Project="..\Directory.Build.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Remove="Internal.AspNetCore.Sdk" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Loading…
Reference in New Issue