Finish up appoffline refactoring (#1018)
This commit is contained in:
parent
cbfd791d7b
commit
f7936ac062
|
|
@ -226,11 +226,9 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Inc\applicationinfo.h" />
|
||||
<ClInclude Include="Inc\appoffline.h" />
|
||||
<ClInclude Include="Inc\aspnetcore_shim_config.h" />
|
||||
<ClInclude Include="inc\globalmodule.h" />
|
||||
<ClInclude Include="Inc\applicationmanager.h" />
|
||||
<ClInclude Include="Inc\filewatcher.h" />
|
||||
<ClInclude Include="Inc\proxymodule.h" />
|
||||
<ClInclude Include="Inc\precomp.hxx" />
|
||||
</ItemGroup>
|
||||
|
|
@ -239,7 +237,6 @@
|
|||
<ClCompile Include="Src\applicationmanager.cxx" />
|
||||
<ClCompile Include="src\aspnetcore_shim_config.cpp" />
|
||||
<ClCompile Include="Src\dllmain.cpp" />
|
||||
<ClCompile Include="Src\filewatcher.cxx" />
|
||||
<ClCompile Include="src\globalmodule.cpp" />
|
||||
<ClCompile Include="src\precomp.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
|
|
|
|||
|
|
@ -3,17 +3,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <httpserv.h>
|
||||
|
||||
#include "hostfxroptions.h"
|
||||
#include "appoffline.h"
|
||||
#include "filewatcher.h"
|
||||
#include "hashtable.h"
|
||||
#include "hashfn.h"
|
||||
#include "aspnetcore_shim_config.h"
|
||||
#include "iapplication.h"
|
||||
#include "SRWSharedLock.h"
|
||||
#include "ntassert.h"
|
||||
|
||||
#define API_BUFFER_TOO_SMALL 0x80008098
|
||||
|
||||
|
|
@ -37,11 +32,8 @@ public:
|
|||
APPLICATION_INFO() :
|
||||
m_pServer(NULL),
|
||||
m_cRefs(1),
|
||||
m_fAppOfflineFound(FALSE),
|
||||
m_fValid(FALSE),
|
||||
m_fDoneAppCreation(FALSE),
|
||||
m_pAppOfflineHtm(NULL),
|
||||
m_pFileWatcherEntry(NULL),
|
||||
m_fAppCreationAttempted(FALSE),
|
||||
m_pConfiguration(NULL),
|
||||
m_pfnAspNetCoreCreateApplication(NULL)
|
||||
{
|
||||
|
|
@ -60,8 +52,7 @@ public:
|
|||
HRESULT
|
||||
Initialize(
|
||||
_In_ IHttpServer *pServer,
|
||||
_In_ IHttpApplication *pApplication,
|
||||
_In_ FILE_WATCHER *pFileWatcher
|
||||
_In_ IHttpApplication *pApplication
|
||||
);
|
||||
|
||||
VOID
|
||||
|
|
@ -79,18 +70,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
APP_OFFLINE_HTM*
|
||||
QueryAppOfflineHtm()
|
||||
{
|
||||
return m_pAppOfflineHtm;
|
||||
}
|
||||
|
||||
BOOL
|
||||
AppOfflineFound()
|
||||
{
|
||||
return m_fAppOfflineFound;
|
||||
}
|
||||
|
||||
BOOL
|
||||
IsValid()
|
||||
{
|
||||
|
|
@ -103,19 +82,12 @@ public:
|
|||
m_fValid = TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
UpdateAppOfflineFileHandle();
|
||||
|
||||
HRESULT
|
||||
StartMonitoringAppOffline();
|
||||
|
||||
ASPNETCORE_SHIM_CONFIG*
|
||||
QueryConfig()
|
||||
{
|
||||
return m_pConfiguration;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExtractApplication will increase the reference counter of the application
|
||||
// Caller is responsible for dereference the application.
|
||||
|
|
@ -152,11 +124,8 @@ private:
|
|||
|
||||
mutable LONG m_cRefs;
|
||||
STRU m_struInfoKey;
|
||||
BOOL m_fAppOfflineFound;
|
||||
BOOL m_fValid;
|
||||
BOOL m_fDoneAppCreation;
|
||||
APP_OFFLINE_HTM *m_pAppOfflineHtm;
|
||||
FILE_WATCHER_ENTRY *m_pFileWatcherEntry;
|
||||
BOOL m_fAppCreationAttempted;
|
||||
ASPNETCORE_SHIM_CONFIG *m_pConfiguration;
|
||||
IAPPLICATION *m_pApplication;
|
||||
SRWLOCK m_srwLock;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "applicationinfo.h"
|
||||
#include "multisz.h"
|
||||
#include "filewatcher.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#define DEFAULT_HASH_BUCKETS 17
|
||||
|
||||
|
|
@ -83,11 +83,6 @@ public:
|
|||
|
||||
~APPLICATION_MANAGER()
|
||||
{
|
||||
if (m_pFileWatcher != NULL)
|
||||
{
|
||||
delete m_pFileWatcher;
|
||||
m_pFileWatcher = NULL;
|
||||
}
|
||||
|
||||
if(m_pApplicationInfoHash != NULL)
|
||||
{
|
||||
|
|
@ -97,41 +92,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
FILE_WATCHER*
|
||||
GetFileWatcher()
|
||||
{
|
||||
return m_pFileWatcher;
|
||||
}
|
||||
|
||||
HRESULT Initialize()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(m_pApplicationInfoHash == NULL)
|
||||
{
|
||||
m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
|
||||
|
||||
hr = m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS);
|
||||
if(FAILED(hr))
|
||||
try
|
||||
{
|
||||
goto Finished;
|
||||
m_pApplicationInfoHash = new APPLICATION_INFO_HASH();
|
||||
}
|
||||
CATCH_RETURN();
|
||||
RETURN_IF_FAILED(m_pApplicationInfoHash->Initialize(DEFAULT_HASH_BUCKETS));
|
||||
}
|
||||
|
||||
if( m_pFileWatcher == NULL )
|
||||
{
|
||||
m_pFileWatcher = new FILE_WATCHER;
|
||||
if(m_pFileWatcher == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
m_pFileWatcher->Create();
|
||||
}
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -139,13 +111,11 @@ private:
|
|||
// we currently limit the size of m_pstrErrorInfo to 5000, be careful if you want to change its payload
|
||||
//
|
||||
APPLICATION_MANAGER() : m_pApplicationInfoHash(NULL),
|
||||
m_pFileWatcher(NULL),
|
||||
m_hostingModel(HOSTING_UNKNOWN)
|
||||
m_hostingModel(HOSTING_UNKNOWN)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
||||
FILE_WATCHER *m_pFileWatcher;
|
||||
APPLICATION_INFO_HASH *m_pApplicationInfoHash;
|
||||
static APPLICATION_MANAGER *sm_pApplicationManager;
|
||||
SRWLOCK m_srwLock;
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stringa.h"
|
||||
#include "stringu.h"
|
||||
|
||||
class APP_OFFLINE_HTM
|
||||
{
|
||||
public:
|
||||
APP_OFFLINE_HTM(LPCWSTR pszPath) : m_cRefs(1)
|
||||
{
|
||||
m_Path.Copy(pszPath);
|
||||
}
|
||||
|
||||
VOID
|
||||
ReferenceAppOfflineHtm() const
|
||||
{
|
||||
InterlockedIncrement(&m_cRefs);
|
||||
}
|
||||
|
||||
VOID
|
||||
DereferenceAppOfflineHtm() const
|
||||
{
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
Load(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
BOOL fResult = TRUE;
|
||||
LARGE_INTEGER li = { 0 };
|
||||
CHAR *pszBuff = NULL;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
handle = CreateFile(m_Path.QueryStr(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (HRESULT_FROM_WIN32(GetLastError()) == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
fResult = FALSE;
|
||||
}
|
||||
|
||||
// This Load() member function is supposed be called only when the change notification event of file creation or file modification happens.
|
||||
// If file is currenlty locked exclusively by other processes, we might get INVALID_HANDLE_VALUE even though the file exists. In that case, we should return TRUE here.
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (!GetFileSizeEx(handle, &li))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
if (li.HighPart != 0)
|
||||
{
|
||||
// > 4gb file size not supported
|
||||
// todo: log a warning at event log
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
if (li.LowPart > 0)
|
||||
{
|
||||
pszBuff = new CHAR[li.LowPart + 1];
|
||||
|
||||
if (ReadFile(handle, pszBuff, li.LowPart, &bytesRead, NULL))
|
||||
{
|
||||
m_Contents.Copy(pszBuff, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (pszBuff != NULL)
|
||||
{
|
||||
delete[] pszBuff;
|
||||
pszBuff = NULL;
|
||||
}
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
STRA m_Contents;
|
||||
STRU m_Path;
|
||||
};
|
||||
|
|
@ -16,8 +16,9 @@
|
|||
#include <Windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <httpserv.h>
|
||||
#include <ntassert.h>
|
||||
#include "stringu.h"
|
||||
#include "stringu.h"
|
||||
#include "stringa.h"
|
||||
|
||||
extern PVOID g_pModuleId;
|
||||
extern BOOL g_fAspnetcoreRHAssemblyLoaded;
|
||||
|
|
|
|||
|
|
@ -12,29 +12,14 @@
|
|||
#include "SRWExclusiveLock.h"
|
||||
#include "GlobalVersionUtility.h"
|
||||
#include "exceptions.h"
|
||||
#include "HandleWrapper.h"
|
||||
#include "PollingAppOfflineApplication.h"
|
||||
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll";
|
||||
const PCWSTR APPLICATION_INFO::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll";
|
||||
|
||||
APPLICATION_INFO::~APPLICATION_INFO()
|
||||
{
|
||||
if (m_pAppOfflineHtm != NULL)
|
||||
{
|
||||
m_pAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
m_pAppOfflineHtm = NULL;
|
||||
}
|
||||
|
||||
if (m_pFileWatcherEntry != NULL)
|
||||
{
|
||||
// Mark the entry as invalid,
|
||||
// StopMonitor will close the file handle and trigger a FCN
|
||||
// the entry will delete itself when processing this FCN
|
||||
m_pFileWatcherEntry->MarkEntryInValid();
|
||||
m_pFileWatcherEntry->StopMonitor();
|
||||
m_pFileWatcherEntry->DereferenceFileWatcherEntry();
|
||||
m_pFileWatcherEntry = NULL;
|
||||
}
|
||||
|
||||
if (m_pApplication != NULL)
|
||||
{
|
||||
// shutdown the application
|
||||
|
|
@ -55,118 +40,24 @@ APPLICATION_INFO::~APPLICATION_INFO()
|
|||
HRESULT
|
||||
APPLICATION_INFO::Initialize(
|
||||
_In_ IHttpServer *pServer,
|
||||
_In_ IHttpApplication *pApplication,
|
||||
_In_ FILE_WATCHER *pFileWatcher
|
||||
_In_ IHttpApplication *pApplication
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
DBG_ASSERT(pServer);
|
||||
DBG_ASSERT(pApplication);
|
||||
DBG_ASSERT(pFileWatcher);
|
||||
|
||||
// todo: make sure Initialize should be called only once
|
||||
m_pServer = pServer;
|
||||
FINISHED_IF_NULL_ALLOC(m_pConfiguration = new ASPNETCORE_SHIM_CONFIG());
|
||||
FINISHED_IF_FAILED(m_pConfiguration->Populate(m_pServer, pApplication));
|
||||
FINISHED_IF_FAILED(m_struInfoKey.Copy(pApplication->GetApplicationId()));
|
||||
FINISHED_IF_NULL_ALLOC(m_pFileWatcherEntry = new FILE_WATCHER_ENTRY(pFileWatcher));
|
||||
|
||||
UpdateAppOfflineFileHandle();
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::StartMonitoringAppOffline()
|
||||
{
|
||||
if (m_pFileWatcherEntry != NULL)
|
||||
{
|
||||
RETURN_IF_FAILED(m_pFileWatcherEntry->Create(m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(), L"app_offline.htm", this, NULL));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Called by the file watcher when the app_offline.htm's file status has been changed.
|
||||
// If it finds it, we will call recycle on the application.
|
||||
//
|
||||
VOID
|
||||
APPLICATION_INFO::UpdateAppOfflineFileHandle()
|
||||
{
|
||||
STRU strFilePath;
|
||||
UTILITY::ConvertPathToFullPath(L".\\app_offline.htm",
|
||||
m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr(),
|
||||
&strFilePath);
|
||||
APP_OFFLINE_HTM *pOldAppOfflineHtm = NULL;
|
||||
APP_OFFLINE_HTM *pNewAppOfflineHtm = NULL;
|
||||
|
||||
ReferenceApplicationInfo();
|
||||
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(strFilePath.QueryStr()))
|
||||
{
|
||||
// Check if app offline was originally present.
|
||||
// if it was, log that app_offline has been dropped.
|
||||
if (m_fAppOfflineFound)
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG);
|
||||
}
|
||||
|
||||
m_fAppOfflineFound = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNewAppOfflineHtm = new APP_OFFLINE_HTM(strFilePath.QueryStr());
|
||||
|
||||
if (pNewAppOfflineHtm != NULL)
|
||||
{
|
||||
if (pNewAppOfflineHtm->Load())
|
||||
{
|
||||
//
|
||||
// loaded the new app_offline.htm
|
||||
//
|
||||
pOldAppOfflineHtm = (APP_OFFLINE_HTM *)InterlockedExchangePointer((VOID**)&m_pAppOfflineHtm, pNewAppOfflineHtm);
|
||||
|
||||
if (pOldAppOfflineHtm != NULL)
|
||||
{
|
||||
pOldAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pOldAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignored the new app_offline file because the file does not exist.
|
||||
pNewAppOfflineHtm->DereferenceAppOfflineHtm();
|
||||
pNewAppOfflineHtm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_fAppOfflineFound = TRUE;
|
||||
|
||||
// recycle the application
|
||||
if (m_pApplication != NULL)
|
||||
{
|
||||
STACK_STRU(strEventMsg, 256);
|
||||
if (SUCCEEDED(strEventMsg.SafeSnwprintf(
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
||||
m_pConfiguration->QueryApplicationPhysicalPath()->QueryStr())))
|
||||
{
|
||||
UTILITY::LogEvent(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
||||
strEventMsg.QueryStr());
|
||||
}
|
||||
|
||||
RecycleApplication();
|
||||
}
|
||||
}
|
||||
|
||||
DereferenceApplicationInfo();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
APPLICATION_INFO::EnsureApplicationCreated(
|
||||
|
|
@ -179,57 +70,68 @@ APPLICATION_INFO::EnsureApplicationCreated(
|
|||
STRU struHostFxrDllLocation;
|
||||
STACK_STRU(struFileName, 300); // >MAX_PATH
|
||||
|
||||
if (m_pApplication != NULL)
|
||||
if (m_pApplication != nullptr && m_pApplication->QueryStatus() != RECYCLED)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// one optimization for failure scenario is to reduce the lock scope
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
|
||||
if (m_pApplication != nullptr)
|
||||
{
|
||||
if (m_pApplication != NULL)
|
||||
if (m_pApplication->QueryStatus() == RECYCLED)
|
||||
{
|
||||
// another thread created the applicaiton
|
||||
FINISHED(S_OK);
|
||||
LOG_INFO("Application went offline");
|
||||
// Application that went offline
|
||||
// are supposed to recycle themselves
|
||||
m_pApplication->DereferenceApplication();
|
||||
m_pApplication = nullptr;
|
||||
}
|
||||
else if (m_fDoneAppCreation)
|
||||
else
|
||||
{
|
||||
// previous CreateApplication failed
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
// another thread created the application
|
||||
FINISHED(S_OK);
|
||||
}
|
||||
}
|
||||
else if (m_fAppCreationAttempted)
|
||||
{
|
||||
// previous CreateApplication failed
|
||||
FINISHED(E_APPLICATION_ACTIVATION_EXEC_FAILURE);
|
||||
}
|
||||
|
||||
auto& httpApplication = *pHttpContext->GetApplication();
|
||||
if (PollingAppOfflineApplication::ShouldBeStarted(httpApplication))
|
||||
{
|
||||
LOG_INFO("Detected app_ofline file, creating polling application");
|
||||
m_pApplication = new PollingAppOfflineApplication(httpApplication);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move the request handler check inside of the lock
|
||||
// such that only one request finds and loads it.
|
||||
// FindRequestHandlerAssembly obtains a global lock, but after releasing the lock,
|
||||
// there is a period where we could call
|
||||
|
||||
m_fAppCreationAttempted = TRUE;
|
||||
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
|
||||
|
||||
if (m_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
|
||||
}
|
||||
|
||||
//
|
||||
// in case of app offline, we don't want to create a new application now
|
||||
//
|
||||
if (!m_fAppOfflineFound)
|
||||
{
|
||||
// Move the request handler check inside of the lock
|
||||
// such that only one request finds and loads it.
|
||||
// FindRequestHandlerAssembly obtains a global lock, but after releasing the lock,
|
||||
// there is a period where we could call
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
{"InProcessExeLocation", struExeLocation.QueryStr()}
|
||||
};
|
||||
LOG_INFO("Creating handler application");
|
||||
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
|
||||
m_pServer,
|
||||
pHttpContext->GetApplication(),
|
||||
parameters.data(),
|
||||
static_cast<DWORD>(parameters.size()),
|
||||
&pApplication));
|
||||
|
||||
m_fDoneAppCreation = TRUE;
|
||||
FINISHED_IF_FAILED(FindRequestHandlerAssembly(struExeLocation));
|
||||
|
||||
if (m_pfnAspNetCoreCreateApplication == NULL)
|
||||
{
|
||||
FINISHED(HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION));
|
||||
}
|
||||
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
{"InProcessExeLocation", struExeLocation.QueryStr()}
|
||||
};
|
||||
|
||||
FINISHED_IF_FAILED(m_pfnAspNetCoreCreateApplication(
|
||||
m_pServer,
|
||||
pHttpContext->GetApplication(),
|
||||
parameters.data(),
|
||||
static_cast<DWORD>(parameters.size()),
|
||||
&pApplication));
|
||||
|
||||
m_pApplication = pApplication;
|
||||
}
|
||||
m_pApplication = pApplication;
|
||||
}
|
||||
|
||||
Finished:
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
{
|
||||
pApplicationInfo = new APPLICATION_INFO();
|
||||
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pServer, pHttpContext->GetApplication(), m_pFileWatcher));
|
||||
FINISHED_IF_FAILED(pApplicationInfo->Initialize(pServer, pHttpContext->GetApplication()));
|
||||
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
|
||||
|
|
@ -102,10 +102,7 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo(
|
|||
|
||||
FINISHED_IF_FAILED(m_pApplicationInfoHash->InsertRecord(pApplicationInfo));
|
||||
|
||||
|
||||
*ppApplicationInfo = pApplicationInfo;
|
||||
pApplicationInfo->StartMonitoringAppOffline();
|
||||
|
||||
pApplicationInfo = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -323,12 +320,6 @@ APPLICATION_MANAGER::ShutDown()
|
|||
g_fInShutdown = TRUE;
|
||||
if (m_pApplicationInfoHash != NULL)
|
||||
{
|
||||
if (m_pFileWatcher != NULL)
|
||||
{
|
||||
delete m_pFileWatcher;
|
||||
m_pFileWatcher = NULL;
|
||||
}
|
||||
|
||||
DBG_ASSERT(m_pApplicationInfoHash);
|
||||
|
||||
// During shutdown we lock until we delete the application
|
||||
|
|
|
|||
|
|
@ -107,37 +107,6 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
|||
goto Finished;
|
||||
}
|
||||
|
||||
// app_offline check to avoid loading aspnetcorerh.dll unnecessarily
|
||||
if (m_pApplicationInfo->AppOfflineFound())
|
||||
{
|
||||
// servicing app_offline
|
||||
HTTP_DATA_CHUNK DataChunk;
|
||||
IHttpResponse *pResponse = NULL;
|
||||
APP_OFFLINE_HTM *pAppOfflineHtm = NULL;
|
||||
|
||||
pResponse = pHttpContext->GetResponse();
|
||||
pAppOfflineHtm = m_pApplicationInfo->QueryAppOfflineHtm();
|
||||
DBG_ASSERT(pAppOfflineHtm);
|
||||
DBG_ASSERT(pResponse);
|
||||
|
||||
// Ignore failure hresults as nothing we can do
|
||||
// Set fTrySkipCustomErrors to true as we want client see the offline content
|
||||
pResponse->SetStatus(503, "Service Unavailable", 0, hr, NULL, TRUE);
|
||||
pResponse->SetHeader("Content-Type",
|
||||
"text/html",
|
||||
(USHORT)strlen("text/html"),
|
||||
FALSE
|
||||
);
|
||||
|
||||
DataChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
DataChunk.FromMemory.pBuffer = (PVOID)pAppOfflineHtm->m_Contents.QueryStr();
|
||||
DataChunk.FromMemory.BufferLength = pAppOfflineHtm->m_Contents.QueryCB();
|
||||
pResponse->WriteEntityChunkByReference(&DataChunk);
|
||||
|
||||
retVal = RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// make sure assmebly is loaded and application is created
|
||||
hr = m_pApplicationInfo->EnsureApplicationCreated(pHttpContext);
|
||||
if (FAILED(hr))
|
||||
|
|
@ -147,18 +116,18 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
|
|||
|
||||
m_pApplicationInfo->ExtractApplication(&pApplication);
|
||||
|
||||
// make sure application is in running state
|
||||
// cannot recreate the application as we cannot reload clr for inprocess
|
||||
if (pApplication != NULL &&
|
||||
pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
|
||||
DBG_ASSERT(pHttpContext);
|
||||
|
||||
// We allow OFFLINE application to serve pages
|
||||
if (pApplication->QueryStatus() != APPLICATION_STATUS::RUNNING &&
|
||||
pApplication->QueryStatus() != APPLICATION_STATUS::STARTING)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
// Create RequestHandler and process the request
|
||||
hr = pApplication->CreateHandler(pHttpContext,
|
||||
&m_pHandler);
|
||||
hr = pApplication->CreateHandler(pHttpContext, &m_pHandler);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@
|
|||
<ClInclude Include="debugutil.h" />
|
||||
<ClInclude Include="disconnectcontext.h" />
|
||||
<ClInclude Include="irequesthandler.h" />
|
||||
<ClInclude Include="PollingAppOfflineApplication.h" />
|
||||
<ClInclude Include="requesthandler.h" />
|
||||
<ClInclude Include="resources.h" />
|
||||
<ClInclude Include="SRWExclusiveLock.h" />
|
||||
|
|
@ -221,6 +222,7 @@
|
|||
<ClCompile Include="HandleWrapper.cpp" />
|
||||
<ClCompile Include="hostfxr_utility.cpp" />
|
||||
<ClCompile Include="hostfxroptions.cpp" />
|
||||
<ClCompile Include="PollingAppOfflineApplication.cpp" />
|
||||
<ClCompile Include="SRWExclusiveLock.cpp" />
|
||||
<ClCompile Include="SRWSharedLock.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
// 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 "PollingAppOfflineApplication.h"
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include "SRWExclusiveLock.h"
|
||||
#include "HandleWrapper.h"
|
||||
|
||||
HRESULT PollingAppOfflineApplication::CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler)
|
||||
{
|
||||
try
|
||||
{
|
||||
*pRequestHandler = new PollingAppOfflineHandler(pHttpContext, m_strAppOfflineContent);
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
APPLICATION_STATUS PollingAppOfflineApplication::QueryStatus()
|
||||
{
|
||||
if (AppOfflineExists())
|
||||
{
|
||||
return APPLICATION_STATUS::RUNNING;
|
||||
}
|
||||
|
||||
return APPLICATION_STATUS::RECYCLED;
|
||||
}
|
||||
|
||||
bool
|
||||
PollingAppOfflineApplication::AppOfflineExists()
|
||||
{
|
||||
const auto ulCurrentTime = GetTickCount64();
|
||||
//
|
||||
// we only care about app offline presented. If not, it means the application has started
|
||||
// and is monitoring the app offline file
|
||||
// we cache the file exist check result for 1 second
|
||||
//
|
||||
if (ulCurrentTime - m_ulLastCheckTime > c_appOfflineRefreshIntervalMS)
|
||||
{
|
||||
SRWExclusiveLock lock(m_statusLock);
|
||||
if (ulCurrentTime - m_ulLastCheckTime > c_appOfflineRefreshIntervalMS)
|
||||
{
|
||||
m_fAppOfflineFound = is_regular_file(m_appOfflineLocation);
|
||||
if(m_fAppOfflineFound)
|
||||
{
|
||||
LOG_IF_FAILED(LoadAppOfflineContent());
|
||||
}
|
||||
m_ulLastCheckTime = ulCurrentTime;
|
||||
}
|
||||
}
|
||||
return m_fAppOfflineFound;
|
||||
}
|
||||
|
||||
HRESULT PollingAppOfflineApplication::LoadAppOfflineContent()
|
||||
{
|
||||
LARGE_INTEGER li = {};
|
||||
|
||||
HandleWrapper<InvalidHandleTraits> handle = CreateFile(m_appOfflineLocation.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
RETURN_LAST_ERROR_IF(handle == INVALID_HANDLE_VALUE);
|
||||
|
||||
RETURN_LAST_ERROR_IF (!GetFileSizeEx(handle, &li));
|
||||
|
||||
if (li.HighPart != 0)
|
||||
{
|
||||
// > 4gb file size not supported
|
||||
// todo: log a warning at event log
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (li.LowPart > 0)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
std::string pszBuff(li.LowPart + 1, '\0');
|
||||
|
||||
RETURN_LAST_ERROR_IF(!ReadFile(handle, pszBuff.data(), li.LowPart, &bytesRead, NULL));
|
||||
pszBuff.resize(bytesRead);
|
||||
|
||||
m_strAppOfflineContent = pszBuff;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool PollingAppOfflineApplication::ShouldBeStarted(IHttpApplication& pApplication)
|
||||
{
|
||||
return is_regular_file(GetAppOfflineLocation(pApplication));
|
||||
}
|
||||
|
||||
std::experimental::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(IHttpApplication& pApplication)
|
||||
{
|
||||
return std::experimental::filesystem::path(pApplication.GetApplicationPhysicalPath()) / "app_offline.htm";
|
||||
}
|
||||
|
||||
void PollingAppOfflineApplication::ShutDown()
|
||||
{
|
||||
}
|
||||
|
||||
void PollingAppOfflineApplication::Recycle()
|
||||
{
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS PollingAppOfflineHandler::OnExecuteRequestHandler()
|
||||
{
|
||||
HTTP_DATA_CHUNK DataChunk;
|
||||
IHttpResponse* pResponse = m_pContext->GetResponse();
|
||||
|
||||
DBG_ASSERT(pResponse);
|
||||
|
||||
// Ignore failure hresults as nothing we can do
|
||||
// Set fTrySkipCustomErrors to true as we want client see the offline content
|
||||
pResponse->SetStatus(503, "Service Unavailable", 0, S_OK, nullptr, TRUE);
|
||||
pResponse->SetHeader("Content-Type",
|
||||
"text/html",
|
||||
static_cast<USHORT>(strlen("text/html")),
|
||||
FALSE
|
||||
);
|
||||
|
||||
DataChunk.DataChunkType = HttpDataChunkFromMemory;
|
||||
DataChunk.FromMemory.pBuffer = m_strAppOfflineContent.data();
|
||||
DataChunk.FromMemory.BufferLength = static_cast<ULONG>(m_strAppOfflineContent.size());
|
||||
pResponse->WriteEntityChunkByReference(&DataChunk);
|
||||
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <experimental/filesystem>
|
||||
#include "application.h"
|
||||
#include "requesthandler.h"
|
||||
|
||||
class PollingAppOfflineApplication: public APPLICATION
|
||||
{
|
||||
public:
|
||||
PollingAppOfflineApplication(IHttpApplication& pApplication)
|
||||
:
|
||||
m_ulLastCheckTime(0),
|
||||
m_appOfflineLocation(GetAppOfflineLocation(pApplication)),
|
||||
m_fAppOfflineFound(false)
|
||||
{
|
||||
InitializeSRWLock(&m_statusLock);
|
||||
}
|
||||
|
||||
HRESULT CreateHandler(IHttpContext* pHttpContext, IREQUEST_HANDLER** pRequestHandler) override;
|
||||
|
||||
APPLICATION_STATUS QueryStatus() override;
|
||||
bool AppOfflineExists();
|
||||
HRESULT LoadAppOfflineContent();
|
||||
static bool ShouldBeStarted(IHttpApplication& pApplication);
|
||||
void ShutDown() override;
|
||||
void Recycle() override;
|
||||
|
||||
private:
|
||||
static const int c_appOfflineRefreshIntervalMS = 200;
|
||||
static std::experimental::filesystem::path GetAppOfflineLocation(IHttpApplication& pApplication);
|
||||
std::string m_strAppOfflineContent;
|
||||
ULONGLONG m_ulLastCheckTime;
|
||||
std::experimental::filesystem::path m_appOfflineLocation;
|
||||
bool m_fAppOfflineFound;
|
||||
SRWLOCK m_statusLock {};
|
||||
};
|
||||
|
||||
|
||||
class PollingAppOfflineHandler: public REQUEST_HANDLER
|
||||
{
|
||||
public:
|
||||
PollingAppOfflineHandler(IHttpContext* pContext, const std::string appOfflineContent)
|
||||
: m_pContext(pContext),
|
||||
m_strAppOfflineContent(appOfflineContent)
|
||||
{
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
private:
|
||||
IHttpContext* m_pContext;
|
||||
std::string m_strAppOfflineContent;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -4,12 +4,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "iapplication.h"
|
||||
#include "exceptions.h"
|
||||
#include "utility.h"
|
||||
#include "ntassert.h"
|
||||
|
||||
|
||||
class APPLICATION : public IAPPLICATION
|
||||
{
|
||||
|
||||
public:
|
||||
// Non-copyable
|
||||
APPLICATION(const APPLICATION&) = delete;
|
||||
const APPLICATION& operator=(const APPLICATION&) = delete;
|
||||
|
||||
APPLICATION_STATUS
|
||||
QueryStatus() override
|
||||
|
|
@ -33,8 +39,7 @@ public:
|
|||
{
|
||||
DBG_ASSERT(m_cRefs != 0);
|
||||
|
||||
LONG cRefs = 0;
|
||||
if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
|
@ -42,7 +47,7 @@ public:
|
|||
|
||||
protected:
|
||||
volatile APPLICATION_STATUS m_status = APPLICATION_STATUS::UNKNOWN;
|
||||
|
||||
private:
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ Language=English
|
|||
.
|
||||
|
||||
Messageid=1024
|
||||
SymbolicName=ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED
|
||||
SymbolicName=ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ enum APPLICATION_STATUS
|
|||
STARTING,
|
||||
RUNNING,
|
||||
SHUTDOWN,
|
||||
RECYCLED,
|
||||
FAIL
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,26 @@ public:
|
|||
{
|
||||
DBG_ASSERT(m_cRefs != 0);
|
||||
|
||||
LONG cRefs = 0;
|
||||
if ((cRefs = InterlockedDecrement(&m_cRefs)) == 0)
|
||||
if (InterlockedDecrement(&m_cRefs) == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(DWORD cbCompletion, HRESULT hrCompletionStatus) override
|
||||
{
|
||||
UNREFERENCED_PARAMETER(cbCompletion);
|
||||
UNREFERENCED_PARAMETER(hrCompletionStatus);
|
||||
// We shouldn't get here in default implementation
|
||||
DBG_ASSERT(FALSE);
|
||||
return RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID TerminateRequest(bool fClientInitiated) override
|
||||
{
|
||||
UNREFERENCED_PARAMETER(fClientInitiated);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable LONG m_cRefs = 1;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Please check the stderr logs for more information."
|
||||
#define ASPNETCORE_EVENT_APP_IN_SHUTDOWN_MSG L"Application shutting down."
|
||||
#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG L"Application '%s' was recycled after detecting the app_offline file."
|
||||
#define ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_REMOVED_MSG L"App_offline.htm has been removed from the application. Application will be recycled."
|
||||
#define ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG L"Monitoring app_offline.htm failed for application '%s', ErrorCode '0x%x'. "
|
||||
#define ASPNETCORE_EVENT_RECYCLE_CONFIGURATION_MSG L"Application '%s' was recycled due to configuration change"
|
||||
#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"
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
hostfxr_main_fn InProcessApplicationBase::s_fMainCallback = NULL;
|
||||
|
||||
InProcessApplicationBase::InProcessApplicationBase(
|
||||
IHttpServer *pHttpServer)
|
||||
:
|
||||
m_srwLock(),
|
||||
m_fRecycleCalled(FALSE),
|
||||
m_pHttpServer(pHttpServer)
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pHttpApplication)
|
||||
: AppOfflineTrackingApplication(pHttpApplication),
|
||||
m_fRecycleCalled(FALSE),
|
||||
m_srwLock(),
|
||||
m_pHttpServer(pHttpServer)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
}
|
||||
|
|
@ -39,23 +40,19 @@ InProcessApplicationBase::Recycle(
|
|||
m_fRecycleCalled = true;
|
||||
}
|
||||
|
||||
if (!m_pHttpServer->IsCommandLineLaunch())
|
||||
if (!m_pHttpServer.IsCommandLineLaunch())
|
||||
{
|
||||
// IIS scenario.
|
||||
// We don't actually handle any shutdown logic here.
|
||||
// Instead, we notify IIS that the process needs to be recycled, which will call
|
||||
// ApplicationManager->Shutdown(). This will call shutdown on the application.
|
||||
m_pHttpServer->RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
|
||||
m_pHttpServer.RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
|
||||
}
|
||||
else
|
||||
{
|
||||
// IISExpress scenario
|
||||
// Try to graceful shutdown the managed application
|
||||
// and call exit to terminate current process
|
||||
ShutDown();
|
||||
// If we set a static callback, we don't want to kill the current process as
|
||||
// that will kill the test process and means we are running in hostable webcore mode.
|
||||
if (m_pHttpServer->IsCommandLineLaunch()
|
||||
if (m_pHttpServer.IsCommandLineLaunch()
|
||||
&& s_fMainCallback == NULL)
|
||||
{
|
||||
exit(0);
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@
|
|||
|
||||
#include "precomp.hxx"
|
||||
#include "application.h"
|
||||
#include "requesthandler_config.h"
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
|
||||
typedef INT(*hostfxr_main_fn) (CONST DWORD argc, CONST PCWSTR argv[]); // TODO these may need to be BSTRs
|
||||
|
||||
class InProcessApplicationBase : public APPLICATION
|
||||
class InProcessApplicationBase : public AppOfflineTrackingApplication
|
||||
{
|
||||
public:
|
||||
|
||||
InProcessApplicationBase(IHttpServer* pHttpServer);
|
||||
InProcessApplicationBase(
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pHttpApplication);
|
||||
|
||||
~InProcessApplicationBase() = default;
|
||||
|
||||
|
|
@ -22,7 +24,7 @@ public:
|
|||
protected:
|
||||
BOOL m_fRecycleCalled;
|
||||
SRWLOCK m_srwLock;
|
||||
IHttpServer* const m_pHttpServer;
|
||||
IHttpServer& m_pHttpServer;
|
||||
// Allows to override call to hostfxr_main with custome callback
|
||||
// used in testing
|
||||
static hostfxr_main_fn s_fMainCallback;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
#include "StartupExceptionApplication.h"
|
||||
|
||||
VOID StartupExceptionApplication::ShutDown()
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pContext, IREQUEST_HANDLER ** pRequestHandler)
|
||||
HRESULT StartupExceptionApplication::CreateHandler(IHttpContext *pHttpContext, IREQUEST_HANDLER ** pRequestHandler)
|
||||
{
|
||||
*pRequestHandler = new StartupExceptionHandler(pContext, m_disableLogs, this);
|
||||
*pRequestHandler = new StartupExceptionHandler(pHttpContext, m_disableLogs, this);
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,68 +3,58 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "StartupExceptionHandler.h"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
||||
class StartupExceptionApplication : public InProcessApplicationBase
|
||||
{
|
||||
public:
|
||||
StartupExceptionApplication(IHttpServer* pServer, BOOL disableLogs)
|
||||
StartupExceptionApplication(
|
||||
IHttpServer& pServer,
|
||||
IHttpApplication& pApplication,
|
||||
BOOL disableLogs)
|
||||
: m_disableLogs(disableLogs),
|
||||
m_pHttpServer(pServer),
|
||||
InProcessApplicationBase(pServer)
|
||||
InProcessApplicationBase(pServer, pApplication)
|
||||
{
|
||||
InitializeSRWLock(&m_srwLock);
|
||||
m_status = APPLICATION_STATUS::RUNNING;
|
||||
html500Page = std::string("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
|
||||
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
|
||||
<head> \
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
|
||||
<title> IIS 500.30 Error </title><style type=\"text/css\"></style></head> \
|
||||
<body> <div id = \"content\"> \
|
||||
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset> <h4> Common causes of this issue: </h4> \
|
||||
<ul><li> The application failed to start </li> \
|
||||
<li> The application started but then stopped </li> \
|
||||
<li> The application started but threw an exception during startup </li></ul></fieldset> \
|
||||
</div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset><h4> Troubleshooting steps: </h4> \
|
||||
<ul><li> Check the system event log for error messages </li> \
|
||||
<li> Enable logging the application process' stdout messages </li> \
|
||||
<li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
|
||||
<fieldset><h4> For more information visit: \
|
||||
<a href=\"https://go.microsoft.com/fwlink/?LinkID=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
|
||||
</fieldset> \
|
||||
</div> \
|
||||
</div></body></html>");
|
||||
}
|
||||
|
||||
~StartupExceptionApplication() = default;
|
||||
|
||||
virtual VOID ShutDown() override;
|
||||
virtual HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override;
|
||||
VOID ShutDown() override;
|
||||
HRESULT CreateHandler(IHttpContext * pHttpContext, IREQUEST_HANDLER ** pRequestHandler) override;
|
||||
|
||||
std::string&
|
||||
GetStaticHtml500Content()
|
||||
{
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (html500Page.empty())
|
||||
{
|
||||
html500Page = std::string("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> \
|
||||
<html xmlns=\"http://www.w3.org/1999/xhtml\"> \
|
||||
<head> \
|
||||
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" /> \
|
||||
<title> IIS 500.30 Error </title><style type=\"text/css\"></style></head> \
|
||||
<body> <div id = \"content\"> \
|
||||
<div class = \"content-container\"><h3> HTTP Error 500.30 - ANCM In-Process Start Failure </h3></div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset> <h4> Common causes of this issue: </h4> \
|
||||
<ul><li> The application failed to start </li> \
|
||||
<li> The application started but then stopped </li> \
|
||||
<li> The application started but threw an exception during startup </li></ul></fieldset> \
|
||||
</div> \
|
||||
<div class = \"content-container\"> \
|
||||
<fieldset><h4> Troubleshooting steps: </h4> \
|
||||
<ul><li> Check the system event log for error messages </li> \
|
||||
<li> Enable logging the application process' stdout messages </li> \
|
||||
<li> Attach a debugger to the application process and inspect </li></ul></fieldset> \
|
||||
<fieldset><h4> For more information visit: \
|
||||
<a href=\"https://go.microsoft.com/fwlink/?LinkID=808681\"> <cite> https://go.microsoft.com/fwlink/?LinkID=808681 </cite></a></h4> \
|
||||
</fieldset> \
|
||||
</div> \
|
||||
</div></body></html>");
|
||||
}
|
||||
}
|
||||
|
||||
return html500Page;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string html500Page;
|
||||
SRWLOCK m_srwLock;
|
||||
BOOL m_disableLogs;
|
||||
IHttpServer* m_pHttpServer;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
#include "precomp.hxx"
|
||||
|
||||
#include "StartupExceptionApplication.h"
|
||||
#include "StartupExceptionHandler.h"
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
|
||||
|
|
@ -28,15 +31,5 @@ REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnExecuteRequestHandler()
|
|||
}
|
||||
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
|
||||
}
|
||||
|
||||
REQUEST_NOTIFICATION_STATUS StartupExceptionHandler::OnAsyncCompletion(DWORD , HRESULT )
|
||||
{
|
||||
return REQUEST_NOTIFICATION_STATUS::RQ_NOTIFICATION_FINISH_REQUEST;
|
||||
}
|
||||
|
||||
VOID StartupExceptionHandler::TerminateRequest(bool )
|
||||
{
|
||||
return VOID();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "requesthandler.h"
|
||||
#include "StartupExceptionApplication.h"
|
||||
|
||||
class StartupExceptionApplication;
|
||||
|
||||
class StartupExceptionHandler : public REQUEST_HANDLER
|
||||
{
|
||||
public:
|
||||
virtual REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
virtual REQUEST_NOTIFICATION_STATUS OnAsyncCompletion(DWORD cbCompletion, HRESULT hrCompletionStatus) override;
|
||||
|
||||
virtual VOID TerminateRequest(bool fClientInitiated) override;
|
||||
|
||||
StartupExceptionHandler(IHttpContext* pContext, BOOL disableLogs, StartupExceptionApplication* pApplication)
|
||||
:
|
||||
m_pContext(pContext),
|
||||
|
|
@ -26,9 +18,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
~StartupExceptionHandler()
|
||||
{
|
||||
}
|
||||
REQUEST_NOTIFICATION_STATUS OnExecuteRequestHandler() override;
|
||||
|
||||
private:
|
||||
IHttpContext * m_pContext;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include <IPHlpApi.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include "inprocessapplication.h"
|
||||
|
|
@ -39,7 +38,7 @@ InitializeGlobalConfiguration(
|
|||
g_pHttpServer = pServer;
|
||||
RETURN_IF_FAILED(ALLOC_CACHE_HANDLER::StaticInitialize());
|
||||
RETURN_IF_FAILED(IN_PROCESS_HANDLER::StaticInitialize());
|
||||
|
||||
|
||||
if (pServer->IsCommandLineLaunch())
|
||||
{
|
||||
g_hEventLog = RegisterEventSource(NULL, ASPNETCORE_IISEXPRESS_EVENT_PROVIDER);
|
||||
|
|
@ -89,27 +88,30 @@ CreateApplication(
|
|||
_Out_ IAPPLICATION **ppApplication
|
||||
)
|
||||
{
|
||||
REQUESTHANDLER_CONFIG *pConfig = NULL;
|
||||
|
||||
try
|
||||
{
|
||||
// Initialze some global variables here
|
||||
RETURN_IF_FAILED(InitializeGlobalConfiguration(pServer));
|
||||
|
||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||
|
||||
BOOL disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
|
||||
|
||||
auto config = std::unique_ptr<REQUESTHANDLER_CONFIG>(pConfig);
|
||||
|
||||
const bool disableStartupPage = pConfig->QueryDisableStartUpErrorPage();
|
||||
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(pServer, std::move(config), pParameters, nParameters);
|
||||
|
||||
auto pApplication = std::make_unique<IN_PROCESS_APPLICATION>(*pServer, *pHttpApplication, std::move(pRequestHandlerConfig), pParameters, nParameters);
|
||||
|
||||
if (FAILED_LOG(pApplication->LoadManagedApplication()))
|
||||
{
|
||||
// Set the currently running application to a fake application that returns startup exceptions.
|
||||
*ppApplication = new StartupExceptionApplication(pServer, disableStartupPage);
|
||||
auto pErrorApplication = std::make_unique<StartupExceptionApplication>(*pServer, *pHttpApplication, disableStartupPage);
|
||||
|
||||
RETURN_IF_FAILED(pErrorApplication->StartMonitoringAppOffline());
|
||||
*ppApplication = pErrorApplication.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
|
||||
*ppApplication = pApplication.release();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +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 "precomp.hxx"
|
||||
#include "inprocessapplication.h"
|
||||
#include "inprocesshandler.h"
|
||||
#include "hostfxroptions.h"
|
||||
|
|
@ -18,17 +19,17 @@ const LPCSTR IN_PROCESS_APPLICATION::s_exeLocationParameterName = "InProcessExeL
|
|||
IN_PROCESS_APPLICATION* IN_PROCESS_APPLICATION::s_Application = NULL;
|
||||
|
||||
IN_PROCESS_APPLICATION::IN_PROCESS_APPLICATION(
|
||||
IHttpServer *pHttpServer,
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters) :
|
||||
InProcessApplicationBase(pHttpServer),
|
||||
InProcessApplicationBase(pHttpServer, pApplication),
|
||||
m_pHttpServer(pHttpServer),
|
||||
m_ProcessExitCode(0),
|
||||
m_fBlockCallbacksIntoManaged(FALSE),
|
||||
m_fShutdownCalledFromNative(FALSE),
|
||||
m_fShutdownCalledFromManaged(FALSE),
|
||||
m_fInitialized(FALSE),
|
||||
m_pConfig(std::move(pConfig))
|
||||
{
|
||||
// is it guaranteed that we have already checked app offline at this point?
|
||||
|
|
@ -664,14 +665,6 @@ IN_PROCESS_APPLICATION::RunDotnetApplication(DWORD argc, CONST PCWSTR* argv, hos
|
|||
return hr;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
IN_PROCESS_APPLICATION::QueryConfig() const
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
HRESULT
|
||||
IN_PROCESS_APPLICATION::CreateHandler(
|
||||
_In_ IHttpContext *pHttpContext,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "InProcessApplicationBase.h"
|
||||
#include "inprocesshandler.h"
|
||||
#include "requesthandler_config.h"
|
||||
|
|
@ -17,7 +16,8 @@ class IN_PROCESS_APPLICATION : public InProcessApplicationBase
|
|||
{
|
||||
public:
|
||||
IN_PROCESS_APPLICATION(
|
||||
IHttpServer* pHttpServer,
|
||||
IHttpServer& pHttpServer,
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig,
|
||||
APPLICATION_PARAMETER *pParameters,
|
||||
DWORD nParameters);
|
||||
|
|
@ -105,17 +105,21 @@ public:
|
|||
return s_Application;
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig() const;
|
||||
|
||||
PCWSTR
|
||||
QueryExeLocation()
|
||||
{
|
||||
return m_struExeLocation.QueryStr();
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig()
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
private:
|
||||
IHttpServer* const m_pHttpServer;
|
||||
|
||||
IHttpServer & m_pHttpServer;
|
||||
|
||||
// Thread executing the .NET Core process
|
||||
HANDLE m_hThread;
|
||||
|
|
@ -144,12 +148,11 @@ private:
|
|||
volatile BOOL m_fShutdownCalledFromManaged;
|
||||
BOOL m_fRecycleCalled;
|
||||
BOOL m_fInitialized;
|
||||
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
|
||||
static IN_PROCESS_APPLICATION* s_Application;
|
||||
|
||||
IOutputManager* m_pLoggerProvider;
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
|
||||
static const LPCSTR s_exeLocationParameterName;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +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 "precomp.hxx"
|
||||
#include "inprocesshandler.h"
|
||||
#include "inprocessapplication.h"
|
||||
#include "aspnetcore_event.h"
|
||||
|
|
@ -12,9 +13,10 @@ IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
|
|||
_In_ IHttpContext *pW3Context,
|
||||
_In_ IN_PROCESS_APPLICATION *pApplication
|
||||
): m_pW3Context(pW3Context),
|
||||
m_pApplication(pApplication)
|
||||
m_requestNotificationStatus(RQ_NOTIFICATION_PENDING),
|
||||
m_pApplication(pApplication),
|
||||
m_fManagedRequestComplete(FALSE)
|
||||
{
|
||||
m_fManagedRequestComplete = FALSE;
|
||||
}
|
||||
|
||||
IN_PROCESS_HANDLER::~IN_PROCESS_HANDLER()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "precomp.hxx"
|
||||
#include "requesthandler.h"
|
||||
|
||||
class IN_PROCESS_APPLICATION;
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ EnsureOutOfProcessInitializtion()
|
|||
|
||||
g_hWinHttpModule = GetModuleHandle(TEXT("winhttp.dll"));
|
||||
|
||||
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcore.dll"));
|
||||
g_hAspNetCoreModule = GetModuleHandle(TEXT("aspnetcorev2.dll"));
|
||||
|
||||
hr = WINHTTP_HELPER::StaticInitialize();
|
||||
if (FAILED(hr))
|
||||
|
|
@ -279,42 +279,20 @@ CreateApplication(
|
|||
{
|
||||
UNREFERENCED_PARAMETER(pParameters);
|
||||
UNREFERENCED_PARAMETER(nParameters);
|
||||
HRESULT hr = S_OK;
|
||||
IAPPLICATION *pApplication = NULL;
|
||||
REQUESTHANDLER_CONFIG *pConfig = NULL;
|
||||
|
||||
// Initialze some global variables here
|
||||
|
||||
InitializeGlobalConfiguration(pServer);
|
||||
|
||||
hr = REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
return hr;
|
||||
}
|
||||
REQUESTHANDLER_CONFIG *pConfig = nullptr;
|
||||
RETURN_IF_FAILED(REQUESTHANDLER_CONFIG::CreateRequestHandlerConfig(pServer, pHttpApplication, &pConfig));
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pRequestHandlerConfig(pConfig);
|
||||
|
||||
hr = EnsureOutOfProcessInitializtion();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
goto Finished;
|
||||
}
|
||||
RETURN_IF_FAILED(EnsureOutOfProcessInitializtion());
|
||||
|
||||
pApplication = new OUT_OF_PROCESS_APPLICATION(pConfig);
|
||||
if (pApplication == NULL)
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
|
||||
goto Finished;
|
||||
}
|
||||
std::unique_ptr<OUT_OF_PROCESS_APPLICATION> pApplication = std::make_unique<OUT_OF_PROCESS_APPLICATION>(*pHttpApplication, std::move(pRequestHandlerConfig));
|
||||
|
||||
hr = ((OUT_OF_PROCESS_APPLICATION*)pApplication)->Initialize();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
delete pApplication;
|
||||
pApplication = NULL;
|
||||
goto Finished;
|
||||
}
|
||||
RETURN_IF_FAILED(pApplication->Initialize());
|
||||
RETURN_IF_FAILED(pApplication->StartMonitoringAppOffline());
|
||||
|
||||
*ppApplication = pApplication;
|
||||
|
||||
Finished:
|
||||
return hr;
|
||||
*ppApplication = pApplication.release();
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
#include "..\precomp.hxx"
|
||||
#include "SRWExclusiveLock.h"
|
||||
|
||||
OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
|
||||
REQUESTHANDLER_CONFIG *pConfig) :
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig) :
|
||||
AppOfflineTrackingApplication(pApplication),
|
||||
m_fWebSocketSupported(WEBSOCKET_STATUS::WEBSOCKET_UNKNOWN),
|
||||
m_pConfig(pConfig)
|
||||
m_pConfig(std::move(pConfig))
|
||||
{
|
||||
m_status = APPLICATION_STATUS::RUNNING;
|
||||
m_pProcessManager = NULL;
|
||||
|
|
@ -12,18 +15,13 @@ OUT_OF_PROCESS_APPLICATION::OUT_OF_PROCESS_APPLICATION(
|
|||
|
||||
OUT_OF_PROCESS_APPLICATION::~OUT_OF_PROCESS_APPLICATION()
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
m_pProcessManager->ShutdownAllProcesses();
|
||||
m_pProcessManager->Shutdown();
|
||||
m_pProcessManager->DereferenceProcessManager();
|
||||
m_pProcessManager = NULL;
|
||||
}
|
||||
|
||||
if (m_pConfig != NULL)
|
||||
{
|
||||
delete m_pConfig;
|
||||
m_pConfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
|
|
@ -56,29 +54,18 @@ OUT_OF_PROCESS_APPLICATION::GetProcess(
|
|||
_Out_ SERVER_PROCESS **ppServerProcess
|
||||
)
|
||||
{
|
||||
return m_pProcessManager->GetProcess(m_pConfig, QueryWebsocketStatus(), ppServerProcess);
|
||||
}
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
OUT_OF_PROCESS_APPLICATION::QueryConfig() const
|
||||
{
|
||||
return m_pConfig;
|
||||
return m_pProcessManager->GetProcess(m_pConfig.get(), QueryWebsocketStatus(), ppServerProcess);
|
||||
}
|
||||
|
||||
__override
|
||||
VOID
|
||||
OUT_OF_PROCESS_APPLICATION::ShutDown()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
{
|
||||
SRWExclusiveLock lock(m_srwLock);
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
if (m_pProcessManager != NULL)
|
||||
{
|
||||
m_pProcessManager->ShutdownAllProcesses();
|
||||
m_pProcessManager->DereferenceProcessManager();
|
||||
m_pProcessManager = NULL;
|
||||
}
|
||||
m_pProcessManager->Shutdown();
|
||||
}
|
||||
ReleaseSRWLockExclusive(&m_srwLock);
|
||||
}
|
||||
|
||||
__override
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
class OUT_OF_PROCESS_APPLICATION : public APPLICATION
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
|
||||
class OUT_OF_PROCESS_APPLICATION : public AppOfflineTrackingApplication
|
||||
{
|
||||
enum WEBSOCKET_STATUS
|
||||
{
|
||||
|
|
@ -14,7 +16,8 @@ class OUT_OF_PROCESS_APPLICATION : public APPLICATION
|
|||
|
||||
public:
|
||||
OUT_OF_PROCESS_APPLICATION(
|
||||
REQUESTHANDLER_CONFIG *pConfig);
|
||||
IHttpApplication& pApplication,
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> pConfig);
|
||||
|
||||
__override
|
||||
~OUT_OF_PROCESS_APPLICATION() override;
|
||||
|
|
@ -44,14 +47,15 @@ public:
|
|||
_Out_ IREQUEST_HANDLER **pRequestHandler)
|
||||
override;
|
||||
|
||||
REQUESTHANDLER_CONFIG*
|
||||
QueryConfig()
|
||||
const;
|
||||
|
||||
BOOL
|
||||
QueryWebsocketStatus()
|
||||
const;
|
||||
|
||||
REQUESTHANDLER_CONFIG* QueryConfig()
|
||||
{
|
||||
return m_pConfig.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
VOID SetWebsocketStatus(IHttpContext *pHttpContext);
|
||||
|
|
@ -60,6 +64,6 @@ private:
|
|||
SRWLOCK m_srwLock;
|
||||
IHttpServer *m_pHttpServer;
|
||||
|
||||
REQUESTHANDLER_CONFIG* m_pConfig;
|
||||
WEBSOCKET_STATUS m_fWebSocketSupported;
|
||||
std::unique_ptr<REQUESTHANDLER_CONFIG> m_pConfig;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,6 +114,11 @@ PROCESS_MANAGER::GetProcess(
|
|||
DWORD dwProcessIndex = 0;
|
||||
SERVER_PROCESS *pSelectedServerProcess = NULL;
|
||||
|
||||
if (InterlockedCompareExchange(&m_lStopping, 1L, 1L) == 1L)
|
||||
{
|
||||
return hr = E_APPLICATION_EXITING;
|
||||
}
|
||||
|
||||
if (!m_fServerProcessListReady)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_srwLock);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,16 @@ public:
|
|||
ReleaseSRWLockExclusive( &m_srwLock );
|
||||
}
|
||||
|
||||
VOID
|
||||
Shutdown(
|
||||
)
|
||||
{
|
||||
if (InterlockedCompareExchange(&m_lStopping, 1L, 0L) == 0L)
|
||||
{
|
||||
ShutdownAllProcesses();
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
IncrementRapidFailCount(
|
||||
VOID
|
||||
|
|
@ -103,6 +113,7 @@ public:
|
|||
m_dwProcessesPerApplication( 1 ),
|
||||
m_dwRouteToProcessIndex( 0 ),
|
||||
m_fServerProcessListReady(FALSE),
|
||||
m_lStopping(0),
|
||||
m_cRefs( 1 )
|
||||
{
|
||||
m_ppServerProcessList = NULL;
|
||||
|
|
@ -193,4 +204,5 @@ private:
|
|||
|
||||
volatile static BOOL sm_fWSAStartupDone;
|
||||
volatile BOOL m_fServerProcessListReady;
|
||||
volatile LONG m_lStopping;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +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"
|
||||
#include "AppOfflineTrackingApplication.h"
|
||||
#include "EventLog.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
extern HANDLE g_hEventLog;
|
||||
|
||||
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOffline()
|
||||
{
|
||||
LOG_INFOF("Starting app_offline monitoring in application %S", m_applicationPath.c_str());
|
||||
HRESULT hr = StartMonitoringAppOflineImpl();
|
||||
|
||||
if (FAILED_LOG(hr))
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_WARNING_TYPE,
|
||||
ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR,
|
||||
ASPNETCORE_EVENT_MONITOR_APPOFFLINE_ERROR_MSG,
|
||||
m_applicationPath.c_str(),
|
||||
hr);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT AppOfflineTrackingApplication::StartMonitoringAppOflineImpl()
|
||||
{
|
||||
if (m_fileWatcher)
|
||||
{
|
||||
RETURN_IF_FAILED(E_UNEXPECTED);
|
||||
}
|
||||
|
||||
m_fileWatcher = std::make_unique<FILE_WATCHER>();
|
||||
RETURN_IF_FAILED(m_fileWatcher->Create());
|
||||
m_fileWatcherEntry.reset(new FILE_WATCHER_ENTRY(m_fileWatcher.get()));
|
||||
// FileWatcherCompletionRoutine calls dereference so we need to get ourselves a reference count
|
||||
m_fileWatcherEntry->ReferenceFileWatcherEntry();
|
||||
RETURN_IF_FAILED(m_fileWatcherEntry->Create(
|
||||
m_applicationPath.c_str(),
|
||||
L"app_offline.htm",
|
||||
std::bind(&AppOfflineTrackingApplication::OnAppOffline, this),
|
||||
NULL));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void AppOfflineTrackingApplication::OnAppOffline()
|
||||
{
|
||||
LOG_INFOF("Received app_offline notification in application %S", m_applicationPath.c_str());
|
||||
m_fileWatcherEntry->StopMonitor();
|
||||
m_status = APPLICATION_STATUS::RECYCLED;
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE,
|
||||
ASPNETCORE_EVENT_RECYCLE_APPOFFLINE_MSG,
|
||||
m_applicationPath.c_str());
|
||||
|
||||
Recycle();
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include "application.h"
|
||||
#include "filewatcher.h"
|
||||
|
||||
class AppOfflineTrackingApplication: public APPLICATION
|
||||
{
|
||||
public:
|
||||
AppOfflineTrackingApplication(const IHttpApplication& application)
|
||||
: m_applicationPath(application.GetApplicationPhysicalPath()),
|
||||
m_fileWatcher(nullptr),
|
||||
m_fileWatcherEntry(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~AppOfflineTrackingApplication() override = default;
|
||||
|
||||
HRESULT
|
||||
StartMonitoringAppOffline();
|
||||
|
||||
virtual
|
||||
VOID
|
||||
OnAppOffline();
|
||||
|
||||
private:
|
||||
HRESULT
|
||||
StartMonitoringAppOflineImpl();
|
||||
|
||||
std::wstring m_applicationPath;
|
||||
std::unique_ptr<FILE_WATCHER> m_fileWatcher;
|
||||
std::unique_ptr<FILE_WATCHER_ENTRY, FILE_WATCHER_ENTRY_DELETER> m_fileWatcherEntry;
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
|
|
@ -188,7 +188,9 @@
|
|||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AppOfflineTrackingApplication.h" />
|
||||
<ClInclude Include="environmentvariablehelpers.h" />
|
||||
<ClInclude Include="filewatcher.h" />
|
||||
<ClInclude Include="NullOutputManager.h" />
|
||||
<ClInclude Include="FileOutputManager.h" />
|
||||
<ClInclude Include="environmentvariablehash.h" />
|
||||
|
|
@ -199,7 +201,9 @@
|
|||
<ClInclude Include="stdafx.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AppOfflineTrackingApplication.cpp" />
|
||||
<ClCompile Include="FileOutputManager.cpp" />
|
||||
<ClCompile Include="filewatcher.cpp" />
|
||||
<ClCompile Include="requesthandler_config.cpp" />
|
||||
<ClCompile Include="LoggingHelpers.cpp" />
|
||||
<ClCompile Include="PipeOutputManager.cpp" />
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
// 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 "filewatcher.h"
|
||||
|
||||
#include "ntassert.h"
|
||||
#include "applicationinfo.h"
|
||||
|
||||
FILE_WATCHER::FILE_WATCHER() :
|
||||
m_hCompletionPort(NULL),
|
||||
m_hChangeNotificationThread(NULL),
|
||||
|
|
@ -214,7 +212,7 @@ FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) :
|
|||
_pFileMonitor(pFileMonitor),
|
||||
_hDirectory(INVALID_HANDLE_VALUE),
|
||||
_hImpersonationToken(NULL),
|
||||
_pApplicationInfo(NULL),
|
||||
_pCallback(),
|
||||
_lStopMonitorCalled(0),
|
||||
_cRefs(1),
|
||||
_fIsValid(TRUE)
|
||||
|
|
@ -225,6 +223,8 @@ FILE_WATCHER_ENTRY::FILE_WATCHER_ENTRY(FILE_WATCHER * pFileMonitor) :
|
|||
|
||||
FILE_WATCHER_ENTRY::~FILE_WATCHER_ENTRY()
|
||||
{
|
||||
StopMonitor();
|
||||
|
||||
_dwSignature = FILE_WATCHER_ENTRY_SIGNATURE_FREE;
|
||||
|
||||
if (_hDirectory != INVALID_HANDLE_VALUE)
|
||||
|
|
@ -330,16 +330,16 @@ HRESULT
|
|||
}
|
||||
}
|
||||
|
||||
Finished:
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
|
||||
if (fFileChanged)
|
||||
{
|
||||
//
|
||||
// so far we only monitoring app_offline
|
||||
//
|
||||
_pApplicationInfo->UpdateAppOfflineFileHandle();
|
||||
_pCallback();
|
||||
}
|
||||
|
||||
Finished:
|
||||
ReleaseSRWLockExclusive(&_srwLock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +399,7 @@ HRESULT
|
|||
FILE_WATCHER_ENTRY::Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION_INFO* pApplicationInfo,
|
||||
_In_ std::function<void()> pCallback,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
)
|
||||
{
|
||||
|
|
@ -408,17 +408,14 @@ FILE_WATCHER_ENTRY::Create(
|
|||
|
||||
if (pszDirectoryToMonitor == NULL ||
|
||||
pszFileNameToMonitor == NULL ||
|
||||
pApplicationInfo == NULL)
|
||||
pCallback == NULL)
|
||||
{
|
||||
DBG_ASSERT(FALSE);
|
||||
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
|
||||
goto Finished;
|
||||
}
|
||||
|
||||
//
|
||||
//remember the application
|
||||
//
|
||||
_pApplicationInfo = pApplicationInfo;
|
||||
_pCallback = pCallback;
|
||||
|
||||
if (FAILED(hr = _strFileName.Copy(pszFileNameToMonitor)))
|
||||
{
|
||||
|
|
@ -1,20 +1,18 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "stringu.h"
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
|
||||
#define FILE_WATCHER_SHUTDOWN_KEY (ULONG_PTR)(-1)
|
||||
#define FILE_WATCHER_ENTRY_BUFFER_SIZE 4096
|
||||
#define FILE_NOTIFY_VALID_MASK 0x00000fff
|
||||
#define FILE_NOTIFY_VALID_MASK 0x00000fff
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE ((DWORD) 'FWES')
|
||||
#define FILE_WATCHER_ENTRY_SIGNATURE_FREE ((DWORD) 'sewf')
|
||||
|
||||
class APPLICATION_INFO;
|
||||
|
||||
class FILE_WATCHER{
|
||||
public:
|
||||
|
||||
|
|
@ -62,7 +60,7 @@ public:
|
|||
Create(
|
||||
_In_ PCWSTR pszDirectoryToMonitor,
|
||||
_In_ PCWSTR pszFileNameToMonitor,
|
||||
_In_ APPLICATION_INFO* pApplicationInfo,
|
||||
_In_ std::function<void()> pCallback,
|
||||
_In_ HANDLE hImpersonationToken
|
||||
);
|
||||
|
||||
|
|
@ -111,11 +109,20 @@ private:
|
|||
HANDLE _hImpersonationToken;
|
||||
HANDLE _hDirectory;
|
||||
FILE_WATCHER* _pFileMonitor;
|
||||
APPLICATION_INFO* _pApplicationInfo;
|
||||
STRU _strFileName;
|
||||
STRU _strDirectoryName;
|
||||
LONG _lStopMonitorCalled;
|
||||
mutable LONG _cRefs;
|
||||
BOOL _fIsValid;
|
||||
SRWLOCK _srwLock;
|
||||
std::function<void()> _pCallback;
|
||||
};
|
||||
|
||||
|
||||
struct FILE_WATCHER_ENTRY_DELETER
|
||||
{
|
||||
void operator()(FILE_WATCHER_ENTRY* entry) const
|
||||
{
|
||||
entry->DereferenceFileWatcherEntry();
|
||||
}
|
||||
};
|
||||
|
|
@ -54,7 +54,8 @@ enum APP_HOSTING_MODEL
|
|||
class REQUESTHANDLER_CONFIG
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
|
||||
|
||||
~REQUESTHANDLER_CONFIG();
|
||||
|
||||
static
|
||||
|
|
@ -217,7 +218,6 @@ protected:
|
|||
REQUESTHANDLER_CONFIG() :
|
||||
m_fStdoutLogEnabled(FALSE),
|
||||
m_pEnvironmentVariables(NULL),
|
||||
m_cRefs(1),
|
||||
m_hostingModel(HOSTING_UNKNOWN),
|
||||
m_ppStrArguments(NULL)
|
||||
{
|
||||
|
|
@ -229,8 +229,6 @@ protected:
|
|||
IHttpApplication *pHttpApplication
|
||||
);
|
||||
|
||||
mutable LONG m_cRefs;
|
||||
|
||||
DWORD m_dwRequestTimeoutInMS;
|
||||
DWORD m_dwStartupTimeLimitInMS;
|
||||
DWORD m_dwShutdownTimeLimitInMS;
|
||||
|
|
@ -254,4 +252,5 @@ protected:
|
|||
STRU m_struHostFxrLocation;
|
||||
PWSTR* m_ppStrArguments;
|
||||
DWORD m_dwArgc;
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,5 +24,3 @@
|
|||
#include "dbgutil.h"
|
||||
#include "ahutil.h"
|
||||
#include "hashfn.h"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -53,15 +53,20 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
}
|
||||
|
||||
// Defaults to inprocess specific deployment parameters
|
||||
public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
|
||||
public static DeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false)
|
||||
{
|
||||
if (site == null)
|
||||
{
|
||||
site = hostingModel == HostingModel.InProcess ? "InProcessWebSite" : "OutOfProcessWebSite";
|
||||
}
|
||||
|
||||
return new DeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
|
||||
{
|
||||
TargetFramework = Tfm.NetCoreApp22,
|
||||
ApplicationType = ApplicationType.Portable,
|
||||
AncmVersion = AncmVersion.AspNetCoreModuleV2,
|
||||
HostingModel = HostingModel.InProcess,
|
||||
PublishApplicationBeforeDeployment = site == "InProcessWebSite",
|
||||
HostingModel = hostingModel,
|
||||
PublishApplicationBeforeDeployment = publish,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ public:
|
|||
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());
|
||||
|
|
@ -167,6 +166,16 @@ class MockHttpServer : public IHttpServer
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class MockHttpApplication: public IHttpApplication
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD0(GetApplicationPhysicalPath, PCWSTR ());
|
||||
MOCK_CONST_METHOD0(GetApplicationId, PCWSTR ());
|
||||
MOCK_CONST_METHOD0(GetAppConfigPath, PCWSTR ());
|
||||
MOCK_METHOD0(GetModuleContextContainer, IHttpModuleContextContainer* ());
|
||||
};
|
||||
|
||||
class MockRequestHandlerConfig : public REQUESTHANDLER_CONFIG
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#include "inprocessapplication.h"
|
||||
#include "fakeclasses.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
// Externals defined in inprocess
|
||||
BOOL g_fProcessDetach;
|
||||
HANDLE g_hEventLog;
|
||||
|
|
@ -15,16 +18,22 @@ namespace InprocessTests
|
|||
{
|
||||
TEST(InProcessTest, NoNullRefForExePath)
|
||||
{
|
||||
auto server = new MockHttpServer();
|
||||
auto requestHandlerConfig = MockRequestHandlerConfig::CreateConfig();
|
||||
auto config = std::unique_ptr<REQUESTHANDLER_CONFIG>(requestHandlerConfig);
|
||||
MockHttpServer server;
|
||||
NiceMock<MockHttpApplication> application;
|
||||
|
||||
ON_CALL(application, GetApplicationPhysicalPath())
|
||||
.WillByDefault(testing::Return(L"Some path"));
|
||||
|
||||
auto requestHandlerConfig = std::unique_ptr<REQUESTHANDLER_CONFIG>(MockRequestHandlerConfig::CreateConfig());
|
||||
|
||||
std::wstring exePath(L"hello");
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters {
|
||||
|
||||
std::array<APPLICATION_PARAMETER, 1> parameters{
|
||||
{"InProcessExeLocation", exePath.data()}
|
||||
};
|
||||
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, std::move(config), parameters.data(), 1);
|
||||
IN_PROCESS_APPLICATION *app = new IN_PROCESS_APPLICATION(server, application, std::move(requestHandlerConfig), parameters.data(), 1);
|
||||
|
||||
ASSERT_STREQ(app->QueryExeLocation(), L"hello");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,25 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
public class AppOfflineTests : IISFunctionalTestBase
|
||||
{
|
||||
// TODO these will differ between IIS and IISExpress
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_SiteReturns503()
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_SiteReturns503(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
await AssertAppOffline(deploymentResult);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_CustomResponse()
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDroppedWhileSiteIsDown_CustomResponse(HostingModel hostingModel)
|
||||
{
|
||||
var expectedResponse = "The app is offline.";
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot, expectedResponse);
|
||||
|
||||
|
|
@ -41,9 +45,9 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown()
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_InProcess()
|
||||
{
|
||||
var deploymentResult = await AssertStarts();
|
||||
var deploymentResult = await AssertStarts(HostingModel.InProcess);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
|
|
@ -51,9 +55,26 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task AppOfflineDropped_CanRemoveAppOfflineAfterAddingAndSiteWorks()
|
||||
public async Task AppOfflineDroppedWhileSiteRunning_SiteShutsDown_OutOfProcess()
|
||||
{
|
||||
var deploymentResult = await DeployApp();
|
||||
var deploymentResult = await AssertStarts(HostingModel.OutOfProcess);
|
||||
|
||||
// Repeat dropping file and restarting multiple times
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
await AssertAppOffline(deploymentResult);
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
[InlineData(HostingModel.InProcess)]
|
||||
[InlineData(HostingModel.OutOfProcess)]
|
||||
public async Task AppOfflineDropped_CanRemoveAppOfflineAfterAddingAndSiteWorks(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
|
|
@ -61,13 +82,12 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
|
||||
var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
|
||||
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
|
||||
private async Task<IISDeploymentResult> DeployApp()
|
||||
private async Task<IISDeploymentResult> DeployApp(HostingModel hostingModel = HostingModel.InProcess)
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(hostingModel: hostingModel, publish: true);
|
||||
|
||||
return await DeployAsync(deploymentParameters);
|
||||
}
|
||||
|
|
@ -118,18 +138,21 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
Assert.True(hostShutdownToken.IsCancellationRequested);
|
||||
}
|
||||
|
||||
private async Task<IISDeploymentResult> AssertStarts()
|
||||
private async Task<IISDeploymentResult> AssertStarts(HostingModel hostingModel)
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
await AssertRunning(deploymentResult);
|
||||
|
||||
return deploymentResult;
|
||||
}
|
||||
|
||||
private static async Task AssertRunning(IISDeploymentResult deploymentResult)
|
||||
{
|
||||
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello World", responseText);
|
||||
|
||||
return deploymentResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
[ConditionalFact]
|
||||
public async Task Authentication_InProcess()
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
deploymentParameters.ServerConfigTemplateContent = GetWindowsAuthConfig();
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
var tempFile = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters();
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = tempFile;
|
||||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
[ConditionalFact]
|
||||
public async Task ServerShutsDownWhenMainExits()
|
||||
{
|
||||
var parameters = Helpers.GetBaseDeploymentParameters();
|
||||
var parameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
var result = await DeployAsync(parameters);
|
||||
|
||||
var response = await result.RetryingHttpClient.GetAsync("/Shutdown");
|
||||
|
|
|
|||
Loading…
Reference in New Issue