diff --git a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj index bd0129be53..4b2c6129e8 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj @@ -232,14 +232,14 @@ + + + - - - @@ -248,11 +248,11 @@ + - Create Create @@ -284,6 +284,17 @@ PreserveNewest + + + + + + true + + + true + + diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index 7414f51161..726229cc9e 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -73,21 +73,18 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication pApplication.GetApplicationPhysicalPath(), outputManager)); - outputManager->TryStartRedirection(); - hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath); + hr = FindNativeAssemblyFromHostfxr(*options.get(), pstrHandlerDllName, handlerDllPath, outputManager.get()); - outputManager->TryStopRedirection(); - - if (FAILED(hr) && m_hHostFxrDll != nullptr) + if (FAILED_LOG(hr)) { auto output = outputManager->GetStdOutContent(); EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG, - handlerDllPath.empty()? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str(), output.c_str()); + return hr; } } else @@ -122,55 +119,38 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication } HRESULT -HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory) +HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options) { - try + SRWExclusiveLock lock(m_requestHandlerLoadLock); + if (m_loadedApplicationHostingModel != HOSTING_UNKNOWN) { - 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 != options.QueryHostingModel()) { - // Mixed hosting models - if (m_loadedApplicationHostingModel != options.QueryHostingModel()) - { - EventLog::Error( - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, - ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, - pApplication.GetApplicationId(), - options.QueryHostingModel()); + EventLog::Error( + ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR, + ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG, + pApplication.GetApplicationId(), + options.QueryHostingModel()); - return E_FAIL; - } - // Multiple in-process apps - if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId()) - { - EventLog::Error( - ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP, - ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, - pApplication.GetApplicationId()); - - return E_FAIL; - } + return E_FAIL; } + // Multiple in-process apps + if (m_loadedApplicationHostingModel == HOSTING_IN_PROCESS && m_loadedApplicationId != pApplication.GetApplicationId()) + { + EventLog::Error( + ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP, + ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG, + pApplication.GetApplicationId()); - m_loadedApplicationHostingModel = options.QueryHostingModel(); - m_loadedApplicationId = pApplication.GetApplicationId(); - RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); - + return E_FAIL; + } } - 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(); + m_loadedApplicationHostingModel = options.QueryHostingModel(); + m_loadedApplicationId = pApplication.GetApplicationId(); + RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); + return S_OK; } @@ -222,7 +202,8 @@ HRESULT HandlerResolver::FindNativeAssemblyFromHostfxr( const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, - std::wstring& handlerDllPath + std::wstring& handlerDllPath, + BaseOutputManager* outputManager ) { std::wstring struNativeSearchPaths; @@ -230,23 +211,29 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( size_t intPrevIndex = 0; DWORD dwBufferSize = s_initialGetNativeSearchDirectoriesBufferSize; DWORD dwRequiredBufferSize = 0; + hostfxr_get_native_search_directories_fn pFnHostFxrSearchDirectories = nullptr; RETURN_LAST_ERROR_IF_NULL(m_hHostFxrDll = LoadLibraryW(hostfxrOptions.GetHostFxrLocation().c_str())); - const auto pFnHostFxrSearchDirectories = ModuleHelpers::GetKnownProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"); - if (pFnHostFxrSearchDirectories == nullptr) + try + { + pFnHostFxrSearchDirectories = ModuleHelpers::GetKnownProcAddress(m_hHostFxrDll, "hostfxr_get_native_search_directories"); + } + catch (...) { EventLog::Error( ASPNETCORE_EVENT_GENERAL_ERROR, ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG, hostfxrOptions.GetHostFxrLocation().c_str() - ); - RETURN_IF_FAILED(E_FAIL); + ); + return OBSERVE_CAUGHT_EXCEPTION(); } RETURN_LAST_ERROR_IF_NULL(pFnHostFxrSearchDirectories); struNativeSearchPaths.resize(dwBufferSize); + outputManager->TryStartRedirection(); + while (TRUE) { DWORD hostfxrArgc; @@ -273,11 +260,23 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( } else { - // Log "Error finding native search directories from aspnetcore application. + // Stop redirecting before logging to event log to avoid logging debug logs + // twice. + outputManager->TryStopRedirection(); + + // If hostfxr didn't set the required buffer size, something in the app is misconfigured + // Ex: Framework not found. + EventLog::Error( + ASPNETCORE_EVENT_GENERAL_ERROR, + ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG + ); + return E_UNEXPECTED; } } + outputManager->TryStopRedirection(); + struNativeSearchPaths.resize(struNativeSearchPaths.find(L'\0')); auto fFound = FALSE; @@ -307,6 +306,10 @@ HandlerResolver::FindNativeAssemblyFromHostfxr( if (!fFound) { + EventLog::Error( + ASPNETCORE_EVENT_GENERAL_ERROR, + ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG, + handlerDllPath.empty() ? s_pwzAspnetcoreInProcessRequestHandlerName : handlerDllPath.c_str()); return HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND); } diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h index 7b230a928f..1cd9029347 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h @@ -9,18 +9,19 @@ #include "hostfxroptions.h" #include "HandleWrapper.h" #include "ApplicationFactory.h" +#include "BaseOutputManager.h" class HandlerResolver { public: HandlerResolver(HMODULE hModule, const IHttpServer &pServer); - HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory); + HRESULT GetApplicationFactory(const IHttpApplication &pApplication, std::unique_ptr& pApplicationFactory, const ShimOptions& options); void ResetHostingModel(); private: HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory); HRESULT FindNativeAssemblyFromGlobalLocation(const ShimOptions& pConfiguration, PCWSTR libraryName, std::wstring& handlerDllPath); - HRESULT FindNativeAssemblyFromHostfxr(const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath); + HRESULT FindNativeAssemblyFromHostfxr(const HOSTFXR_OPTIONS& hostfxrOptions, PCWSTR libraryName, std::wstring& handlerDllPath, BaseOutputManager* outputManager); HMODULE m_hModule; const IHttpServer &m_pServer; diff --git a/src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc b/src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc new file mode 100644 index 0000000000..d923a2121c Binary files /dev/null and b/src/AspNetCoreModuleV2/AspNetCore/HtmlResponses.rc differ diff --git a/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm b/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm new file mode 100644 index 0000000000..b7e575552a --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/InProcessShimStaticHtml.htm @@ -0,0 +1,45 @@ + + + + + + IIS 500 Error + + + + +
+
+

HTTP Error 500.0 - ANCM InProcess Startup Failure

+
+
+
+

Common causes of this issue:

+
    +
  • The specified version of Microsoft.NetCore.App or Microsoft.AspNetCore.App was not found.
  • +
  • The in process request handler, Microsoft.AspNetCore.Server.IIS, was not referenced in the application.
  • +
  • ANCM could not find dotnet.
  • +
+
+
+
+
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

For more information visit: + + https://go.microsoft.com/fwlink/?LinkID=808681 + +

+
+
+
+ + + diff --git a/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm b/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm new file mode 100644 index 0000000000..475ce26956 --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/OutOfProcessShimStaticHtml.htm @@ -0,0 +1,44 @@ + + + + + + IIS 500 Error + + + + +
+
+

HTTP Error 500.0 - ANCM OutOfProcess Startup Failure

+
+
+
+

Common causes of this issue:

+
    +
  • The out of process request handler, aspnetcorev2_outofprocess.dll, could not be found next to the aspnetcorev2.dll.
  • +
  • Could not read configuration correctly. Check the application's associated web.config.
  • +
+
+
+
+
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

For more information visit: + + https://go.microsoft.com/fwlink/?LinkID=808681 + +

+
+
+
+ + + \ No newline at end of file diff --git a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h index df686adbc4..ac5bd85aaf 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h +++ b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorApplication.h @@ -9,8 +9,16 @@ class ServerErrorApplication : public PollingAppOfflineApplication { public: - ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr) + ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr, HINSTANCE moduleInstance) + : ServerErrorApplication(pApplication, hr, moduleInstance, true /* disableStartupPage*/, 0 /* page */) + { + } + + ServerErrorApplication(const IHttpApplication& pApplication, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) : m_HR(hr), + m_disableStartupPage(disableStartupPage), + m_page(page), + m_moduleInstance(moduleInstance), PollingAppOfflineApplication(pApplication, PollingAppOfflineApplicationMode::StopWhenAdded) { } @@ -19,7 +27,7 @@ public: HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override { - auto handler = std::make_unique(*pHttpContext, m_HR); + auto handler = std::make_unique(*pHttpContext, m_HR, m_moduleInstance, m_disableStartupPage, m_page); *pRequestHandler = handler.release(); return S_OK; } @@ -27,5 +35,8 @@ public: HRESULT OnAppOfflineFound() noexcept override { return S_OK; } private: HRESULT m_HR; + bool m_disableStartupPage; + int m_page; + HINSTANCE m_moduleInstance; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h b/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h deleted file mode 100644 index 10cf3ee049..0000000000 --- a/src/AspNetCoreModuleV2/AspNetCore/ServerErrorHandler.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#pragma once -#include "requesthandler.h" - -class ServerErrorHandler : public REQUEST_HANDLER -{ -public: - ServerErrorHandler(IHttpContext &pContext, HRESULT hr) : m_pContext(pContext), m_HR(hr) - { - } - - REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override - { - m_pContext.GetResponse()->SetStatus(500, "Internal Server Error", 0, m_HR); - return RQ_NOTIFICATION_FINISH_REQUEST; - } - -private: - IHttpContext &m_pContext; - HRESULT m_HR; -}; diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp index 3ba1db7889..cb7f1488d7 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp @@ -40,4 +40,5 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) : 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); + m_fDisableStartupPage = section->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE); } diff --git a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h index 4b934ad9b4..3cfb47169e 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h +++ b/src/AspNetCoreModuleV2/AspNetCore/ShimOptions.h @@ -53,6 +53,12 @@ public: return m_struStdoutLogFile; } + bool + QueryDisableStartupPage() const noexcept + { + return m_fDisableStartupPage; + } + ShimOptions(const ConfigurationSource &configurationSource); private: @@ -62,4 +68,5 @@ private: std::wstring m_strHandlerVersion; std::wstring m_struStdoutLogFile; bool m_fStdoutLogEnabled; + bool m_fDisableStartupPage; }; diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 85bb5c6398..9b95d94f16 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -12,6 +12,11 @@ #include "EventLog.h" #include "ServerErrorApplication.h" #include "AppOfflineApplication.h" +#include "WebConfigConfigurationSource.h" +#include "ConfigurationLoadException.h" +#include "resource.h" + +extern HINSTANCE g_hServerModule; HRESULT APPLICATION_INFO::CreateHandler( @@ -23,7 +28,7 @@ APPLICATION_INFO::CreateHandler( { SRWSharedLock lock(m_applicationLock); - + RETURN_IF_FAILED(hr = TryCreateHandler(pHttpContext, pHandler)); if (hr == S_OK) @@ -31,10 +36,10 @@ APPLICATION_INFO::CreateHandler( return S_OK; } } - + { SRWExclusiveLock lock(m_applicationLock); - + // check if other thread created application RETURN_IF_FAILED(hr = TryCreateHandler(pHttpContext, pHandler)); @@ -66,48 +71,78 @@ APPLICATION_INFO::CreateHandler( HRESULT APPLICATION_INFO::CreateApplication(const IHttpApplication& pHttpApplication) { - HRESULT hr = S_OK; - if (AppOfflineApplication::ShouldBeStarted(pHttpApplication)) { LOG_INFO(L"Detected app_offline file, creating polling application"); - #pragma warning( push ) - #pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here - m_pApplication.reset(new AppOfflineApplication(pHttpApplication)); - #pragma warning( pop ) + m_pApplication = make_application(pHttpApplication); + + return S_OK; } else { - FINISHED_IF_FAILED(m_handlerResolver.GetApplicationFactory(pHttpApplication, m_pApplicationFactory)); + try + { + const WebConfigConfigurationSource configurationSource(m_pServer.GetAdminManager(), pHttpApplication); + ShimOptions options(configurationSource); - LOG_INFO(L"Creating handler application"); - IAPPLICATION * newApplication; - FINISHED_IF_FAILED(m_pApplicationFactory->Execute( - &m_pServer, - &pHttpApplication, - &newApplication)); + const auto hr = TryCreateApplication(pHttpApplication, options); - m_pApplication.reset(newApplication); + if (FAILED_LOG(hr)) + { + // Log the failure and update application info to not try again + EventLog::Error( + ASPNETCORE_EVENT_ADD_APPLICATION_ERROR, + ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG, + pHttpApplication.GetApplicationId(), + hr); + + m_pApplication = make_application( + pHttpApplication, + hr, + g_hServerModule, + options.QueryDisableStartupPage(), + options.QueryHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS ? IN_PROCESS_SHIM_STATIC_HTML : OUT_OF_PROCESS_SHIM_STATIC_HTML); + } + return S_OK; + } + catch (ConfigurationLoadException &ex) + { + EventLog::Error( + ASPNETCORE_CONFIGURATION_LOAD_ERROR, + ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG, + ex.get_message().c_str()); + } + catch (...) + { + EventLog::Error( + ASPNETCORE_CONFIGURATION_LOAD_ERROR, + ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG, + L""); + } + + m_pApplication = make_application( + pHttpApplication, + E_FAIL, + g_hServerModule); + + return S_OK; } +} -Finished: +HRESULT +APPLICATION_INFO::TryCreateApplication(const IHttpApplication& pHttpApplication, const ShimOptions& options) +{ + RETURN_IF_FAILED(m_handlerResolver.GetApplicationFactory(pHttpApplication, m_pApplicationFactory, options)); + LOG_INFO(L"Creating handler application"); - if (m_pApplication == nullptr || FAILED(hr)) - { - // Log the failure and update application info to not try again - EventLog::Error( - ASPNETCORE_EVENT_ADD_APPLICATION_ERROR, - ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG, - pHttpApplication.GetApplicationId(), - hr); - - #pragma warning( push ) - #pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here - m_pApplication.reset(new ServerErrorApplication(pHttpApplication, hr)); - #pragma warning( pop ) - } + IAPPLICATION * newApplication; + RETURN_IF_FAILED(m_pApplicationFactory->Execute( + &m_pServer, + &pHttpApplication, + &newApplication)); - return hr; + m_pApplication.reset(newApplication); + return S_OK; } HRESULT @@ -139,7 +174,7 @@ APPLICATION_INFO::ShutDownApplication(bool fServerInitiated) if (m_pApplication) { LOG_INFOF(L"Stopping application '%ls'", QueryApplicationInfoKey().c_str()); - m_pApplication ->Stop(fServerInitiated); + m_pApplication->Stop(fServerInitiated); m_pApplication = nullptr; m_pApplicationFactory = nullptr; } diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h index 9c6d1b7cde..4b190007dd 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationinfo.h @@ -76,6 +76,9 @@ private: HRESULT CreateApplication(const IHttpApplication& pHttpApplication); + HRESULT + TryCreateApplication(const IHttpApplication& pHttpApplication, const ShimOptions& options); + IHttpServer &m_pServer; HandlerResolver &m_handlerResolver; diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp index 52d9730ec1..d1e2b12375 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp @@ -13,7 +13,7 @@ extern BOOL g_fInShutdown; // // Retrieves the application info from the application manager -// Will create the application info if it isn't initalized +// Will create the application info if it isn't initialized // HRESULT APPLICATION_MANAGER::GetOrCreateApplicationInfo( @@ -21,7 +21,6 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo( _Out_ std::shared_ptr& ppApplicationInfo ) { - auto &pApplication = *pHttpContext.GetApplication(); // The configuration path is unique for each application and is used for the diff --git a/src/AspNetCoreModuleV2/AspNetCore/resource.h b/src/AspNetCoreModuleV2/AspNetCore/resource.h new file mode 100644 index 0000000000..289df99bc3 --- /dev/null +++ b/src/AspNetCoreModuleV2/AspNetCore/resource.h @@ -0,0 +1,19 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by HtmlResponses.rc +// +#define IN_PROCESS_SHIM_STATIC_HTML 101 +#define OUT_OF_PROCESS_SHIM_STATIC_HTML 102 +#define UNKNOWN_HOSTING_STATIC_HTML 103 + + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index 8628cc6529..caa53ff29d 100644 --- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -223,12 +223,14 @@ - + + + diff --git a/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp b/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp index b0442e1a81..1b3772bb4f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/FileOutputManager.cpp @@ -11,8 +11,6 @@ #include "StdWrapper.h" #include "StringHelpers.h" -extern HINSTANCE g_hModule; - FileOutputManager::FileOutputManager(std::wstring pwzStdOutLogFileName, std::wstring pwzApplicationPath) : FileOutputManager(pwzStdOutLogFileName, pwzApplicationPath, /* fEnableNativeLogging */ true) { } diff --git a/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h b/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h new file mode 100644 index 0000000000..721c0d12eb --- /dev/null +++ b/src/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +#pragma once +#include "requesthandler.h" +#include "file_utility.h" + +class ServerErrorHandler : public REQUEST_HANDLER +{ +public: + + ServerErrorHandler(IHttpContext &pContext, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) + : m_pContext(pContext), m_HR(hr), m_disableStartupPage(disableStartupPage), m_page(page), m_moduleInstance(moduleInstance) + { + } + + REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override + { + static std::string s_html500Page = FILE_UTILITY::GetHtml(m_moduleInstance, m_page); + + WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableStartupPage); + + return RQ_NOTIFICATION_FINISH_REQUEST; + } + +private: + IHttpContext &m_pContext; + HRESULT m_HR; + bool m_disableStartupPage; + int m_page; + HINSTANCE m_moduleInstance; +}; diff --git a/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp index a971821208..228c1c0d66 100644 --- a/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/file_utility.cpp @@ -5,6 +5,7 @@ #include #include "debugutil.h" +#include "exceptions.h" HRESULT FILE_UTILITY::IsPathUnc( @@ -165,3 +166,24 @@ FILE_UTILITY::EnsureDirectoryPathExist( Finished: return hr; } + +std::string +FILE_UTILITY::GetHtml(HMODULE module, int page) +{ + HRESULT hr = S_OK; + HRSRC rc = nullptr; + HGLOBAL rcData = nullptr; + const char* data = nullptr; + DWORD size = 0; + + FINISHED_LAST_ERROR_IF_NULL(rc = FindResource(module, MAKEINTRESOURCE(page), RT_HTML)); + FINISHED_LAST_ERROR_IF_NULL(rcData = LoadResource(module, rc)); + size = SizeofResource(module, rc); + FINISHED_LAST_ERROR_IF(size == 0); + FINISHED_LAST_ERROR_IF_NULL(data = static_cast(LockResource(rcData))); + + return data; +Finished: + + return ""; +} diff --git a/src/AspNetCoreModuleV2/CommonLib/file_utility.h b/src/AspNetCoreModuleV2/CommonLib/file_utility.h index cc541b712a..686e810cbe 100644 --- a/src/AspNetCoreModuleV2/CommonLib/file_utility.h +++ b/src/AspNetCoreModuleV2/CommonLib/file_utility.h @@ -25,6 +25,11 @@ public: EnsureDirectoryPathExist( _In_ LPCWSTR pszPath ); + + static + std::string + GetHtml(HMODULE module, int page); + private: static HRESULT @@ -32,5 +37,6 @@ private: __in LPCWSTR pszPath, __out BOOL * pfIsUnc ); + }; diff --git a/src/AspNetCoreModuleV2/CommonLib/iapplication.h b/src/AspNetCoreModuleV2/CommonLib/iapplication.h index 3349cb66fb..2e8660748f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/iapplication.h +++ b/src/AspNetCoreModuleV2/CommonLib/iapplication.h @@ -51,3 +51,13 @@ std::unique_ptr ReferenceApplication(APPLICAT application->ReferenceApplication(); return std::unique_ptr(application); }; + +template< class APPLICATION, typename ...Params > +std::unique_ptr make_application(Params&&... params) +{ +#pragma warning( push ) +#pragma warning ( disable : 26409 ) // Disable "Avoid using new", using custom deleter here + return std::unique_ptr(new APPLICATION(std::forward(params)...)); +#pragma warning( pop ) +} + diff --git a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h index a5e16bf022..b4cd3a0e35 100644 --- a/src/AspNetCoreModuleV2/CommonLib/requesthandler.h +++ b/src/AspNetCoreModuleV2/CommonLib/requesthandler.h @@ -46,6 +46,32 @@ public: { } +protected: + + static + void WriteStaticResponse(IHttpContext& pContext, std::string &s_html500Page, HRESULT hr, bool disableStartupErrorPage) + { + if (disableStartupErrorPage) + { + pContext.GetResponse()->SetStatus(500, "Internal Server Error", 30, E_FAIL); + return; + } + + HTTP_DATA_CHUNK dataChunk = {}; + IHttpResponse* pResponse = pContext.GetResponse(); + pResponse->SetStatus(500, "Internal Server Error", 0, hr, nullptr, true); + pResponse->SetHeader("Content-Type", + "text/html", + (USHORT)strlen("text/html"), + FALSE + ); + dataChunk.DataChunkType = HttpDataChunkFromMemory; + + dataChunk.FromMemory.pBuffer = s_html500Page.data(); + dataChunk.FromMemory.BufferLength = static_cast(s_html500Page.size()); + pResponse->WriteEntityChunkByReference(&dataChunk); + } + private: mutable LONG m_cRefs = 1; }; diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h index d44c6a25f8..fdee8b9578 100644 --- a/src/AspNetCoreModuleV2/CommonLib/resources.h +++ b/src/AspNetCoreModuleV2/CommonLib/resources.h @@ -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_CONFIGURATION_LOAD_ERROR_MSG L"Configuration load error. %s" +#define ASPNETCORE_CONFIGURATION_LOAD_ERROR_MSG L"Could not load configuration. Exception message: %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, exit code = '%d'. 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, exit code = '%d'. Please check the stderr logs for more information." @@ -39,9 +39,11 @@ #define ASPNETCORE_EVENT_RECYCLE_FAILURE_CONFIGURATION_MSG L"Failed to recycle application due to a configuration change at '%s'. Recycling worker process." #define ASPNETCORE_EVENT_MODULE_DISABLED_MSG L"AspNetCore Module is disabled" #define ASPNETCORE_EVENT_HOSTFXR_DLL_INVALID_VERSION_MSG L"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '%s'." +#define ASPNETCORE_EVENT_HOSTFXR_FAILURE_MSG L"Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. This most likely means the app is misconfigured, please check the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App that are targeted by the application and are installed on the machine." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Please check the stderr logs for more information." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, exception code = '0x%x'. Last 4KB characters of captured stdout and stderr logs:\r\n%s" -#define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application. Captured output: %s" +#define ASPNETCORE_EVENT_INPROCESS_RH_ERROR_MSG L"Could not find inprocess request handler. Captured output from invoking hostfxr: %s" +#define ASPNETCORE_EVENT_INPROCESS_RH_REFERENCE_MSG L"Could not find the assembly '%s' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application." #define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress." #define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully." #define ASPNETCORE_EVENT_INPROCESS_START_ERROR_MSG L"Application '%s' wasn't able to start. %s" diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc b/src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc new file mode 100644 index 0000000000..25a99683c5 Binary files /dev/null and b/src/AspNetCoreModuleV2/InProcessRequestHandler/HtmlResponses.rc differ diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj index f295280e4e..5e3fe5c6c1 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRequestHandler.vcxproj @@ -229,10 +229,10 @@ + - @@ -247,8 +247,6 @@ Create Create - - @@ -262,9 +260,13 @@ + + + true + diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm new file mode 100644 index 0000000000..4675db7cdb --- /dev/null +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/InProcessRhStaticHtml.htm @@ -0,0 +1,44 @@ + + + + + + + IIS 500.30 Error + + + +
+ +

HTTP Error 500.30 - ANCM In-Process Start Failure

+
+ +
+

Common causes of this issue:

+
    +
  • The application failed to start
  • +
  • The application started but then stopped
  • +
  • The application started but threw an exception during startup
  • +
+
+
+
+ +
+

Troubleshooting steps:

+
    +
  • Check the system event log for error messages
  • +
  • Enable logging the application process' stdout messages
  • +
  • Attach a debugger to the application process and inspect
  • +
+
+
+

+ For more information visit: + https://go.microsoft.com/fwlink/?LinkID=808681 +

+
+
+
+ + diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp deleted file mode 100644 index b198e95909..0000000000 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#include "StartupExceptionApplication.h" - -HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) -{ - *pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs); - return S_OK; -} diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h index d3505315be..7d8acc4e7e 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h @@ -4,7 +4,8 @@ #pragma once #include "InProcessApplicationBase.h" -#include "StartupExceptionHandler.h" +#include "ServerErrorHandler.h" +#include "resource.h" class StartupExceptionApplication : public InProcessApplicationBase { @@ -12,15 +13,24 @@ public: StartupExceptionApplication( IHttpServer& pServer, IHttpApplication& pApplication, - BOOL disableLogs) + HINSTANCE moduleInstance, + BOOL disableLogs, + HRESULT hr) : m_disableLogs(disableLogs), + m_HR(hr), + m_moduleInstance(moduleInstance), InProcessApplicationBase(pServer, pApplication) { } ~StartupExceptionApplication() = default; - HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override; + HRESULT + CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler) + { + *pRequestHandler = new ServerErrorHandler(*pHttpContext, m_HR,m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML); + return S_OK; + } std::string& GetStaticHtml500Content() @@ -31,5 +41,7 @@ public: private: std::string html500Page; BOOL m_disableLogs; + HRESULT m_HR; + HINSTANCE m_moduleInstance; }; diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp deleted file mode 100644 index d180460898..0000000000 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -#include "StartupExceptionApplication.h" -#include "StartupExceptionHandler.h" - -std::string StartupExceptionHandler::s_html500Page = " \ - \ - \ - \ - IIS 500.30 Error \ -
\ -

HTTP Error 500.30 - ANCM In-Process Start Failure

\ -
\ -

Common causes of this issue:

\ -
  • The application failed to start
  • \ -
  • The application started but then stopped
  • \ -
  • The application started but threw an exception during startup
\ -
\ -
\ -

Troubleshooting steps:

\ -
  • Check the system event log for error messages
  • \ -
  • Enable logging the application process' stdout messages
  • \ -
  • Attach a debugger to the application process and inspect
\ -

For more information visit: \ - https://go.microsoft.com/fwlink/?LinkID=808681

\ -
\ -
\ -
"; - -REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler() -{ - if (!m_disableLogs) - { - HTTP_DATA_CHUNK DataChunk; - IHttpResponse* pResponse = m_pContext->GetResponse(); - pResponse->SetStatus(500, "Internal Server Error", 30, E_FAIL, NULL, TRUE); - pResponse->SetHeader("Content-Type", - "text/html", - (USHORT)strlen("text/html"), - FALSE - ); - DataChunk.DataChunkType = HttpDataChunkFromMemory; - DataChunk.FromMemory.pBuffer = (PVOID)s_html500Page.c_str(); - DataChunk.FromMemory.BufferLength = (ULONG)s_html500Page.size(); - pResponse->WriteEntityChunkByReference(&DataChunk); - } - else - { - m_pContext->GetResponse()->SetStatus(500, "Internal Server Error", 30, E_FAIL); - } - - return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST; -} - diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h index 266474e1b5..1d0f3b7cc9 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionHandler.h @@ -3,31 +3,38 @@ #pragma once -#include #include "requesthandler.h" +#include "resource.h" +#include "file_utility.h" -class StartupExceptionApplication; class StartupExceptionHandler : public REQUEST_HANDLER { public: - StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs) - : - m_pContext(pContext), - m_disableLogs(disableLogs) + + StartupExceptionHandler(IHttpContext& pContext, BOOL disableLogs, HRESULT hr) + : m_pContext(pContext), + m_disableLogs(disableLogs), + m_HR(hr) { } + ~StartupExceptionHandler() { - } - REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override; + + REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() + { + static std::string s_html500Page = FILE_UTILITY::GetHtml(g_hModule, IN_PROCESS_SHIM_STATIC_HTML); + + WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableLogs); + + return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST; + } private: - IHttpContext * m_pContext; + IHttpContext& m_pContext; BOOL m_disableLogs; - - static - std::string s_html500Page; + HRESULT m_HR; }; diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp index 32a314dd50..49f2142fd4 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/dllmain.cpp @@ -6,7 +6,6 @@ #include #include "inprocessapplication.h" -#include "StartupExceptionApplication.h" #include "inprocesshandler.h" #include "requesthandler_config.h" #include "debugutil.h" @@ -17,6 +16,7 @@ #include "EventLog.h" #include "WebConfigConfigurationSource.h" #include "ConfigurationLoadException.h" +#include "StartupExceptionApplication.h" DECLARE_DEBUG_PRINT_OBJECT("aspnetcorev2_inprocess.dll"); @@ -28,6 +28,7 @@ HINSTANCE g_hWinHttpModule; HINSTANCE g_hAspNetCoreModule; HANDLE g_hEventLog = NULL; bool g_fInProcessApplicationCreated = false; +HINSTANCE g_hServerModule; HRESULT InitializeGlobalConfiguration( @@ -69,7 +70,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, ) { UNREFERENCED_PARAMETER(lpReserved); - + g_hServerModule = hModule; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: @@ -100,6 +101,7 @@ CreateApplication( { try { + HRESULT hr = S_OK; RETURN_IF_FAILED(InitializeGlobalConfiguration(pServer, pHttpApplication)); // In process application was already created so another call to CreateApplication @@ -114,7 +116,7 @@ CreateApplication( g_fInProcessApplicationCreated = true; std::unique_ptr inProcessApplication; - if (!FAILED_LOG(IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication))) + if (!FAILED_LOG(hr = IN_PROCESS_APPLICATION::Start(*pServer, *pHttpApplication, pParameters, nParameters, inProcessApplication))) { *ppApplication = inProcessApplication.release(); } @@ -123,7 +125,7 @@ CreateApplication( std::unique_ptr options; THROW_IF_FAILED(InProcessOptions::Create(*pServer, *pHttpApplication, options)); // Set the currently running application to a fake application that returns startup exceptions. - auto pErrorApplication = std::make_unique(*pServer, *pHttpApplication, options->QueryDisableStartUpErrorPage()); + auto pErrorApplication = std::make_unique(*pServer, *pHttpApplication, g_hServerModule, options->QueryDisableStartUpErrorPage(), hr); RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline()); *ppApplication = pErrorApplication.release(); diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h b/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h new file mode 100644 index 0000000000..61f67c2833 --- /dev/null +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by HtmlResponses.rc +// +#define IN_PROCESS_RH_STATIC_HTML 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index 76ce9a3800..a2c3360cf4 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { private const string DetailedErrorsEnvironmentVariable = "ASPNETCORE_DETAILEDERRORS"; - private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(10); + private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(60); private static readonly TimeSpan _retryDelay = TimeSpan.FromMilliseconds(200); private CancellationTokenSource _hostShutdownToken = new CancellationTokenSource(); diff --git a/test/Common.FunctionalTests/ConfigurationChangeTests.cs b/test/Common.FunctionalTests/ConfigurationChangeTests.cs index 014e2520c4..099cefb97a 100644 --- a/test/Common.FunctionalTests/ConfigurationChangeTests.cs +++ b/test/Common.FunctionalTests/ConfigurationChangeTests.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests await deploymentResult.HttpClient.RetryRequestAsync("/HelloWorld", r => r.StatusCode == HttpStatusCode.InternalServerError); StopServer(); - EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Could not find the assembly 'aspnetcorev2_inprocess.dll'"); + EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Could not find the assembly 'aspnetcorev2_inprocess.dll'", Logger); } [ConditionalTheory] diff --git a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs index 2d7de2a8f1..cf977b76f4 100644 --- a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs +++ b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs @@ -1,12 +1,14 @@ // 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.RegularExpressions; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; +using Microsoft.Extensions.Logging; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -21,6 +23,25 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests AssertSingleEntry(expectedRegexMatchString, entries); } + public static void VerifyEventLogEvent(IISDeploymentResult deploymentResult, string expectedRegexMatchString, ILogger logger) + { + Assert.True(deploymentResult.HostProcess.HasExited); + + var entries = GetEntries(deploymentResult); + try + { + AssertSingleEntry(expectedRegexMatchString, entries); + } + catch (Exception ex) + { + foreach (var entry in entries) + { + logger.LogInformation(entry.Message); + } + throw ex; + } + } + public static void VerifyEventLogEvents(IISDeploymentResult deploymentResult, params string[] expectedRegexMatchString) { Assert.True(deploymentResult.HostProcess.HasExited); @@ -149,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public static string ConfigurationLoadError(IISDeploymentResult deploymentResult, string reason) { - return $"Configuration load error. {reason}"; + return $"Could not load configuration. Exception message: {reason}"; } public static string OutOfProcessFailedToStart(IISDeploymentResult deploymentResult) @@ -159,6 +180,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests $"The last try of listening port is '(.*)'. See previous warnings for details."; } + public static string InProcessHostfxrInvalid(IISDeploymentResult deploymentResult) + { + return $"Hostfxr version used does not support 'hostfxr_get_native_search_directories', update the version of hostfxr to a higher version. Path to hostfxr: '(.*)'."; + } + + public static string InProcessFailedToFindNativeDependencies(IISDeploymentResult deploymentResult) + { + return "Invoking hostfxr to find the inprocess request handler failed without finding any native dependencies. " + + "This most likely means the app is misconfigured, please check the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App that " + + "are targeted by the application and are installed on the machine."; + } + + public static string InProcessFailedToFindRequestHandler(IISDeploymentResult deploymentResult) + { + return "Could not find the assembly '(.*)' referenced for the in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."; + } + private static string EscapedContentRoot(IISDeploymentResult deploymentResult) { var contentRoot = deploymentResult.ContentRoot; diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs index cb6779210a..8087b67b1d 100644 --- a/test/Common.FunctionalTests/Utilities/Helpers.cs +++ b/test/Common.FunctionalTests/Utilities/Helpers.cs @@ -12,6 +12,8 @@ using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -159,5 +161,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests return Directory.GetFiles(logFolderPath).Single(); } } + + public static void ModifyFrameworkVersionInRuntimeConfig(IISDeploymentResult deploymentResult) + { + var path = Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.runtimeconfig.json"); + dynamic depsFileContent = JsonConvert.DeserializeObject(File.ReadAllText(path)); + depsFileContent["runtimeOptions"]["framework"]["version"] = "2.9.9"; + var output = JsonConvert.SerializeObject(depsFileContent); + File.WriteAllText(path, output); + } } } diff --git a/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs b/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs index deab1d756b..9c89249d1e 100644 --- a/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs +++ b/test/IIS.FunctionalTests/Inprocess/StdOutRedirectionTests.cs @@ -32,7 +32,7 @@ namespace IIS.FunctionalTests.Inprocess var deploymentResult = await DeployAsync(deploymentParameters); - InvalidateRuntimeConfig(deploymentResult); + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); Assert.False(response.IsSuccessStatusCode); @@ -54,7 +54,7 @@ namespace IIS.FunctionalTests.Inprocess var deploymentResult = await DeployAsync(deploymentParameters); - InvalidateRuntimeConfig(deploymentResult); + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); Assert.False(response.IsSuccessStatusCode); @@ -146,14 +146,5 @@ namespace IIS.FunctionalTests.Inprocess EventLogHelpers.VerifyEventLogEvent(deploymentResult, "Invoked hostfxr"); Assert.Contains("Invoked hostfxr", contents); } - - private static void InvalidateRuntimeConfig(IISDeploymentResult deploymentResult) - { - var path = Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.runtimeconfig.json"); - dynamic depsFileContent = JsonConvert.DeserializeObject(File.ReadAllText(path)); - depsFileContent["runtimeOptions"]["framework"]["version"] = "2.9.9"; - var output = JsonConvert.SerializeObject(depsFileContent); - File.WriteAllText(path, output); - } } } diff --git a/test/IIS.FunctionalTests/RequiresIISAttribute.cs b/test/IIS.FunctionalTests/RequiresIISAttribute.cs index 507de60279..9fa3a7c502 100644 --- a/test/IIS.FunctionalTests/RequiresIISAttribute.cs +++ b/test/IIS.FunctionalTests/RequiresIISAttribute.cs @@ -151,8 +151,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests if (capabilities.HasFlag(IISCapability.ApplicationInitialization)) { - IsMet &= _dynamicCompressionAvailable; - if (!_dynamicCompressionAvailable) + IsMet &= _applicationInitializationModule; + if (!_applicationInitializationModule) { SkipReason += "The machine does not have IIS ApplicationInitialization installed."; } diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs index 227722e6ca..662aba0727 100644 --- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; +using Newtonsoft.Json; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -60,6 +61,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests StopServer(); EventLogHelpers.VerifyEventLogEvent(deploymentResult, $@"Application '{Regex.Escape(deploymentResult.ContentRoot)}\\' wasn't able to start. {subError}"); + + Assert.Contains("HTTP Error 500.0 - ANCM InProcess Startup Failure", await response.Content.ReadAsStringAsync()); } [ConditionalFact] @@ -185,6 +188,48 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests EventLogHelpers.InProcessThreadExit(deploymentResult, "12")); } + [ConditionalFact] + public async Task RemoveHostfxrFromApp_InProcessHostfxrInvalid() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + var deploymentResult = await DeployAsync(deploymentParameters); + + File.Copy( + Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll"), + Path.Combine(deploymentResult.ContentRoot, "hostfxr.dll"), + true); + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessHostfxrInvalid(deploymentResult), Logger); + } + + [ConditionalFact] + public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependencies() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + var deploymentResult = await DeployAsync(deploymentParameters); + + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); + } + + [ConditionalFact] + public async Task RemoveInProcessReference_FailedToFindRequestHandler() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + var deploymentResult = await DeployAsync(deploymentParameters); + + File.Delete(Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll")); + + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + + EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindRequestHandler(deploymentResult), Logger); + } + [ConditionalFact] public async Task StartupTimeoutIsApplied() { @@ -239,7 +284,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests StopServer(); EventLogHelpers.VerifyEventLogEvents(deploymentResult, - EventLogHelpers.FailedToStartApplication(deploymentResult, "0x80004005"), EventLogHelpers.ConfigurationLoadError(deploymentResult, "Unknown hosting model 'bogus'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file.") ); } @@ -259,8 +303,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); StopServer(); + EventLogHelpers.VerifyEventLogEvents(deploymentResult, - EventLogHelpers.FailedToStartApplication(deploymentResult, "0x80004005"), EventLogHelpers.ConfigurationLoadError(deploymentResult, expectedError) ); } @@ -407,5 +451,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } }); } + + private async Task AssertSiteFailsToStartWithInProcessStaticContent(IISDeploymentResult deploymentResult) + { + var response = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.Contains("HTTP Error 500.0 - ANCM InProcess Startup Failure", await response.Content.ReadAsStringAsync()); + StopServer(); + } } } diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index 674550f6fc..855096e026 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -64,6 +64,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest); Assert.False(response.IsSuccessStatusCode); + var responseString = await response.Content.ReadAsStringAsync(); + Assert.Contains("HTTP Error 500.0 - ANCM OutOfProcess Startup Failure", responseString); } [ConditionalTheory]