Load ANCM out of process via global versioning (#895)

This commit is contained in:
Justin Kotalik 2018-06-12 14:04:21 -07:00 committed by GitHub
parent f00d7b34c5
commit 9d97ff38f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 862 additions and 68 deletions

View File

@ -29,8 +29,8 @@
</PropertyGroup>
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)\$(AspNetCoreModuleOutOfProcessVersion)\%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_outofprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)\$(AspNetCoreModuleOutOfProcessVersion)\%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_inprocess.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2_inprocess.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />
<None Include="$(MSBuildThisFileDirectory)..\src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\$(NativeFolder)\aspnetcorev2.dll" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="$(BasePathForRequestHandler)%(FileName)%(Extension)" />

View File

@ -21,8 +21,8 @@
<files>
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\Win32\aspnetcorev2.dll" target="contentFiles\any\any\x86\aspnetcorev2.dll" />
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\aspnetcorev2.dll" target="contentFiles\any\any\x64\aspnetcorev2.dll" />
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x86\aspnetcorev2_outofprocess.dll" />
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x64\aspnetcorev2_outofprocess.dll" />
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x86\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll" />
<file src="src\AspNetCoreModuleV2\OutOfProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_outofprocess.dll" target="contentFiles\any\any\x64\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll" />
<file src="src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$Configuration$\Win32\aspnetcorev2_inprocess.dll" target="contentFiles\any\any\x86\aspnetcorev2_inprocess.dll" />
<file src="src\AspNetCoreModuleV2\InProcessRequestHandler\bin\$Configuration$\x64\aspnetcorev2_inprocess.dll" target="contentFiles\any\any\x64\aspnetcorev2_inprocess.dll" />
<file src="src\AspNetCoreModuleV2\AspNetCore\bin\$Configuration$\x64\*.xml"/>

View File

@ -5,8 +5,8 @@
<AspNetCoreModuleX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcore.dll</AspNetCoreModuleX86Location>
<InProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorev2_inprocess.dll</InProcessRequestHandlerX64Location>
<InProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorev2_inprocess.dll</InProcessRequestHandlerX86Location>
<OutOfProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX64Location>
<OutOfProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX86Location>
<OutOfProcessRequestHandlerX64Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x64\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX64Location>
<OutOfProcessRequestHandlerX86Location>$(MSBuildThisFileDirectory)..\contentFiles\any\any\x86\$(AspNetCoreModuleOutOfProcessVersion)\aspnetcorev2_outofprocess.dll</OutOfProcessRequestHandlerX86Location>
</PropertyGroup>
</Project>

View File

@ -4,6 +4,7 @@
#pragma once
#include "precomp.hxx"
#include <map>
#define CS_ASPNETCORE_SECTION L"system.webServer/aspNetCore"
#define CS_ASPNETCORE_PROCESS_EXE_PATH L"processPath"
@ -105,6 +106,14 @@ public:
return m_hostingModel;
}
STRU*
QueryHandlerVersion(
VOID
)
{
return &m_struHandlerVersion;
}
private:
ASPNETCORE_SHIM_CONFIG() :
m_cRefs(1),
@ -120,5 +129,6 @@ private:
STRU m_struConfigPath;
APP_HOSTING_MODEL m_hostingModel;
STRU m_struHostFxrLocation;
STRU m_struHandlerVersion;
};

View File

@ -358,60 +358,47 @@ Finished:
HRESULT
APPLICATION_INFO::FindNativeAssemblyFromGlobalLocation(
PCWSTR libraryName,
STRU* struFilename)
PCWSTR pstrHandlerDllName,
STRU* struFilename
)
{
HRESULT hr = S_OK;
DWORD dwSize = MAX_PATH;
BOOL fDone = FALSE;
DWORD dwPosition = 0;
// Though we could call LoadLibrary(L"aspnetcorerh.dll") relying the OS to solve
// the path (the targeted dll is the same folder of w3wp.exe/iisexpress)
// let's still load with full path to avoid security issue
if (FAILED(hr = struFilename->Resize(dwSize + 20)))
try
{
goto Finished;
}
std::wstring modulePath = GlobalVersionUtility::GetModuleName(g_hModule);
while (!fDone)
{
DWORD dwReturnedSize = GetModuleFileNameW(g_hModule, struFilename->QueryStr(), dwSize);
if (dwReturnedSize == 0)
modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath);
std::wstring retval = GlobalVersionUtility::GetGlobalRequestHandlerPath(modulePath.c_str(),
m_pConfiguration->QueryHandlerVersion()->QueryStr(),
pstrHandlerDllName
);
if (FAILED(hr = struFilename->Copy(retval.c_str())))
{
hr = HRESULT_FROM_WIN32(GetLastError());
fDone = TRUE;
goto Finished;
}
else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
dwSize *= 2; // smaller buffer. increase the buffer and retry
if (FAILED(hr = struFilename->Resize(dwSize + 40))) // + 40 for aspnetcorerh.dll
{
goto Finished;
}
}
else
{
fDone = TRUE;
return hr;
}
}
if (FAILED(hr = struFilename->SyncWithBuffer()))
catch (std::exception& e)
{
goto Finished;
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;
}
dwPosition = struFilename->LastIndexOf(L'\\', 0);
struFilename->QueryStr()[dwPosition] = L'\0';
if (FAILED(hr = struFilename->SyncWithBuffer()) ||
FAILED(hr = struFilename->Append(L"\\")) ||
FAILED(hr = struFilename->Append(libraryName)))
catch (...)
{
goto Finished;
hr = E_FAIL;
}
Finished:
return hr;
}

View File

@ -3,6 +3,7 @@
#include "aspnetcore_shim_config.h"
#include "config_utility.h"
#include "hostfxr_utility.h"
#include "debugutil.h"
#include "ahutil.h"
@ -192,6 +193,8 @@ ASPNETCORE_SHIM_CONFIG::Populate(
goto Finished;
}
hr = ConfigUtility::FindHandlerVersion(pAspNetCoreElement, &m_struHandlerVersion);
Finished:
if (pAspNetCoreElement != NULL)

View File

@ -181,6 +181,8 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="application.h" />
<ClInclude Include="config_utility.h" />
<ClInclude Include="GlobalVersionUtility.h" />
<ClInclude Include="NullOutputManager.h" />
<ClInclude Include="FileOutputManager.h" />
<ClInclude Include="fx_ver.h" />
@ -205,6 +207,7 @@
<ItemGroup>
<ClCompile Include="FileOutputManager.cpp" />
<ClCompile Include="fx_ver.cxx" />
<ClCompile Include="GlobalVersionUtility.cpp" />
<ClCompile Include="hostfxr_utility.cpp" />
<ClCompile Include="hostfxroptions.cpp" />
<ClCompile Include="requesthandler_config.cpp" />

View File

@ -0,0 +1,131 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "stdafx.h"
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
// throws runtime error if no request handler versions are installed.
// Throw invalid_argument if any argument is null
std::wstring
GlobalVersionUtility::GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName)
{
if (pwzAspNetCoreFolderPath == NULL)
{
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
}
if (pwzHandlerVersion == NULL)
{
throw new std::invalid_argument("pwzHandlerVersion is NULL");
}
if (pwzHandlerName == NULL)
{
throw new std::invalid_argument("pwzHandlerName is NULL");
}
std::wstring folderVersion(pwzHandlerVersion);
fs::path aspNetCoreFolderPath(pwzAspNetCoreFolderPath);
if (folderVersion.empty())
{
folderVersion = FindHighestGlobalVersion(pwzAspNetCoreFolderPath);
}
aspNetCoreFolderPath = aspNetCoreFolderPath
.append(folderVersion)
.append(pwzHandlerName);
return aspNetCoreFolderPath;
}
// Throw filesystem_error if directory_iterator can't iterate over the directory
// Throw invalid_argument if any argument is null
std::vector<fx_ver_t>
GlobalVersionUtility::GetRequestHandlerVersions(PCWSTR pwzAspNetCoreFolderPath)
{
if (pwzAspNetCoreFolderPath == NULL)
{
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
}
std::vector<fx_ver_t> versionsInDirectory;
for (auto& p : fs::directory_iterator(pwzAspNetCoreFolderPath))
{
if (!fs::is_directory(p))
{
continue;
}
fx_ver_t requested_ver(-1, -1, -1);
if (fx_ver_t::parse(p.path().filename(), &requested_ver, false))
{
versionsInDirectory.push_back(requested_ver);
}
}
return versionsInDirectory;
}
// throws runtime error if no request handler versions are installed.
// Throw invalid_argument if any argument is null
std::wstring
GlobalVersionUtility::FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath)
{
if (pwzAspNetCoreFolderPath == NULL)
{
throw new std::invalid_argument("pwzAspNetCoreFolderPath is NULL");
}
std::vector<fx_ver_t> versionsInDirectory = GetRequestHandlerVersions(pwzAspNetCoreFolderPath);
if (versionsInDirectory.empty())
{
throw new std::runtime_error("Cannot find request handler next to aspnetcorev2.dll. Verify a version of the request handler is installed in a version folder.");
}
std::sort(versionsInDirectory.begin(), versionsInDirectory.end());
return versionsInDirectory.back().as_str();
}
// Throws std::out_of_range if there is an index out of range
// Throw invalid_argument if any argument is null
std::wstring
GlobalVersionUtility::RemoveFileNameFromFolderPath(std::wstring fileName)
{
fs::path path(fileName);
return path.parent_path();
}
std::wstring
GlobalVersionUtility::GetModuleName(HMODULE hModuleName)
{
DWORD dwSize = MAX_PATH;
BOOL fDone = FALSE;
// Instead of creating a temporary buffer, use the std::wstring directly as the receive buffer.
std::wstring retVal;
retVal.resize(dwSize);
while (!fDone)
{
DWORD dwReturnedSize = GetModuleFileNameW(hModuleName, &retVal[0], dwSize);
if (dwReturnedSize == 0)
{
throw new std::runtime_error("GetModuleFileNameW returned 0.");
}
else if ((dwReturnedSize == dwSize) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
dwSize *= 2;
retVal.resize(dwSize); // smaller buffer. increase the buffer and retry
}
else
{
// GetModuleFilename will not account for the null terminator
// std::wstring auto appends one, so we don't need to subtract 1 when resizing.
retVal.resize(dwReturnedSize);
fDone = TRUE;
}
}
return retVal;
}

View File

@ -0,0 +1,31 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include <experimental/filesystem>
class GlobalVersionUtility
{
public:
static
std::wstring
GetGlobalRequestHandlerPath(PCWSTR pwzAspNetCoreFolderPath, PCWSTR pwzHandlerVersion, PCWSTR pwzHandlerName);
static
std::wstring
FindHighestGlobalVersion(PCWSTR pwzAspNetCoreFolderPath);
static
std::wstring
RemoveFileNameFromFolderPath(std::wstring fileName);
static
std::vector<fx_ver_t>
GetRequestHandlerVersions(PCWSTR pwzAspNetCoreFolderPath);
static
std::wstring
GetModuleName(HMODULE hModuleName);
};

View File

@ -0,0 +1,106 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#pragma once
#include "stdafx.h"
class ConfigUtility
{
#define CS_ASPNETCORE_HANDLER_SETTINGS L"handlerSettings"
#define CS_ASPNETCORE_HANDLER_VERSION L"handlerVersion"
#define CS_ASPNETCORE_HANDLER_SETTINGS_NAME L"name"
#define CS_ASPNETCORE_HANDLER_SETTINGS_VALUE L"value"
public:
static
HRESULT
FindHandlerVersion(IAppHostElement* pElement, STRU* strHandlerVersionValue)
{
HRESULT hr = S_OK;
IAppHostElement *pHandlerSettings = NULL;
IAppHostElementCollection *pHandlerSettingsCollection = NULL;
ENUM_INDEX index;
IAppHostElement *pHandlerVar = NULL;
STRU strHandlerName;
STRU strHandlerValue;
hr = GetElementChildByName(pElement,
CS_ASPNETCORE_HANDLER_SETTINGS,
&pHandlerSettings);
if (FAILED(hr))
{
goto Finished;
}
hr = pHandlerSettings->get_Collection(&pHandlerSettingsCollection);
if (FAILED(hr))
{
goto Finished;
}
for (hr = FindFirstElement(pHandlerSettingsCollection, &index, &pHandlerVar);
SUCCEEDED(hr);
hr = FindNextElement(pHandlerSettingsCollection, &index, &pHandlerVar))
{
if (hr == S_FALSE)
{
hr = S_OK;
break;
}
hr = GetElementStringProperty(pHandlerVar,
CS_ASPNETCORE_HANDLER_SETTINGS_NAME,
&strHandlerName);
if (FAILED(hr))
{
goto Finished;
}
hr = GetElementStringProperty(pHandlerVar,
CS_ASPNETCORE_HANDLER_SETTINGS_VALUE,
&strHandlerValue);
if (FAILED(hr))
{
goto Finished;
}
if (strHandlerName.Equals(CS_ASPNETCORE_HANDLER_VERSION))
{
hr = strHandlerVersionValue->Copy(strHandlerValue);
goto Finished;
}
strHandlerName.Reset();
strHandlerValue.Reset();
pHandlerVar->Release();
pHandlerVar = NULL;
}
Finished:
if (pHandlerVar != NULL)
{
pHandlerVar->Release();
pHandlerVar = NULL;
}
if (pHandlerSettingsCollection != NULL)
{
pHandlerSettingsCollection->Release();
pHandlerSettingsCollection = NULL;
}
if (pHandlerSettings != NULL)
{
pHandlerSettings->Release();
pHandlerSettings = NULL;
}
return hr;
}
};

View File

@ -14,6 +14,8 @@
#include <shellapi.h>
#include <sstream>
#include <memory>
#include <experimental/filesystem>
#include "Shlwapi.h"
#include <io.h>
#include "hashtable.h"
@ -31,10 +33,11 @@
#include "application.h"
#include "SRWLockWrapper.h"
#include "environmentvariablehash.h"
#include "fx_ver.h"
#include "utility.h"
#include "GlobalVersionUtility.h"
#include "resources.h"
#include "aspnetcore_msg.h"
#include "fx_ver.h"
#include "hostfxr_utility.h"
#include "hostfxroptions.h"
#include "IOutputManager.h"
@ -42,3 +45,4 @@
#include "PipeOutputManager.h"
#include "NullOutputManager.h"
#include "LoggingHelpers.h"

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#include"stdafx.h"
#include "stdafx.h"
// static
HRESULT

View File

@ -3,6 +3,8 @@
#pragma once
#include "stdafx.h"
class UTILITY
{
public:
@ -121,3 +123,4 @@ private:
UTILITY() {}
~UTILITY() {}
};

View File

@ -50,7 +50,9 @@
<ClInclude Include="stdafx.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ConfigUtilityTests.cpp" />
<ClCompile Include="FileOutputManagerTests.cpp" />
<ClCompile Include="GlobalVersionTests.cpp" />
<ClCompile Include="Helpers.cpp" />
<ClCompile Include="hostfxr_utility_tests.cpp" />
<ClCompile Include="inprocess_application_tests.cpp" />
@ -93,7 +95,7 @@
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;..\gtest\googletest\googlemock\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
@ -118,7 +120,7 @@
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;..\gtest\googletest\googlemock\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
@ -141,7 +143,7 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;..\gtest\googletest\googlemock\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
@ -166,9 +168,9 @@
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories);..\..\src\AspNetCoreModuleV2\IISLib;..\..\src\AspNetCoreModuleV2\CommonLib;..\gtest\googletest\googletest\include;..\gtest\googletest\googlemock\include;...\..\src\AspNetCoreModuleV2\AspNetCore\Inc;..\..\src\AspNetCoreModuleV2\InProcessRequestHandler\;</AdditionalIncludeDirectories>
<AdditionalOptions>/D "_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING" </AdditionalOptions>
<LanguageStandard>stdcpp14</LanguageStandard>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -0,0 +1,106 @@
// 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.
#include "stdafx.h"
#include "gmock/gmock.h"
using ::testing::_;
using ::testing::NiceMock;
namespace ConfigUtilityTests
{
TEST(ConfigUtilityTest, HandlerVersionSet)
{
IAppHostElement* retElement = NULL;
STRU handlerVersion;
// NiceMock removes warnings about "uninteresting calls",
auto element = std::make_unique<NiceMock<MockElement>>();
auto innerElement = std::make_unique<NiceMock<MockElement>>();
auto collection = std::make_unique<NiceMock<MockCollection>>();
auto nameElement = std::make_unique<NiceMock<MockElement>>();
auto mockProperty = std::make_unique<NiceMock<MockProperty>>();
ON_CALL(*element, GetElementByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(innerElement.get()), testing::Return(S_OK)));
ON_CALL(*innerElement, get_Collection(_))
.WillByDefault(testing::DoAll(testing::SetArgPointee<0>(collection.get()), testing::Return(S_OK)));
ON_CALL(*collection, get_Count(_))
.WillByDefault(DoAll(testing::SetArgPointee<0>(1), testing::Return(S_OK)));
ON_CALL(*collection, get_Item(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(nameElement.get()), testing::Return(S_OK)));
ON_CALL(*nameElement, GetPropertyByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(mockProperty.get()), testing::Return(S_OK)));
EXPECT_CALL(*mockProperty, get_StringValue(_))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"handlerVersion")), testing::Return(S_OK)))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"value")), testing::Return(S_OK)));
HRESULT hr = ConfigUtility::FindHandlerVersion(element.get(), &handlerVersion);
EXPECT_STREQ(handlerVersion.QueryStr(), L"value");
}
TEST(ConfigUtilityTest, NoHandlerVersion)
{
IAppHostElement* retElement = NULL;
STRU handlerVersion;
// NiceMock removes warnings about "uninteresting calls",
auto element = std::make_unique<NiceMock<MockElement>>();
auto innerElement = std::make_unique<NiceMock<MockElement>>();
auto collection = std::make_unique<NiceMock<MockCollection>>();
auto nameElement = std::make_unique<NiceMock<MockElement>>();
auto mockProperty = std::make_unique<NiceMock<MockProperty>>();
ON_CALL(*element, GetElementByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(innerElement.get()), testing::Return(S_OK)));
ON_CALL(*innerElement, get_Collection(_))
.WillByDefault(testing::DoAll(testing::SetArgPointee<0>(collection.get()), testing::Return(S_OK)));
ON_CALL(*collection, get_Count(_))
.WillByDefault(DoAll(testing::SetArgPointee<0>(1), testing::Return(S_OK)));
ON_CALL(*collection, get_Item(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(nameElement.get()), testing::Return(S_OK)));
ON_CALL(*nameElement, GetPropertyByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(mockProperty.get()), testing::Return(S_OK)));
EXPECT_CALL(*mockProperty, get_StringValue(_))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"randomvalue")), testing::Return(S_OK)))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"value")), testing::Return(S_OK)));
HRESULT hr = ConfigUtility::FindHandlerVersion(element.get(), &handlerVersion);
EXPECT_STREQ(handlerVersion.QueryStr(), L"");
}
TEST(ConfigUtilityTest, MultipleElements)
{
IAppHostElement* retElement = NULL;
STRU handlerVersion;
auto element = std::make_unique<NiceMock<MockElement>>();
auto innerElement = std::make_unique<NiceMock<MockElement>>();
auto collection = std::make_unique<NiceMock<MockCollection>>();
auto nameElement = std::make_unique<NiceMock<MockElement>>();
auto mockProperty = std::make_unique<NiceMock<MockProperty>>();
ON_CALL(*element, GetElementByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(innerElement.get()), testing::Return(S_OK)));
ON_CALL(*innerElement, get_Collection(_))
.WillByDefault(testing::DoAll(testing::SetArgPointee<0>(collection.get()), testing::Return(S_OK)));
ON_CALL(*collection, get_Count(_))
.WillByDefault(DoAll(testing::SetArgPointee<0>(2), testing::Return(S_OK)));
ON_CALL(*collection, get_Item(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(nameElement.get()), testing::Return(S_OK)));
ON_CALL(*nameElement, GetPropertyByName(_, _))
.WillByDefault(DoAll(testing::SetArgPointee<1>(mockProperty.get()), testing::Return(S_OK)));
EXPECT_CALL(*mockProperty, get_StringValue(_))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"key")), testing::Return(S_OK)))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"value")), testing::Return(S_OK)))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"handlerVersion")), testing::Return(S_OK)))
.WillOnce(DoAll(testing::SetArgPointee<0>(SysAllocString(L"value2")), testing::Return(S_OK)));
HRESULT hr = ConfigUtility::FindHandlerVersion(element.get(), &handlerVersion);
EXPECT_STREQ(handlerVersion.QueryStr(), L"value2");
}
}

View File

@ -40,8 +40,6 @@ namespace FileOutManagerStartupTests
wprintf(expected, out);
}
// std::filesystem is available on c++17, however gtest fails to build when using it
// c++14 has filesystem as experimental.
for (auto & p : std::experimental::filesystem::directory_iterator(tempDirectory))
{
std::wstring filename(p.path().filename());

View File

@ -0,0 +1,153 @@
// 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.
#include "stdafx.h"
#include "gtest/internal/gtest-port.h"
namespace GlobalVersionTests
{
using ::testing::Test;
namespace fs = std::experimental::filesystem;
class GlobalVersionTest : public Test
{
protected:
void
RemoveFileNamePath(PCWSTR dllPath, PCWSTR expected)
{
std::wstring res = GlobalVersionUtility::RemoveFileNameFromFolderPath(dllPath);
EXPECT_STREQ(res.c_str(), expected);
}
};
TEST_F(GlobalVersionTest, RemovesPathCorrectly)
{
RemoveFileNamePath(L"test\\log.txt", L"test");
RemoveFileNamePath(L"test\\log", L"test");
RemoveFileNamePath(L"C:\\Program Files\\IIS\\aspnetcorev2.dll", L"C:\\Program Files\\IIS");
RemoveFileNamePath(L"test\\log.txt", L"test");
}
TEST(GetRequestHandlerVersions, GetFolders)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
auto res = GlobalVersionUtility::GetRequestHandlerVersions(tempPath.c_str());
EXPECT_EQ(res.size(), 1);
EXPECT_EQ(res.at(0), fx_ver_t(2, 0, 0, std::wstring()));
}
TEST(GetRequestHandlerVersions, GetFolderPreview)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0-preview"));
auto res = GlobalVersionUtility::GetRequestHandlerVersions(tempPath.c_str());
EXPECT_EQ(res.size(), 1);
EXPECT_EQ(res.at(0), fx_ver_t(2, 0, 0, std::wstring(L"-preview")));
}
TEST(GetRequestHandlerVersions, GetFolderManyVersions)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\1.9.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0"));
auto res = GlobalVersionUtility::GetRequestHandlerVersions(tempPath.c_str());
EXPECT_EQ(res.size(), 3);
EXPECT_TRUE(std::find(res.begin(), res.end(), fx_ver_t(1, 9, 0, std::wstring())) != std::end(res));
EXPECT_TRUE(std::find(res.begin(), res.end(), fx_ver_t(2, 0, 0, std::wstring())) != std::end(res));
EXPECT_TRUE(std::find(res.begin(), res.end(), fx_ver_t(2, 1, 0, std::wstring())) != std::end(res));
}
TEST(FindHighestGlobalVersion, HighestVersionWithSingleFolder)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
auto res = GlobalVersionUtility::FindHighestGlobalVersion(tempPath.c_str());
EXPECT_STREQ(res.c_str(), L"2.0.0");
}
TEST(FindHighestGlobalVersion, HighestVersionWithMultipleVersions)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0"));
auto res = GlobalVersionUtility::FindHighestGlobalVersion(tempPath.c_str());
EXPECT_STREQ(res.c_str(), L"2.1.0");
}
TEST(FindHighestGlobalVersion, HighestVersionWithMultipleVersionsPreview)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.2.0-preview"));
auto res = GlobalVersionUtility::FindHighestGlobalVersion(tempPath.c_str());
EXPECT_STREQ(res.c_str(), L"2.2.0-preview");
}
TEST(FindHighestGlobalVersion, HighestVersionWithMultipleVersionNoPreview)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0-preview"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0"));
auto res = GlobalVersionUtility::FindHighestGlobalVersion(tempPath.c_str());
EXPECT_STREQ(res.c_str(), L"2.1.0");
}
TEST(GetGlobalRequestHandlerPath, FindHighestVersionNoHandlerName)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
auto result = GlobalVersionUtility::GetGlobalRequestHandlerPath(tempPath.c_str(), L"", L"aspnetcorev2_outofprocess.dll");
EXPECT_STREQ(result.c_str(), (tempPath + L"2.0.0\\aspnetcorev2_outofprocess.dll").c_str());
}
TEST(GetGlobalRequestHandlerPath, FindHighestVersionPreviewWins)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0-preview"));
auto result = GlobalVersionUtility::GetGlobalRequestHandlerPath(tempPath.c_str(), L"", L"aspnetcorev2_outofprocess.dll");
EXPECT_STREQ(result.c_str(), (tempPath + L"2.1.0-preview\\aspnetcorev2_outofprocess.dll").c_str());
}
TEST(GetGlobalRequestHandlerPath, FindHighestVersionSpecificVersion)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0-preview"));
auto result = GlobalVersionUtility::GetGlobalRequestHandlerPath(tempPath.c_str(), L"2.0.0", L"aspnetcorev2_outofprocess.dll");
EXPECT_STREQ(result.c_str(), (tempPath + L"2.0.0\\aspnetcorev2_outofprocess.dll").c_str());
}
TEST(GetGlobalRequestHandlerPath, FindHighestVersionSpecificPreview)
{
std::wstring tempPath = Helpers::CreateRandomTempDirectory();
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.0.0"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.1.0-preview"));
EXPECT_TRUE(fs::create_directories(tempPath + L"\\2.2.0"));
auto result = GlobalVersionUtility::GetGlobalRequestHandlerPath(tempPath.c_str(), L"2.1.0-preview", L"aspnetcorev2_outofprocess.dll");
EXPECT_STREQ(result.c_str(), (tempPath + L"2.1.0-preview\\aspnetcorev2_outofprocess.dll").c_str());
}
}

View File

@ -1,7 +1,62 @@
// 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.
#include "stdafx.h"
#pragma once
#include "gtest/gtest.h"
#include "gmock/gmock.h"
class MockProperty : public IAppHostProperty
{
public:
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, QueryInterface, HRESULT(REFIID riid, void ** ppvObject));
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, AddRef, ULONG());
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Release, ULONG());
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Name, HRESULT(BSTR* pbstrValue));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Value, HRESULT(VARIANT * pVariant));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Value, HRESULT(VARIANT value));
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Clear, HRESULT());
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_StringValue, HRESULT(BSTR* pbstrValue));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Exception, HRESULT(IAppHostPropertyException ** ppException));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetMetadata, HRESULT(BSTR bstrMetadataType, VARIANT * pValue));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetMetadata, HRESULT(BSTR bstrMetadataType, VARIANT value));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Schema, HRESULT(IAppHostPropertySchema ** ppSchema));
};
class MockCollection : public IAppHostElementCollection
{
public:
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, QueryInterface, HRESULT(REFIID riid, void ** ppvObject));
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, AddRef, ULONG());
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Release, ULONG());
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Clear, HRESULT());
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Schema, HRESULT(IAppHostCollectionSchema** pSchema));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Count, HRESULT(DWORD * dwordElem));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, get_Item, HRESULT(VARIANT cIndex, IAppHostElement ** ppElement));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddElement, HRESULT(IAppHostElement * pElement, INT cPosition));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, DeleteElement, HRESULT(VARIANT cIndex));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, CreateNewElement, HRESULT(BSTR bstrElementName, IAppHostElement** ppElement));
};
class MockElement : public IAppHostElement
{
public:
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, QueryInterface, HRESULT(REFIID riid, void ** ppvObject));
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, AddRef, ULONG());
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Release, ULONG());
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Name, HRESULT(BSTR * pbstrName));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Collection, HRESULT(IAppHostElementCollection ** ppCollection));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Properties, HRESULT(IAppHostPropertyCollection ** ppProperties));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_ChildElements, HRESULT(IAppHostChildElementCollection ** ppElements));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetMetadata, HRESULT(BSTR bstrMetadataType, VARIANT * pValue));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetMetadata, HRESULT(BSTR bstrMetadataType, VARIANT value));
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Schema, HRESULT(IAppHostElementSchema** pSchema));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetElementByName, HRESULT(BSTR bstrSubName, IAppHostElement ** ppElement));
MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetPropertyByName, HRESULT(BSTR bstrSubName, IAppHostProperty ** ppProperty));
MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Clear, HRESULT());
MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Methods, HRESULT(IAppHostMethodCollection ** ppMethods));
};
class MockHttpServer : public IHttpServer
{

View File

@ -43,6 +43,7 @@
#include "requesthandler_config.h"
#include "hostfxr_utility.h"
#include "config_utility.h"
#include "environmentvariablehash.h"
#include "iapplication.h"
#include "utility.h"
@ -51,9 +52,11 @@
#include "resources.h"
#include "aspnetcore_msg.h"
#include "Helpers.h"
#include "GlobalVersionUtility.h"
#undef assert // Macro redefinition in IISLib.
#include "gtest\gtest.h"
#include "gtest/gtest.h"
#include "fakeclasses.h"
// Externals defined in inprocess
BOOL g_fProcessDetach;

View File

@ -0,0 +1,160 @@
// 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.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using IISIntegration.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
public class GlobalVersionTests : IISFunctionalTestBase
{
private const string _aspNetCoreDll = "aspnetcorev2_outofprocess.dll";
private const string _handlerVersion20 = "2.0.0";
private const string _helloWorldRequest = "HelloWorld";
private const string _helloWorldResponse = "Hello World";
private const string _outOfProcessVersionVariable = "/p:AspNetCoreModuleOutOfProcessVersion=";
[Fact]
public async Task GlobalVersion_DefaultWorks()
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
deploymentParameters.PublishApplicationBeforeDeployment = false;
deploymentParameters.ServerConfigTemplateContent = GetServerConfig(
element =>
{
var handlerVersionElement = new XElement("handlerSetting");
handlerVersionElement.SetAttributeValue("name", "handlerVersion");
handlerVersionElement.SetAttributeValue("value", _handlerVersion20);
element.Descendants("aspNetCore").Single()
.Add(new XElement("handlerSettings", handlerVersionElement));
});
var deploymentResult = await DeployAsync(deploymentParameters);
var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest);
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
}
[Theory] // Tests need to publish to change folder locations
[InlineData("2.1.0")]
[InlineData("2.1.0-preview")]
public async Task GlobalVersion_NewVersionNumber_Fails(string version)
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
var deploymentResult = await DeployAsync(deploymentParameters);
Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version);
var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest);
Assert.False(response.IsSuccessStatusCode);
}
[Theory] // Tests need to publish to change folder locations
[InlineData("2.1.0")]
[InlineData("2.1.0-preview")]
public async Task GlobalVersion_NewVersionNumber(string version)
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
deploymentParameters.AdditionalPublishParameters = $"{_outOfProcessVersionVariable}{version}";
var deploymentResult = await DeployAsync(deploymentParameters);
Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version);
var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest);
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
}
[Theory] // Tests need to publish to change folder locations
[InlineData("2.1.0")]
[InlineData("2.1.0-preview")]
public async Task GlobalVersion_MultipleRequestHandlers_PicksHighestOne(string version)
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
var deploymentResult = await DeployAsync(deploymentParameters);
var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
var newANCMPath = GetANCMRequestHandlerPath(deploymentResult, version);
var di = Directory.CreateDirectory(Path.GetDirectoryName(newANCMPath));
File.Copy(originalANCMPath, newANCMPath, true);
deploymentResult.RetryingHttpClient.DefaultRequestHeaders.Add("ANCMRHPath", newANCMPath);
var response = await deploymentResult.RetryingHttpClient.GetAsync("CheckRequestHandlerVersion");
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
}
[Theory]
[InlineData("2.1.0")]
[InlineData("2.1.0-preview")]
public async Task GlobalVersion_MultipleRequestHandlers_UpgradeWorks(string version)
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
var deploymentResult = await DeployAsync(deploymentParameters);
var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
deploymentResult.RetryingHttpClient.DefaultRequestHeaders.Add("ANCMRHPath", originalANCMPath);
var response = await deploymentResult.RetryingHttpClient.GetAsync("CheckRequestHandlerVersion");
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
Dispose();
deploymentResult = await DeployAsync(deploymentParameters);
originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
var newANCMPath = GetANCMRequestHandlerPath(deploymentResult, version);
var di = Directory.CreateDirectory(Path.GetDirectoryName(newANCMPath));
File.Copy(originalANCMPath, newANCMPath, true);
deploymentResult.RetryingHttpClient.DefaultRequestHeaders.Add("ANCMRHPath", newANCMPath);
response = await deploymentResult.RetryingHttpClient.GetAsync("CheckRequestHandlerVersion");
responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
}
private DeploymentParameters GetGlobalVersionBaseDeploymentParameters()
{
return new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
TargetFramework = Tfm.NetCoreApp22,
ApplicationType = ApplicationType.Portable,
AncmVersion = AncmVersion.AspNetCoreModuleV2,
HostingModel = HostingModel.OutOfProcess,
PublishApplicationBeforeDeployment = true,
AdditionalPublishParameters = $"{_outOfProcessVersionVariable}{_handlerVersion20}"
};
}
private string GetANCMRequestHandlerPath(IISDeploymentResult deploymentResult, string version)
{
return Path.Combine(deploymentResult.DeploymentResult.ContentRoot,
deploymentResult.DeploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(),
version,
_aspNetCoreDll);
}
}
}

