Make IISExpress shutdown gracefully. (#1066)
This commit is contained in:
parent
89fda83bbd
commit
256aed8369
|
|
@ -5,36 +5,36 @@
|
|||
<PropertyGroup Label="Package Versions">
|
||||
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
||||
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17099</InternalAspNetCoreSdkPackageVersion>
|
||||
<MicrosoftAspNetCoreAllPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreAllPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpOverridesPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHttpOverridesPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHttpPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpSysSourcesPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreHttpSysSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreAllPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreAllPackageVersion>
|
||||
<MicrosoftAspNetCoreAuthenticationCorePackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreAuthenticationCorePackageVersion>
|
||||
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHostingPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpOverridesPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHttpOverridesPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHttpPackageVersion>
|
||||
<MicrosoftAspNetCoreHttpSysSourcesPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreHttpSysSourcesPackageVersion>
|
||||
<MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.6.0-a-preview1-DeploymentParameters-17085</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34694</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
||||
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreServerKestrelPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview1-34709</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
||||
<MicrosoftBuildFrameworkPackageVersion>15.6.82</MicrosoftBuildFrameworkPackageVersion>
|
||||
<MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
|
||||
<MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>
|
||||
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsLoggingDebugPackageVersion>
|
||||
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34694</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>
|
||||
<MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsConfigurationEnvironmentVariablesPackageVersion>
|
||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsLoggingConsolePackageVersion>
|
||||
<MicrosoftExtensionsLoggingDebugPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsLoggingDebugPackageVersion>
|
||||
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsLoggingPackageVersion>
|
||||
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsLoggingTestingPackageVersion>
|
||||
<MicrosoftExtensionsOptionsPackageVersion>2.2.0-preview1-34709</MicrosoftExtensionsOptionsPackageVersion>
|
||||
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
|
||||
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
|
||||
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview1-26618-02</MicrosoftNETCoreApp22PackageVersion>
|
||||
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34694</MicrosoftNetHttpHeadersPackageVersion>
|
||||
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview1-34709</MicrosoftNetHttpHeadersPackageVersion>
|
||||
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
|
||||
<MicrosoftWebAdministrationPackageVersion>11.1.0</MicrosoftWebAdministrationPackageVersion>
|
||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||
|
|
|
|||
|
|
@ -224,6 +224,13 @@ Language=English
|
|||
%1
|
||||
.
|
||||
|
||||
|
||||
Messageid=1033
|
||||
SymbolicName=ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL
|
||||
Language=English
|
||||
%1
|
||||
.
|
||||
|
||||
;
|
||||
;#endif // _ASPNETCORE_MODULE_MSG_H_
|
||||
;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG L"Sent shutdown HTTP message to process '%d' and received http status '%d'."
|
||||
#define ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG L"Failed to gracefully shutdown application '%s'."
|
||||
#define ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG L"Application '%s' with physical root '%s' failed to load clr and managed application, ErrorCode = '0x%x."
|
||||
#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_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'."
|
||||
|
|
|
|||
|
|
@ -126,6 +126,14 @@ Finished:
|
|||
//
|
||||
exit(hr);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTILITY::LogEventF(g_hEventLog,
|
||||
EVENTLOG_INFORMATION_TYPE,
|
||||
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL,
|
||||
ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG,
|
||||
m_pConfig->QueryConfigPath()->QueryStr());
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
switch (deploymentParameters.ServerType)
|
||||
{
|
||||
case ServerType.IISExpress:
|
||||
return new IIS.IISExpressDeployer(deploymentParameters, loggerFactory);
|
||||
return new IISExpressDeployer(deploymentParameters, loggerFactory);
|
||||
case ServerType.IIS:
|
||||
return new IISDeployer(deploymentParameters, loggerFactory);
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
/// </summary>
|
||||
internal class IISApplication
|
||||
{
|
||||
private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(5);
|
||||
private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(10);
|
||||
private static readonly TimeSpan _retryDelay = TimeSpan.FromMilliseconds(200);
|
||||
private readonly ServerManager _serverManager = new ServerManager();
|
||||
private readonly DeploymentParameters _deploymentParameters;
|
||||
|
|
@ -32,6 +32,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
"config",
|
||||
"applicationhost.config");
|
||||
|
||||
public Process HostProcess { get; set; }
|
||||
|
||||
public IISApplication(DeploymentParameters deploymentParameters, ILogger logger)
|
||||
{
|
||||
_deploymentParameters = deploymentParameters;
|
||||
|
|
@ -63,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
}
|
||||
AddTemporaryAppHostConfig();
|
||||
|
||||
ConfigureAppPool(contentRoot);
|
||||
var apppool = ConfigureAppPool(contentRoot);
|
||||
|
||||
ConfigureSite(contentRoot, port);
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
|
||||
_serverManager.CommitChanges();
|
||||
|
||||
await WaitUntilSiteStarted();
|
||||
await WaitUntilSiteStarted(apppool);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +91,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
config.Save(webConfigFile);
|
||||
}
|
||||
|
||||
private async Task WaitUntilSiteStarted()
|
||||
private async Task WaitUntilSiteStarted(ApplicationPool appPool)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
|
|
@ -98,6 +100,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
try
|
||||
{
|
||||
var site = _serverManager.Sites.FirstOrDefault(s => s.Name.Equals(WebSiteName));
|
||||
|
||||
if (site.State == ObjectState.Started)
|
||||
{
|
||||
_logger.LogInformation($"Site {WebSiteName} has started.");
|
||||
|
|
|
|||
|
|
@ -75,13 +75,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
|
||||
// Warm up time for IIS setup.
|
||||
Logger.LogInformation("Successfully finished IIS application directory setup.");
|
||||
|
||||
return new DeploymentResult(
|
||||
return new IISDeploymentResult(
|
||||
LoggerFactory,
|
||||
IISDeploymentParameters,
|
||||
applicationBaseUri: uri.ToString(),
|
||||
contentRoot: contentRoot,
|
||||
hostShutdownToken: _hostShutdownToken.Token
|
||||
hostShutdownToken: _hostShutdownToken.Token,
|
||||
hostProcess: _application.HostProcess
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||
{
|
||||
|
|
@ -43,6 +44,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
ServerConfigActionList = tempParameters.ServerConfigActionList;
|
||||
WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables;
|
||||
HandlerSettings = tempParameters.HandlerSettings;
|
||||
GracefulShutdown = tempParameters.GracefulShutdown;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +61,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
|
||||
public IDictionary<string, string> HandlerSettings { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
public bool GracefulShutdown { get; set; }
|
||||
|
||||
private Action<XElement> AddWebConfigEnvironmentVariables()
|
||||
{
|
||||
return xElement =>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||
{
|
||||
public class IISDeploymentResult : DeploymentResult
|
||||
{
|
||||
public ILogger Logger { get; set; }
|
||||
public Process HostProcess { get; }
|
||||
|
||||
public IISDeploymentResult(ILoggerFactory loggerFactory,
|
||||
IISDeploymentParameters deploymentParameters,
|
||||
string applicationBaseUri,
|
||||
string contentRoot,
|
||||
CancellationToken hostShutdownToken,
|
||||
Process hostProcess)
|
||||
: base(loggerFactory,
|
||||
deploymentParameters,
|
||||
applicationBaseUri,
|
||||
contentRoot,
|
||||
hostShutdownToken)
|
||||
{
|
||||
HostProcess = hostProcess;
|
||||
Logger = loggerFactory.CreateLogger(deploymentParameters.SiteName);
|
||||
// SocketsHttpHandler isn't available in netstandard2.0
|
||||
RetryingHttpClient = CreateRetryClient(new HttpClientHandler());
|
||||
HttpClient = CreateClient(new HttpClientHandler());
|
||||
}
|
||||
|
||||
public HttpClient CreateRetryClient(HttpMessageHandler messageHandler)
|
||||
{
|
||||
var loggingHandler = new LoggingHandler(messageHandler, Logger);
|
||||
var retryHandler = new RetryHandler(loggingHandler, Logger);
|
||||
return new HttpClient(retryHandler)
|
||||
{
|
||||
BaseAddress = base.HttpClient.BaseAddress
|
||||
};
|
||||
}
|
||||
|
||||
public HttpClient CreateClient(HttpMessageHandler messageHandler)
|
||||
{
|
||||
return new HttpClient(new LoggingHandler(messageHandler, Logger))
|
||||
{
|
||||
BaseAddress = base.HttpClient.BaseAddress
|
||||
};
|
||||
}
|
||||
|
||||
public HttpClient RetryingHttpClient { get; set; }
|
||||
|
||||
public new HttpClient HttpClient { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ using System.Diagnostics;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings";
|
||||
private const string UnableToStartIISExpressMessage = "Unable to start iisexpress.";
|
||||
private const int MaximumAttempts = 5;
|
||||
|
||||
private readonly TimeSpan ShutdownTimeSpan = TimeSpan.FromSeconds(60);
|
||||
private static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?<url>[^""]+)"" for site.*$");
|
||||
|
||||
private Process _hostProcess;
|
||||
|
|
@ -97,12 +98,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
Logger.LogInformation("Application ready at URL: {appUrl}", actualUri);
|
||||
|
||||
// Right now this works only for urls like http://localhost:5001/. Does not work for http://localhost:5001/subpath.
|
||||
return new DeploymentResult(
|
||||
|
||||
return new IISDeploymentResult(
|
||||
LoggerFactory,
|
||||
IISDeploymentParameters,
|
||||
applicationBaseUri: actualUri.ToString(),
|
||||
contentRoot: contentRoot,
|
||||
hostShutdownToken: hostExitToken);
|
||||
hostShutdownToken: hostExitToken,
|
||||
hostProcess: _hostProcess);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +355,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
{
|
||||
using (Logger.BeginScope("Dispose"))
|
||||
{
|
||||
ShutDownIfAnyHostProcess(_hostProcess);
|
||||
if (IISDeploymentParameters.GracefulShutdown)
|
||||
{
|
||||
GracefullyShutdownProcess(_hostProcess);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShutDownIfAnyHostProcess(_hostProcess);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation)
|
||||
&& File.Exists(DeploymentParameters.ServerConfigLocation))
|
||||
|
|
@ -388,6 +398,59 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
|||
}
|
||||
}
|
||||
|
||||
private class WindowsNativeMethods
|
||||
{
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetTopWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
}
|
||||
|
||||
private static void SendStopMessageToProcess(int pid)
|
||||
{
|
||||
for (var ptr = WindowsNativeMethods.GetTopWindow(IntPtr.Zero); ptr != IntPtr.Zero; ptr = WindowsNativeMethods.GetWindow(ptr, 2))
|
||||
{
|
||||
uint num;
|
||||
WindowsNativeMethods.GetWindowThreadProcessId(ptr, out num);
|
||||
if (pid == num)
|
||||
{
|
||||
var hWnd = new HandleRef(null, ptr);
|
||||
WindowsNativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GracefullyShutdownProcess(Process hostProcess)
|
||||
{
|
||||
if (hostProcess != null && !hostProcess.HasExited)
|
||||
{
|
||||
// Calling hostProcess.StandardInput.WriteLine("q") with StandardInput redirected
|
||||
// for the process does not work when stopping IISExpress
|
||||
// Also, hostProcess.CloseMainWindow() doesn't work either.
|
||||
// Instead we have to send WM_QUIT to the iisexpress process via pInvokes.
|
||||
// See: https://stackoverflow.com/questions/4772092/starting-and-stopping-iis-express-programmatically
|
||||
|
||||
SendStopMessageToProcess(hostProcess.Id);
|
||||
if (!hostProcess.WaitForExit((int)ShutdownTimeSpan.TotalMilliseconds))
|
||||
{
|
||||
throw new InvalidOperationException($"iisexpress Process {hostProcess.Id} failed to gracefully shutdown.");
|
||||
}
|
||||
if (hostProcess.ExitCode != 0)
|
||||
{
|
||||
Logger.LogWarning($"IISExpress exit code is non-zero after graceful shutdown. Exit code: {hostProcess.ExitCode}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"iisexpress Process {hostProcess.Id} crashed before shutdown was triggered.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ModifyDotNetExePathInWebConfig()
|
||||
{
|
||||
// We assume the x64 dotnet.exe is on the path so we need to provide an absolute path for x86 scenarios.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||
{
|
||||
public class LoggingHandler: DelegatingHandler
|
||||
{
|
||||
|
|
@ -8,7 +8,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
|
||||
{
|
||||
public class RetryHandler : DelegatingHandler
|
||||
{
|
||||
|
|
@ -20,5 +20,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
EventLogHelpers.VerifyEventLogEvent(TestSink, "Application '.+' started the coreclr in-process successfully.");
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task CheckShutdownEventLogMessage()
|
||||
{
|
||||
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
deploymentParameters.GracefulShutdown = true;
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
await Helpers.AssertStarts(deploymentResult);
|
||||
|
||||
StopServer();
|
||||
|
||||
EventLogHelpers.VerifyEventLogEvent(TestSink, "Application '.+' has shutdown.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||
|
||||
|
||||
await Helpers.AssertStarts(deploymentResult, "HelloWorld");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
{
|
||||
}
|
||||
|
||||
private ApplicationDeployer _deployer;
|
||||
protected ApplicationDeployer _deployer;
|
||||
|
||||
protected virtual async Task<IISDeploymentResult> DeployAsync(IISDeploymentParameters parameters)
|
||||
{
|
||||
|
|
@ -31,11 +31,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
|||
parameters.ServerConfigTemplateContent = parameters.ServerConfigTemplateContent ?? File.ReadAllText("IISExpress.config");
|
||||
}
|
||||
|
||||
|
||||
_deployer = IISApplicationDeployerFactory.Create(parameters, LoggerFactory);
|
||||
|
||||
var result = await _deployer.DeployAsync();
|
||||
|
||||
return new IISDeploymentResult(result, Logger);
|
||||
return (IISDeploymentResult)await _deployer.DeployAsync();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
// 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.Net.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IntegrationTesting
|
||||
{
|
||||
public class IISDeploymentResult
|
||||
{
|
||||
public DeploymentResult DeploymentResult { get; }
|
||||
public ILogger Logger { get; }
|
||||
|
||||
public IISDeploymentResult(DeploymentResult deploymentResult, ILogger logger)
|
||||
{
|
||||
DeploymentResult = deploymentResult;
|
||||
Logger = logger;
|
||||
|
||||
RetryingHttpClient = CreateRetryClient(new SocketsHttpHandler());
|
||||
HttpClient = CreateClient(new SocketsHttpHandler());
|
||||
}
|
||||
|
||||
public HttpClient CreateRetryClient(HttpMessageHandler messageHandler)
|
||||
{
|
||||
return new HttpClient(new RetryHandler(new LoggingHandler(messageHandler, Logger), Logger))
|
||||
{
|
||||
BaseAddress = DeploymentResult.HttpClient.BaseAddress
|
||||
};
|
||||
}
|
||||
|
||||
public HttpClient CreateClient(HttpMessageHandler messageHandler)
|
||||
{
|
||||
return new HttpClient(new LoggingHandler(messageHandler, Logger))
|
||||
{
|
||||
BaseAddress = DeploymentResult.HttpClient.BaseAddress
|
||||
};
|
||||
}
|
||||
|
||||
public HttpClient HttpClient { get; set; }
|
||||
public HttpClient RetryingHttpClient { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Builder;
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
<None Include="$(MSBuildThisFileDirectory)..\..\src\AspNetCoreModuleV2\AspNetCore\bin\$(Configuration)\x64\aspnetcorev2.pdb" CopyToOutputDirectory="PreserveNewest" Visible="true" Link="%(FileName)%(Extension)" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(MicrosoftAspNetCoreHostingPackageVersion)" />
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Server.IntegrationTesting;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
||||
{
|
||||
|
|
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
{
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
|
||||
await AssertAppOffline(deploymentResult);
|
||||
}
|
||||
|
|
@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
var expectedResponse = "The app is offline.";
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot, expectedResponse);
|
||||
AddAppOffline(deploymentResult.ContentRoot, expectedResponse);
|
||||
|
||||
await AssertAppOffline(deploymentResult, expectedResponse);
|
||||
}
|
||||
|
|
@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
{
|
||||
var deploymentResult = await AssertStarts(HostingModel.InProcess);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
|
||||
await AssertStopsProcess(deploymentResult);
|
||||
}
|
||||
|
|
@ -62,9 +63,9 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
// Repeat dropping file and restarting multiple times
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
await AssertAppOffline(deploymentResult);
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
RemoveAppOffline(deploymentResult.ContentRoot);
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
}
|
||||
|
|
@ -76,11 +77,11 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
{
|
||||
var deploymentResult = await DeployApp(hostingModel);
|
||||
|
||||
AddAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
AddAppOffline(deploymentResult.ContentRoot);
|
||||
|
||||
await AssertAppOffline(deploymentResult);
|
||||
|
||||
RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot);
|
||||
RemoveAppOffline(deploymentResult.ContentRoot);
|
||||
|
||||
await AssertRunning(deploymentResult);
|
||||
}
|
||||
|
|
@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess
|
|||
// dropping app_offline will kill the process
|
||||
}
|
||||
|
||||
var hostShutdownToken = deploymentResult.DeploymentResult.HostShutdownToken;
|
||||
var hostShutdownToken = deploymentResult.HostShutdownToken;
|
||||
|
||||
Assert.True(hostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout));
|
||||
Assert.True(hostShutdownToken.IsCancellationRequested);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
|
||||
var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true };
|
||||
var httpClient = deploymentResult.DeploymentResult.CreateHttpClient(httpClientHandler);
|
||||
var httpClient = deploymentResult.CreateHttpClient(httpClientHandler);
|
||||
|
||||
response = await httpClient.GetAsync("/AuthenticationAnonymous");
|
||||
responseText = await response.Content.ReadAsStringAsync();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,30 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
var result = await DeployAsync(parameters);
|
||||
|
||||
var response = await result.RetryingHttpClient.GetAsync("/Shutdown");
|
||||
Assert.True(result.DeploymentResult.HostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout));
|
||||
Assert.True(result.HostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout));
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task GracefulShutdown_DoesNotCrashProcess()
|
||||
{
|
||||
var parameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
parameters.GracefulShutdown = true;
|
||||
var result = await DeployAsync(parameters);
|
||||
|
||||
var response = await result.RetryingHttpClient.GetAsync("/HelloWorld");
|
||||
StopServer();
|
||||
Assert.True(result.HostProcess.ExitCode == 0);
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
public async Task ForcefulShutdown_DoesrashProcess()
|
||||
{
|
||||
var parameters = Helpers.GetBaseDeploymentParameters(publish: true);
|
||||
var result = await DeployAsync(parameters);
|
||||
|
||||
var response = await result.RetryingHttpClient.GetAsync("/HelloWorld");
|
||||
StopServer();
|
||||
Assert.True(result.HostProcess.ExitCode == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
|||
|
||||
private string GetANCMRequestHandlerPath(IISDeploymentResult deploymentResult, string version)
|
||||
{
|
||||
return Path.Combine(deploymentResult.DeploymentResult.ContentRoot,
|
||||
deploymentResult.DeploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(),
|
||||
return Path.Combine(deploymentResult.ContentRoot,
|
||||
deploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(),
|
||||
version,
|
||||
_aspNetCoreDll);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue