Skip to content

Commit 56c064b

Browse files
pakrymjkotalik
authored andcommitted
Display startup errors in ANCM (#8518)
1 parent eb41de8 commit 56c064b

27 files changed

+1408
-1115
lines changed

src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ private RequestDelegate BuildErrorPageApplication(Exception exception)
186186
{
187187
context.Response.StatusCode = 500;
188188
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
189+
context.Response.ContentType = "text/html; charset=utf-8";
189190
return errorPage.ExecuteAsync(context);
190191
};
191192
}

src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<ItemGroup>
1313
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" />
1414
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" />
15+
<Compile Include="$(SharedSourceRoot)ErrorPage\**\*.cs" />
1516
</ItemGroup>
1617

1718
<ItemGroup>

src/Hosting/Hosting/src/Resources.resx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,6 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120-
<data name="ErrorPageHtml_Title" xml:space="preserve">
121-
<value>Internal Server Error</value>
122-
</data>
123-
<data name="ErrorPageHtml_UnhandledException" xml:space="preserve">
124-
<value>An error occurred while starting the application.</value>
125-
</data>
126-
<data name="ErrorPageHtml_UnknownLocation" xml:space="preserve">
127-
<value>Unknown location</value>
128-
</data>
129120
<data name="WebHostBuilder_SingleInstance" xml:space="preserve">
130121
<value>WebHostBuilder allows creation only of a single instance of WebHost</value>
131122
</data>

src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY L"setCurrentDirectory"
2929
#define CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE L"disableStartUpErrorPage"
3030
#define CS_ENABLED L"enabled"
31+
#define CS_ASPNETCORE_HANDLER_CALL_STARTUP_HOOK L"callStartupHook"
3132

3233
class ConfigurationSection: NonCopyable
3334
{

src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ServerErrorHandler.h

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,34 @@
99
class ServerErrorHandler : public REQUEST_HANDLER
1010
{
1111
public:
12+
ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page) noexcept
13+
: ServerErrorHandler(pContext, statusCode, subStatusCode, statusText, hr, module, disableStartupPage, page, std::vector<byte>())
14+
{
15+
}
1216

13-
ServerErrorHandler(IHttpContext &pContext, USHORT statusCode, USHORT subStatusCode, std::string statusText, HRESULT hr, HINSTANCE moduleInstance, bool disableStartupPage, int page) noexcept
17+
ServerErrorHandler(IHttpContext& pContext, USHORT statusCode, USHORT subStatusCode, const std::string& statusText, HRESULT hr, HINSTANCE module, bool disableStartupPage, int page, const std::vector<byte>& content) noexcept
1418
: REQUEST_HANDLER(pContext),
15-
m_pContext(pContext),
16-
m_HR(hr),
17-
m_disableStartupPage(disableStartupPage),
18-
m_page(page),
19-
m_moduleInstance(moduleInstance),
20-
m_statusCode(statusCode),
21-
m_subStatusCode(subStatusCode),
22-
m_statusText(std::move(statusText))
19+
m_pContext(pContext),
20+
m_HR(hr),
21+
m_disableStartupPage(disableStartupPage),
22+
m_statusCode(statusCode),
23+
m_subStatusCode(subStatusCode),
24+
m_statusText(std::move(statusText)),
25+
m_page(page),
26+
m_ExceptionInfoContent(content),
27+
m_moduleInstance(module)
2328
{
2429
}
2530

2631
REQUEST_NOTIFICATION_STATUS ExecuteRequestHandler() override
2732
{
28-
static std::string s_html500Page = GetHtml(m_moduleInstance, m_page);
29-
30-
WriteStaticResponse(m_pContext, s_html500Page, m_HR, m_disableStartupPage);
33+
WriteStaticResponse(m_pContext, m_HR, m_disableStartupPage);
3134

3235
return RQ_NOTIFICATION_FINISH_REQUEST;
3336
}
3437

3538
private:
36-
void WriteStaticResponse(IHttpContext& pContext, std::string &page, HRESULT hr, bool disableStartupErrorPage) const
39+
void WriteStaticResponse(IHttpContext& pContext, HRESULT hr, bool disableStartupErrorPage)
3740
{
3841
if (disableStartupErrorPage)
3942
{
@@ -49,14 +52,23 @@ class ServerErrorHandler : public REQUEST_HANDLER
4952
(USHORT)strlen("text/html"),
5053
FALSE
5154
);
52-
dataChunk.DataChunkType = HttpDataChunkFromMemory;
5355

54-
dataChunk.FromMemory.pBuffer = page.data();
55-
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(page.size());
56+
dataChunk.DataChunkType = HttpDataChunkFromMemory;
57+
if (m_ExceptionInfoContent.size() > 0)
58+
{
59+
dataChunk.FromMemory.pBuffer = &m_ExceptionInfoContent[0];
60+
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(m_ExceptionInfoContent.size());
61+
}
62+
else
63+
{
64+
static std::string s_html500Page = GetHtml(m_moduleInstance, m_page);
65+
dataChunk.FromMemory.pBuffer = s_html500Page.data();
66+
dataChunk.FromMemory.BufferLength = static_cast<ULONG>(s_html500Page.size());
67+
}
68+
5669
pResponse->WriteEntityChunkByReference(&dataChunk);
5770
}
5871

59-
static
6072
std::string
6173
GetHtml(HMODULE module, int page)
6274
{
@@ -91,12 +103,13 @@ class ServerErrorHandler : public REQUEST_HANDLER
91103
}
92104
}
93105

94-
IHttpContext &m_pContext;
106+
IHttpContext& m_pContext;
95107
HRESULT m_HR;
96108
bool m_disableStartupPage;
97109
int m_page;
98110
HINSTANCE m_moduleInstance;
99111
USHORT m_statusCode;
100112
USHORT m_subStatusCode;
101113
std::string m_statusText;
114+
std::vector<byte> m_ExceptionInfoContent;
102115
};

src/Servers/IIS/AspNetCoreModuleV2/CommonLibTests/inprocess_application_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ using ::testing::NiceMock;
1313
// Externals defined in inprocess
1414
BOOL g_fProcessDetach;
1515
HANDLE g_hEventLog;
16+
std::wstring g_exceptionEventLog;
1617

1718
namespace InprocessTests
1819
{
Binary file not shown.

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ InProcessOptions::InProcessOptions(const ConfigurationSource &configurationSourc
5757

5858
const auto handlerSettings = aspNetCoreSection->GetKeyValuePairs(CS_ASPNETCORE_HANDLER_SETTINGS);
5959
m_fSetCurrentDirectory = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_SET_CURRENT_DIRECTORY).value_or(L"true"), L"true");
60+
m_fCallStartupHook = equals_ignore_case(find_element(handlerSettings, CS_ASPNETCORE_HANDLER_CALL_STARTUP_HOOK).value_or(L"true"), L"true");
6061

6162
m_dwStartupTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_STARTUP_TIME_LIMIT) * 1000;
6263
m_dwShutdownTimeLimitInMS = aspNetCoreSection->GetRequiredLong(CS_ASPNETCORE_PROCESS_SHUTDOWN_TIME_LIMIT) * 1000;

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class InProcessOptions: NonCopyable
4848
return m_fSetCurrentDirectory;
4949
}
5050

51+
bool
52+
QueryCallStartupHook() const
53+
{
54+
return m_fCallStartupHook;
55+
}
56+
5157
bool
5258
QueryWindowsAuthEnabled() const
5359
{
@@ -116,6 +122,7 @@ class InProcessOptions: NonCopyable
116122
bool m_fStdoutLogEnabled;
117123
bool m_fDisableStartUpErrorPage;
118124
bool m_fSetCurrentDirectory;
125+
bool m_fCallStartupHook;
119126
bool m_fWindowsAuthEnabled;
120127
bool m_fBasicAuthEnabled;
121128
bool m_fAnonymousAuthEnabled;

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/StartupExceptionApplication.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,28 @@ class StartupExceptionApplication : public InProcessApplicationBase
1515
IHttpApplication& pApplication,
1616
HINSTANCE moduleInstance,
1717
BOOL disableLogs,
18-
HRESULT hr)
18+
HRESULT hr,
19+
std::vector<byte>&& errorPageContent
20+
)
1921
: m_disableLogs(disableLogs),
2022
m_HR(hr),
2123
m_moduleInstance(moduleInstance),
24+
m_errorPageContent(std::move(errorPageContent)),
2225
InProcessApplicationBase(pServer, pApplication)
2326
{
2427
}
2528

2629
~StartupExceptionApplication() = default;
2730

28-
HRESULT CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler)
31+
HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler)
2932
{
30-
*pRequestHandler = new ServerErrorHandler(*pHttpContext, 500, 30, "Internal Server Error", m_HR, m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML);
31-
return S_OK;
32-
}
33+
*pRequestHandler = new ServerErrorHandler(*pHttpContext, 500, 30, "Internal Server Error", m_HR, m_moduleInstance, m_disableLogs, IN_PROCESS_RH_STATIC_HTML, m_errorPageContent);
3334

34-
std::string&
35-
GetStaticHtml500Content()
36-
{
37-
return html500Page;
35+
return S_OK;
3836
}
3937

4038
private:
41-
std::string html500Page;
39+
std::vector<byte> m_errorPageContent;
4240
BOOL m_disableLogs;
4341
HRESULT m_HR;
4442
HINSTANCE m_moduleInstance;

0 commit comments

Comments
 (0)