View File

@ -21,16 +21,31 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
public static void ModifyAspNetCoreSectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value)
=> ModifySectionInWebConfig(deploymentResult, key, value, section: "aspNetCore", 0);
=> ModifyAttributeInWebConfig(deploymentResult, key, value, section: "aspNetCore");
public static void ModifySectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value, string section, int index)
public static void ModifyAttributeInWebConfig(IISDeploymentResult deploymentResult, string key, string value, string section)
{
// modify the web.config after publish
var root = deploymentResult.DeploymentResult.ContentRoot;
var webConfigFile = $"{root}/web.config";
var webConfigFile = GetWebConfigFile(deploymentResult);
var config = XDocument.Load(webConfigFile);
var element = config.Descendants(section).ToList()[index];
var element = config.Descendants(section).Single();
element.SetAttributeValue(key, value);
config.Save(webConfigFile);
}
public static void ModifyHandlerSectionInWebConfig(IISDeploymentResult deploymentResult, string handlerVersionValue)
{
var webConfigFile = GetWebConfigFile(deploymentResult);
var config = XDocument.Load(webConfigFile);
var handlerVersionElement = new XElement("handlerSetting");
handlerVersionElement.SetAttributeValue("name", "handlerVersion");
handlerVersionElement.SetAttributeValue("value", handlerVersionValue);
config.Descendants("aspNetCore").Single()
.Add(new XElement("handlerSettings", handlerVersionElement));
config.Save(webConfigFile);
}
@ -46,5 +61,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
};
}
private static string GetWebConfigFile(IISDeploymentResult deploymentResult)
=> Path.Combine(deploymentResult.DeploymentResult.ContentRoot, "web.config");
}
}

