diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp index 6c9f5d848269049fbb24a3acf759feaf9f69d6ab..28a5dde1c8c908adba5e06e7d8e17b6a861e6449 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp @@ -133,6 +133,30 @@ APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext) HRESULT APPLICATION_INFO::TryCreateApplication(IHttpContext& pHttpContext, const ShimOptions& options) { + const auto startupEvent = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_STARTUP_SUSPEND_EVENT"); + if (startupEvent.has_value()) + { + LOG_INFOF(L"Startup suspend event %ls", startupEvent.value().c_str()); + + HandleWrapper<NullHandleTraits> eventHandle = OpenEvent(SYNCHRONIZE, false, startupEvent.value().c_str()); + + if (eventHandle == nullptr) + { + LOG_INFOF(L"Unable to open startup suspend event"); + } + else + { + auto const suspendedEventName = startupEvent.value() + L"_suspended"; + + HandleWrapper<NullHandleTraits> suspendedEventHandle = OpenEvent(EVENT_MODIFY_STATE, false, suspendedEventName.c_str()); + if (suspendedEventHandle != nullptr) + { + LOG_LAST_ERROR_IF(!SetEvent(suspendedEventHandle)); + } + LOG_LAST_ERROR_IF(WaitForSingleObject(eventHandle, INFINITE) != WAIT_OBJECT_0); + } + + } RETURN_IF_FAILED(m_handlerResolver.GetApplicationFactory(*pHttpContext.GetApplication(), m_pApplicationFactory, options)); LOG_INFO(L"Creating handler application"); diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs index 0390b5b3df2f127432f41e278dc577b4621676cb..55d4cfc170ddc351127bf7566b6e38a126bd40de 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Net; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; @@ -520,6 +521,41 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(deploymentResult.ContentRoot + "\\", await deploymentResult.HttpClient.GetStringAsync("/ASPNETCORE_IIS_PHYSICAL_PATH")); } + [ConditionalFact] + [RequiresNewShim] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] + public async Task StartupIsSuspendedWhenEventIsUsed() + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(); + deploymentParameters.ApplicationType = ApplicationType.Standalone; + deploymentParameters.EnvironmentVariables["ASPNETCORE_STARTUP_SUSPEND_EVENT"] = "ANCM_TestEvent"; + + var eventPrefix = deploymentParameters.ServerType == ServerType.IISExpress ? "" : "Global\\"; + + var startWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset, eventPrefix + "ANCM_TestEvent"); + var suspendedWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset, eventPrefix + "ANCM_TestEvent_suspended"); + + var deploymentResult = await DeployAsync(deploymentParameters); + + var request = deploymentResult.AssertStarts(); + + Assert.True(suspendedWaitHandle.WaitOne(TimeoutExtensions.DefaultTimeoutValue)); + + // didn't figure out a better way to check that ANCM is waiting to start + var applicationDll = Path.Combine(deploymentResult.ContentRoot, "InProcessWebSite.dll"); + var handlerDll = Path.Combine(deploymentResult.ContentRoot, "aspnetcorev2_inprocess.dll"); + // Make sure application dll is not locked + File.WriteAllBytes(applicationDll, File.ReadAllBytes(applicationDll)); + // Make sure handler dll is not locked + File.WriteAllBytes(handlerDll, File.ReadAllBytes(handlerDll)); + // Make sure request is not completed + Assert.False(request.IsCompleted); + + startWaitHandle.Set(); + + await request; + } + private static void MoveApplication( IISDeploymentParameters parameters, string subdirectory)