View File

@ -2,7 +2,9 @@
// 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.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
@ -84,5 +86,22 @@ namespace TestSites
public Task UpgradeFeatureDetection(HttpContext context) =>
context.Response.WriteAsync(context.Features.Get<IHttpUpgradeFeature>() != null? "Enabled": "Disabled");
public Task CheckRequestHandlerVersion(HttpContext context)
{
// We need to check if the aspnetcorev2_outofprocess dll is loaded by iisexpress.exe
// As they aren't in the same process, we will try to delete the file and expect a file
// in use error
try
{
File.Delete(context.Request.Headers["ANCMRHPath"]);
}
catch(UnauthorizedAccessException)
{
return context.Response.WriteAsync("Hello World");
}
return context.Response.WriteAsync(context.Request.Headers["ANCMRHPath"]);
}
}
}

View File

@ -19,6 +19,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="googletest\googlemock\src\gmock-all.cc" />
<ClCompile Include="googletest\googletest\src\gtest-all.cc" />
</ItemGroup>
<PropertyGroup Label="Globals">
@ -105,7 +106,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;googletest\googlemock;googletest\googlemock\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
@ -121,7 +122,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;googletest\googlemock;googletest\googlemock\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
@ -139,7 +140,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;googletest\googlemock;googletest\googlemock\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@ -159,7 +160,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>googletest\googletest\include;googletest\googletest;googletest\googlemock;googletest\googlemock\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>

View File

@ -11,5 +11,6 @@
<AspNetCoreModuleVersionMajor>8</AspNetCoreModuleVersionMajor>
<AspNetCoreModuleVersionMinor>1</AspNetCoreModuleVersionMinor>
<AspNetCoreModuleVersionRevision>0</AspNetCoreModuleVersionRevision>
<AspNetCoreModuleOutOfProcessVersion>2.0.0</AspNetCoreModuleOutOfProcessVersion>
</PropertyGroup>
</Project>