diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 64ff041d5c..eac4268e4c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
Contributing
======
-Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo.
+Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/master/CONTRIBUTING.md) in the Home repo.
diff --git a/build/dependencies.props b/build/dependencies.props
index 8e4a0a815d..a1e8c3f738 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -34,6 +34,7 @@
2.0.9
2.1.2
2.2.0-preview1-26618-02
+ 1.0.1
3.0.0-alpha1-10123
15.6.1
11.1.0
diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
index a857706142..4cb6b222cf 100644
--- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
+++ b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp
@@ -3,6 +3,7 @@
#include "aspnetcore_shim_config.h"
+#include "EventLog.h"
#include "config_utility.h"
#include "hostfxr_utility.h"
#include "ahutil.h"
@@ -49,6 +50,7 @@ ASPNETCORE_SHIM_CONFIG::Populate(
else
{
// block unknown hosting value
+ EVENTLOG(g_hEventLog, UNKNOWN_HOSTING_MODEL_ERROR, strHostingModel.QueryStr());
RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
}
diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
index 2be58bcc5c..5ff3e0103f 100644
--- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
+++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj
@@ -195,6 +195,7 @@
+
diff --git a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp
index 396a69ff31..b2c6b69871 100644
--- a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp
@@ -2,7 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include
-#include
+#include
#include "GlobalVersionUtility.h"
diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp
index 3b07cf8645..dff673fee3 100644
--- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp
@@ -3,7 +3,7 @@
#include "PollingAppOfflineApplication.h"
-#include
+#include
#include "SRWExclusiveLock.h"
#include "HandleWrapper.h"
diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h
index e66f5f46c8..592cdb2dc8 100644
--- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h
+++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#pragma once
-#include
+#include
#include "application.h"
#include "requesthandler.h"
diff --git a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
index c15047b235..477c1a0d0a 100644
--- a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
+++ b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc
@@ -224,6 +224,19 @@ Language=English
%1
.
+
+Messageid=1033
+SymbolicName=ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL
+Language=English
+%1
+.
+
+Messageid=1034
+SymbolicName=ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR
+Language=English
+%1
+.
+
;
;#endif // _ASPNETCORE_MODULE_MSG_H_
;
diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
index fd3a65abf8..ab827460bf 100644
--- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
+++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp
@@ -141,7 +141,9 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
auto fullProcessPath = GetAbsolutePathToDotnet(applicationPhysicalPath, processPath);
if (!fullProcessPath.has_value())
{
- return E_FAIL;
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ EVENTLOG(hEventLog, INVALID_PROCESS_PATH, processPath.c_str(), hr);
+ return hr;
}
processPath = fullProcessPath.value();
@@ -149,7 +151,8 @@ HOSTFXR_UTILITY::GetHostFxrParameters(
auto hostFxrPath = GetAbsolutePathToHostFxr(processPath, hEventLog);
if (!hostFxrPath.has_value())
{
- return E_FAIL;
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ return hr;
}
RETURN_IF_FAILED(HOSTFXR_UTILITY::ParseHostfxrArguments(
@@ -368,6 +371,8 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet(
// Only do it if no path is specified
if (requestedPath.has_parent_path())
{
+ WLOG_INFOF(L"Absolute path to dotnet.exe was not found at %s", requestedPath.c_str());
+
return std::nullopt;
}
diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h
index dfdeb08b3a..1315865803 100644
--- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h
+++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h
@@ -5,7 +5,7 @@
#include
#include
-#include
+#include
#include
#include "stringu.h"
diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h
index 2956cce581..ae26e9777f 100644
--- a/src/AspNetCoreModuleV2/CommonLib/resources.h
+++ b/src/AspNetCoreModuleV2/CommonLib/resources.h
@@ -26,8 +26,11 @@
#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_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file."
+#define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_LEVEL EVENTLOG_ERROR_TYPE
#define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Last 4KB characters of captured stdout and stderr logs:\r\n%s"
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Please check the stderr logs for more information."
@@ -48,7 +51,7 @@
#define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information."
#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_LEVEL EVENTLOG_ERROR_TYPE
-#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = %s, ErrorCode = '0x%x'."
+#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = '%s', ErrorCode = '0x%x'."
#define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application."
#define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress."
#define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully."
diff --git a/src/AspNetCoreModuleV2/CommonLib/stdafx.h b/src/AspNetCoreModuleV2/CommonLib/stdafx.h
index d5407df316..b17ae43485 100644
--- a/src/AspNetCoreModuleV2/CommonLib/stdafx.h
+++ b/src/AspNetCoreModuleV2/CommonLib/stdafx.h
@@ -14,4 +14,4 @@
#include
#include
#include
-#include
+#include
diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
index baf73ec9c1..b52b08f833 100644
--- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
+++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp
@@ -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
diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
index fd6382710b..78a02ce72b 100644
--- a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
+++ b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h
@@ -12,7 +12,7 @@
#include
#include
#include
-#include
+#include
#include "Shlwapi.h"
#include
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs
index aaec90971e..8fddbaede6 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs
@@ -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:
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs
index d0c0bfb153..b83e7aa4df 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs
@@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
///
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,33 +65,19 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
}
AddTemporaryAppHostConfig();
- ConfigureAppPool(contentRoot);
+ var apppool = ConfigureAppPool(contentRoot);
ConfigureSite(contentRoot, port);
ConfigureAppHostConfig(contentRoot);
- if (_deploymentParameters.ApplicationType == ApplicationType.Portable)
- {
- ModifyAspNetCoreSectionInWebConfig("processPath", DotNetCommands.GetDotNetExecutable(_deploymentParameters.RuntimeArchitecture));
- }
-
_serverManager.CommitChanges();
- await WaitUntilSiteStarted();
+ await WaitUntilSiteStarted(apppool);
}
}
- private void ModifyAspNetCoreSectionInWebConfig(string key, string value)
- {
- var webConfigFile = Path.Combine(_deploymentParameters.PublishedApplicationRootPath, "web.config");
- var config = XDocument.Load(webConfigFile);
- var element = config.Descendants("aspNetCore").FirstOrDefault();
- element.SetAttributeValue(key, value);
- config.Save(webConfigFile);
- }
-
- private async Task WaitUntilSiteStarted()
+ private async Task WaitUntilSiteStarted(ApplicationPool appPool)
{
var sw = Stopwatch.StartNew();
@@ -98,6 +86,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.");
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs
index f1f4922e88..3f7425fce6 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs
@@ -2,10 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
using Microsoft.Extensions.Logging;
@@ -14,12 +12,17 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
///
/// Deployer for IIS.
///
- public partial class IISDeployer : ApplicationDeployer
+ public partial class IISDeployer : IISDeployerBase
{
private IISApplication _application;
private CancellationTokenSource _hostShutdownToken = new CancellationTokenSource();
public IISDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
+ : base(new IISDeploymentParameters(deploymentParameters), loggerFactory)
+ {
+ }
+
+ public IISDeployer(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
: base(deploymentParameters, loggerFactory)
{
}
@@ -53,31 +56,41 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
DeploymentParameters.ServerConfigTemplateContent = File.ReadAllText("IIS.config");
}
- _application = new IISApplication(DeploymentParameters, Logger);
+ _application = new IISApplication(IISDeploymentParameters, Logger);
// For now, only support using published output
DeploymentParameters.PublishApplicationBeforeDeployment = true;
+
+
+ if (DeploymentParameters.ApplicationType == ApplicationType.Portable)
+ {
+ DefaultWebConfigActions.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection(
+ "processPath",
+ DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture)));
+ }
+
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
DotnetPublish();
contentRoot = DeploymentParameters.PublishedApplicationRootPath;
+ IISDeploymentParameters.AddDebugLogToWebConfig(Path.Combine(contentRoot, $"{_application.WebSiteName}.txt"));
+ RunWebConfigActions();
}
- WebConfigHelpers.AddDebugLogToWebConfig(contentRoot, Path.Combine(contentRoot, $"{_application.WebSiteName}.txt"));
-
var uri = TestUriHelper.BuildTestUri(ServerType.IIS, DeploymentParameters.ApplicationBaseUriHint);
// To prevent modifying the IIS setup concurrently.
await _application.StartIIS(uri, contentRoot);
// Warm up time for IIS setup.
Logger.LogInformation("Successfully finished IIS application directory setup.");
-
- return new DeploymentResult(
+ return new IISDeploymentResult(
LoggerFactory,
- DeploymentParameters,
+ IISDeploymentParameters,
applicationBaseUri: uri.ToString(),
contentRoot: contentRoot,
- hostShutdownToken: _hostShutdownToken.Token
+ hostShutdownToken: _hostShutdownToken.Token,
+ hostProcess: _application.HostProcess
);
}
}
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs
new file mode 100644
index 0000000000..5042a192e3
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs
@@ -0,0 +1,74 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
+{
+ public abstract class IISDeployerBase : ApplicationDeployer
+ {
+ public IISDeploymentParameters IISDeploymentParameters { get; }
+
+ protected List> DefaultWebConfigActions { get; } = new List>();
+
+ public IISDeployerBase(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
+ : base(deploymentParameters, loggerFactory)
+ {
+ IISDeploymentParameters = deploymentParameters;
+ }
+
+ public void RunWebConfigActions()
+ {
+ if (IISDeploymentParameters == null)
+ {
+ return;
+ }
+
+ if (!DeploymentParameters.PublishApplicationBeforeDeployment)
+ {
+ throw new InvalidOperationException("Cannot modify web.config file if no published output.");
+ }
+
+ var path = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config");
+ var webconfig = XDocument.Load(path);
+ var xElement = webconfig.Descendants("system.webServer").Single();
+
+ foreach (var action in DefaultWebConfigActions)
+ {
+ action.Invoke(xElement);
+ }
+
+ foreach (var action in IISDeploymentParameters.WebConfigActionList)
+ {
+ action.Invoke(xElement);
+ }
+
+ webconfig.Save(path);
+ }
+
+
+ public string RunServerConfigActions(string serverConfigString)
+ {
+ if (IISDeploymentParameters == null)
+ {
+ return serverConfigString;
+ }
+
+ var serverConfig = XDocument.Parse(serverConfigString);
+ var xElement = serverConfig.Descendants("configuration").FirstOrDefault();
+
+ foreach (var action in IISDeploymentParameters.ServerConfigActionList)
+ {
+ action.Invoke(xElement);
+ }
+ return xElement.ToString();
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs
new file mode 100644
index 0000000000..ff2365a82a
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs
@@ -0,0 +1,49 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
+{
+ public static class IISDeploymentParameterExtensions
+ {
+ public static void AddDebugLogToWebConfig(this IISDeploymentParameters parameters, string filename)
+ {
+ parameters.HandlerSettings["debugLevel"] = "4";
+ parameters.HandlerSettings["debugFile"] = filename;
+ }
+
+ public static void AddServerConfigAction(this IISDeploymentParameters parameters, Action action)
+ {
+ parameters.ServerConfigActionList.Add(action);
+ }
+
+ public static void AddHttpsToServerConfig(this IISDeploymentParameters parameters)
+ {
+ parameters.ServerConfigActionList.Add(
+ element =>
+ {
+ element.Descendants("binding")
+ .Single()
+ .SetAttributeValue("protocol", "https");
+
+ element.Descendants("access")
+ .Single()
+ .SetAttributeValue("sslFlags", "Ssl, SslNegotiateCert");
+ });
+ }
+
+ public static void AddWindowsAuthToServerConfig(this IISDeploymentParameters parameters)
+ {
+ parameters.ServerConfigActionList.Add(
+ element =>
+ {
+ element.Descendants("windowsAuthentication")
+ .Single()
+ .SetAttributeValue("enabled", "true");
+ });
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs
new file mode 100644
index 0000000000..a22116d557
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs
@@ -0,0 +1,127 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
+{
+ public class IISDeploymentParameters : DeploymentParameters
+ {
+ public IISDeploymentParameters() : base()
+ {
+ WebConfigActionList = CreateDefaultWebConfigActionList();
+ }
+
+ public IISDeploymentParameters(TestVariant variant)
+ : base(variant)
+ {
+ WebConfigActionList = CreateDefaultWebConfigActionList();
+ }
+
+ public IISDeploymentParameters(
+ string applicationPath,
+ ServerType serverType,
+ RuntimeFlavor runtimeFlavor,
+ RuntimeArchitecture runtimeArchitecture)
+ : base(applicationPath, serverType, runtimeFlavor, runtimeArchitecture)
+ {
+ WebConfigActionList = CreateDefaultWebConfigActionList();
+ }
+
+ public IISDeploymentParameters(DeploymentParameters parameters)
+ : base(parameters)
+ {
+ WebConfigActionList = CreateDefaultWebConfigActionList();
+
+ if (parameters is IISDeploymentParameters)
+ {
+ var tempParameters = (IISDeploymentParameters)parameters;
+ WebConfigActionList = tempParameters.WebConfigActionList;
+ ServerConfigActionList = tempParameters.ServerConfigActionList;
+ WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables;
+ HandlerSettings = tempParameters.HandlerSettings;
+ GracefulShutdown = tempParameters.GracefulShutdown;
+ }
+ }
+
+ private IList> CreateDefaultWebConfigActionList()
+ {
+ return new List>() { AddWebConfigEnvironmentVariables(), AddHandlerSettings() };
+ }
+
+ public IList> WebConfigActionList { get; }
+
+ public IList> ServerConfigActionList { get; } = new List>();
+
+ public IDictionary WebConfigBasedEnvironmentVariables { get; set; } = new Dictionary();
+
+ public IDictionary HandlerSettings { get; set; } = new Dictionary();
+
+ public bool GracefulShutdown { get; set; }
+
+ private Action AddWebConfigEnvironmentVariables()
+ {
+ return xElement =>
+ {
+ if (WebConfigBasedEnvironmentVariables.Count == 0)
+ {
+ return;
+ }
+
+ var element = xElement.Descendants("environmentVariables").SingleOrDefault();
+ if (element == null)
+ {
+ element = new XElement("environmentVariables");
+ xElement.Descendants("aspNetCore").SingleOrDefault().Add(element);
+ }
+
+ foreach (var envVar in WebConfigBasedEnvironmentVariables)
+ {
+ CreateOrSetElement(element, envVar.Key, envVar.Value, "environmentVariable");
+ }
+ };
+ }
+
+ private Action AddHandlerSettings()
+ {
+ return xElement =>
+ {
+ if (HandlerSettings.Count == 0)
+ {
+ return;
+ }
+
+ var element = xElement.Descendants("handlerSettings").SingleOrDefault();
+ if (element == null)
+ {
+ element = new XElement("handlerSettings");
+ xElement.Descendants("aspNetCore").SingleOrDefault().Add(element);
+ }
+
+ foreach (var handlerSetting in HandlerSettings)
+ {
+ CreateOrSetElement(element, handlerSetting.Key, handlerSetting.Value, "handlerSetting");
+ }
+ };
+ }
+
+ private static void CreateOrSetElement(XElement rootElement, string name, string value, string elementName)
+ {
+ if (rootElement.Descendants()
+ .Attributes()
+ .Where(attribute => attribute.Value == name)
+ .Any())
+ {
+ return;
+ }
+ var element = new XElement(elementName);
+ element.SetAttributeValue("name", name);
+ element.SetAttributeValue("value", value);
+ rootElement.Add(element);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs
new file mode 100644
index 0000000000..4a9d881900
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs
@@ -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; }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs
index 0cd67cc132..0fea5fa391 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs
@@ -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;
@@ -19,18 +20,23 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
///
/// Deployment helper for IISExpress.
///
- public class IISExpressDeployer : ApplicationDeployer
+ public class IISExpressDeployer : IISDeployerBase
{
private const string IISExpressRunningMessage = "IIS Express is running.";
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 ""(?[^""]+)"" for site.*$");
private Process _hostProcess;
public IISExpressDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
+ : base(new IISDeploymentParameters(deploymentParameters), loggerFactory)
+ {
+ }
+
+ public IISExpressDeployer(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
: base(deploymentParameters, loggerFactory)
{
}
@@ -92,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,
- DeploymentParameters,
+ IISDeploymentParameters,
applicationBaseUri: actualUri.ToString(),
contentRoot: contentRoot,
- hostShutdownToken: hostExitToken);
+ hostShutdownToken: hostExitToken,
+ hostProcess: _hostProcess);
}
}
@@ -272,11 +280,16 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
// For published apps, prefer the content in the web.config, but update it.
- ModifyAspNetCoreSectionInWebConfig(key: "hostingModel",
- value: DeploymentParameters.HostingModel == HostingModel.InProcess ? "inprocess" : "");
- ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString());
+ DefaultWebConfigActions.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection(
+ key: "hostingModel",
+ value: DeploymentParameters.HostingModel == HostingModel.InProcess ? "inprocess" : ""));
+
+ DefaultWebConfigActions.Add(WebConfigHelpers.AddOrModifyHandlerSection(
+ key: "modules",
+ value: DeploymentParameters.AncmVersion.ToString()));
ModifyDotNetExePathInWebConfig();
serverConfig = RemoveRedundantElements(serverConfig);
+ RunWebConfigActions();
}
else
{
@@ -284,6 +297,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
serverConfig = ReplacePlaceholder(serverConfig, "[HostingModel]", DeploymentParameters.HostingModel.ToString());
serverConfig = ReplacePlaceholder(serverConfig, "[AspNetCoreModule]", DeploymentParameters.AncmVersion.ToString());
}
+ serverConfig = RunServerConfigActions(serverConfig);
DeploymentParameters.ServerConfigLocation = Path.GetTempFileName();
Logger.LogDebug("Saving Config to {configPath}", DeploymentParameters.ServerConfigLocation);
@@ -345,7 +359,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))
@@ -381,6 +402,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.
@@ -394,29 +468,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{
throw new Exception($"Unable to find '{executableName}'.'");
}
- ModifyAspNetCoreSectionInWebConfig("processPath", executableName);
+ DefaultWebConfigActions.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", executableName));
}
}
- // Transforms the web.config file to set attributes like hostingModel="inprocess" element
- private void ModifyAspNetCoreSectionInWebConfig(string key, string value)
- {
- var webConfigFile = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config");
- var config = XDocument.Load(webConfigFile);
- var element = config.Descendants("aspNetCore").FirstOrDefault();
- element.SetAttributeValue(key, value);
- config.Save(webConfigFile);
- }
-
- private void ModifyHandlerSectionInWebConfig(string key, string value)
- {
- var webConfigFile = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config");
- var config = XDocument.Load(webConfigFile);
- var element = config.Descendants("handlers").FirstOrDefault().Descendants("add").FirstOrDefault();
- element.SetAttributeValue(key, value);
- config.Save(webConfigFile);
- }
-
// These elements are duplicated in the web.config if you publish. Remove them from the host.config.
private string RemoveRedundantElements(string serverConfig)
{
diff --git a/test/Common.Tests/Utilities/LoggingHandler.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs
similarity index 96%
rename from test/Common.Tests/Utilities/LoggingHandler.cs
rename to src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs
index 9559d8106c..241991f62d 100644
--- a/test/Common.Tests/Utilities/LoggingHandler.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs
@@ -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
{
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
index 0891a315dc..363de4e34f 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj
@@ -15,6 +15,7 @@
+
diff --git a/test/Common.Tests/Utilities/RetryHandler.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs
similarity index 96%
rename from test/Common.Tests/Utilities/RetryHandler.cs
rename to src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs
index 00e1174c7a..4282c3afca 100644
--- a/test/Common.Tests/Utilities/RetryHandler.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs
@@ -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
{
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/TestUriHelper.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/TestUriHelper.cs
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs
index e5c13225b5..8d2af5eb1d 100644
--- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs
+++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs
@@ -2,49 +2,34 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.IO;
using System.Linq;
using System.Xml.Linq;
-using Microsoft.AspNetCore.Server.IntegrationTesting;
-using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS
{
- public class WebConfigHelpers
+ public static class WebConfigHelpers
{
- public static void AddDebugLogToWebConfig(string contentRoot, string filename)
+ public static Action AddOrModifyAspNetCoreSection(string key, string value)
+ => AddAction(key, value, section: "aspNetCore");
+
+ public static Action AddAction(string key, string value, string section)
{
- var path = Path.Combine(contentRoot, "web.config");
- var webconfig = XDocument.Load(path);
- var xElement = webconfig.Descendants("aspNetCore").Single();
-
- var element = xElement.Descendants("handlerSettings").SingleOrDefault();
- if (element == null)
+ return (element) =>
{
- element = new XElement("handlerSettings");
- xElement.Add(element);
- }
-
- CreateOrSetElement(element, "debugLevel", "4");
-
- CreateOrSetElement(element, "debugFile", Path.Combine(contentRoot, filename));
-
- webconfig.Save(path);
+ element.Descendants(section).SingleOrDefault().SetAttributeValue(key, value);
+ };
}
- private static void CreateOrSetElement(XElement rootElement, string name, string value)
+ public static Action AddOrModifyHandlerSection(string key, string value)
{
- if (rootElement.Descendants()
- .Attributes()
- .Where(attribute => attribute.Value == name)
- .Any())
+ return element =>
{
- return;
- }
- var element = new XElement("handlerSetting");
- element.SetAttributeValue("name", name);
- element.SetAttributeValue("value", value);
- rootElement.Add(element);
+ element.Descendants("handlers")
+ .FirstOrDefault()
+ .Descendants("add")
+ .FirstOrDefault()
+ .SetAttributeValue(key, value);
+ };
}
}
}
diff --git a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs
index 176661189c..a2476cea1b 100644
--- a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs
+++ b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs
@@ -1,4 +1,6 @@
-using System;
+// 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;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
@@ -20,5 +22,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.");
+ }
}
}
diff --git a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs
index 6384fd508e..eb3294a537 100644
--- a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs
+++ b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs
@@ -21,17 +21,19 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[InlineData("CheckLogFile")]
public async Task CheckStdoutLoggingToFile(string path)
{
- var deploymentParameters = Helpers.GetBaseDeploymentParameters();
- deploymentParameters.PublishApplicationBeforeDeployment = true;
+ var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
+
+ deploymentParameters.WebConfigActionList.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogEnabled", "true"));
+
+ var pathToLogs = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+ deploymentParameters.WebConfigActionList.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine(pathToLogs, "std")));
var deploymentResult = await DeployAsync(deploymentParameters);
- var pathToLogs = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
try
{
- Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogEnabled", "true");
- Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogFile", Path.Combine(pathToLogs, "std"));
-
await Helpers.AssertStarts(deploymentResult, path);
StopServer();
@@ -63,10 +65,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
- var deploymentResult = await DeployAsync(deploymentParameters);
+ deploymentParameters.WebConfigActionList.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogEnabled", "true"));
+ deploymentParameters.WebConfigActionList.Add(
+ WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine("Q:", "std")));
- Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogEnabled", "true");
- Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogFile", Path.Combine("Q:", "std"));
+ var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult, "HelloWorld");
}
@@ -80,11 +84,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = tempFile;
+ deploymentParameters.AddDebugLogToWebConfig(tempFile);
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.AddDebugLogToWebConfig(deploymentResult.DeploymentResult.ContentRoot, tempFile);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync("/");
StopServer();
@@ -123,11 +126,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStdoutLoggingToPipeWithFirstWrite(string path)
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
-
- var deploymentResult = await DeployAsync(deploymentParameters);
var firstWriteString = path + path;
- Helpers.ModifyEnvironmentVariableCollectionInWebConfig(deploymentResult, "ASPNETCORE_INPROCESS_INITIAL_WRITE", firstWriteString);
+ deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_INITIAL_WRITE"] = firstWriteString;
+
+ var deploymentResult = await DeployAsync(deploymentParameters);
await Helpers.AssertStarts(deploymentResult, path);
@@ -152,9 +155,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = firstTempFile;
+ deploymentParameters.AddDebugLogToWebConfig(secondTempFile);
var deploymentResult = await DeployAsync(deploymentParameters);
- WebConfigHelpers.AddDebugLogToWebConfig(deploymentParameters.PublishedApplicationRootPath, secondTempFile);
var response = await deploymentResult.RetryingHttpClient.GetAsync("/");
diff --git a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs
index 667c47327c..93683b8a78 100644
--- a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs
+++ b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
@@ -25,15 +24,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true);
var randomNumberString = new Random(Guid.NewGuid().GetHashCode()).Next(10000000).ToString();
-
- var environmentVariablesInWebConfig = new Dictionary
- {
- ["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path,
- ["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString
- };
+ deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
+ deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString;
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.AddEnvironmentVariablesToWebConfig(deploymentResult.DeploymentResult.ContentRoot, environmentVariablesInWebConfig);
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
@@ -52,16 +46,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task CheckStdoutWithLargeWrites(string path)
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true);
-
- var environmentVariablesInWebConfig = new Dictionary
- {
- ["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path
- };
+ deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path;
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.AddEnvironmentVariablesToWebConfig(deploymentResult.DeploymentResult.ContentRoot, environmentVariablesInWebConfig);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
diff --git a/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs b/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs
index 876b8e010f..8ae0c7dc89 100644
--- a/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs
+++ b/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
// The default in hosting sets windows auth to true.
// Set it to the IISExpress.config file
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetOutOfProcessTestSitesPath()
};
diff --git a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs
index 4827fcaecc..d23b7836e5 100644
--- a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs
+++ b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.Extensions.Logging.Testing;
using Xunit.Abstractions;
@@ -16,9 +17,9 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
}
- private ApplicationDeployer _deployer;
+ protected ApplicationDeployer _deployer;
- protected virtual async Task DeployAsync(DeploymentParameters parameters)
+ protected virtual async Task DeployAsync(IISDeploymentParameters parameters)
{
if (!parameters.EnvironmentVariables.ContainsKey(DebugEnvironmentVariable))
{
@@ -30,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()
diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs
index 63f09dbac1..f4348514d1 100644
--- a/test/Common.FunctionalTests/Utilities/Helpers.cs
+++ b/test/Common.FunctionalTests/Utilities/Helpers.cs
@@ -2,13 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing;
using Xunit;
@@ -24,117 +24,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite");
public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite");
-
- public static void ModifyAspNetCoreSectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value)
- => ModifyAttributeInWebConfig(deploymentResult, key, value, section: "aspNetCore");
-
- public static void ModifyAttributeInWebConfig(IISDeploymentResult deploymentResult, string key, string value, string section)
- {
- var webConfigFile = GetWebConfigFile(deploymentResult);
- var config = XDocument.Load(webConfigFile);
-
- var element = config.Descendants(section).Single();
- element.SetAttributeValue(key, value);
-
- config.Save(webConfigFile);
- }
-
- public static void ModifyEnvironmentVariableCollectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value)
- {
- var webConfigFile = GetWebConfigFile(deploymentResult);
- var config = XDocument.Load(webConfigFile);
-
- var envVarElement = new XElement("environmentVariable");
- envVarElement.SetAttributeValue("name", key);
- envVarElement.SetAttributeValue("value", value);
-
- config.Descendants("aspNetCore").Single()
- .Descendants("environmentVariables").Single()
- .Add(envVarElement);
-
- config.Save(webConfigFile);
- }
-
- public static void ModifyHandlerSectionInWebConfig(IISDeploymentResult deploymentResult, string handlerVersionValue)
- {
- var webConfigFile = GetWebConfigFile(deploymentResult);
- var config = XDocument.Load(webConfigFile);
-
- var handlerVersionElement = new XElement("handlerSetting");
- handlerVersionElement.SetAttributeValue("name", "handlerVersion");
- handlerVersionElement.SetAttributeValue("value", handlerVersionValue);
-
- config.Descendants("aspNetCore").Single()
- .Add(new XElement("handlerSettings", handlerVersionElement));
-
- config.Save(webConfigFile);
- }
-
- public static void AddDebugLogToWebConfig(string contentRoot, string filename)
- {
- var path = Path.Combine(contentRoot, "web.config");
- var webconfig = XDocument.Load(path);
- var xElement = webconfig.Descendants("aspNetCore").Single();
-
- var element = xElement.Descendants("handlerSettings").SingleOrDefault();
- if (element == null)
- {
- element = new XElement("handlerSettings");
- xElement.Add(element);
- }
-
- CreateOrSetElement(element, "debugLevel", "4", "handlerSetting");
-
- CreateOrSetElement(element, "debugFile", Path.Combine(contentRoot, filename), "handlerSetting");
-
- webconfig.Save(path);
- }
-
- public static void AddEnvironmentVariablesToWebConfig(string contentRoot, IDictionary environmentVariables)
- {
- var path = Path.Combine(contentRoot, "web.config");
- var webconfig = XDocument.Load(path);
- var xElement = webconfig.Descendants("aspNetCore").Single();
-
- var element = xElement.Descendants("environmentVariables").SingleOrDefault();
- if (element == null)
- {
- element = new XElement("environmentVariables");
- xElement.Add(element);
- }
-
- foreach (var envVar in environmentVariables)
- {
- CreateOrSetElement(element, envVar.Key, envVar.Value, "environmentVariable");
- }
-
- webconfig.Save(path);
- }
-
- public static void CreateOrSetElement(XElement rootElement, string name, string value, string elementName)
- {
- if (rootElement.Descendants()
- .Attributes()
- .Where(attribute => attribute.Value == name)
- .Any())
- {
- return;
- }
- var element = new XElement(elementName);
- element.SetAttributeValue("name", name);
- element.SetAttributeValue("value", value);
- rootElement.Add(element);
- }
-
+
// Defaults to inprocess specific deployment parameters
- public static DeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false)
+ public static IISDeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false)
{
if (site == null)
{
site = hostingModel == HostingModel.InProcess ? "InProcessWebSite" : "OutOfProcessWebSite";
}
- return new DeploymentParameters(GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
+ return new IISDeploymentParameters(GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
TargetFramework = Tfm.NetCoreApp22,
ApplicationType = ApplicationType.Portable,
@@ -144,9 +43,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
};
}
- private static string GetWebConfigFile(IISDeploymentResult deploymentResult)
- => Path.Combine(deploymentResult.DeploymentResult.ContentRoot, "web.config");
-
public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld")
{
var response = await deploymentResult.RetryingHttpClient.GetAsync(path);
diff --git a/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs b/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs
deleted file mode 100644
index 8e39634f2b..0000000000
--- a/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs
+++ /dev/null
@@ -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; }
- }
-}
diff --git a/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs b/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs
index d4c74c551b..a20a5e2e0e 100644
--- a/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs
+++ b/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs
@@ -1,11 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Xunit.Abstractions;
@@ -16,36 +11,5 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities
public IISFunctionalTestBase(ITestOutputHelper output = null) : base(output)
{
}
-
- protected string GetServerConfig(Action transform)
- {
- var doc = XDocument.Load(DeployerSelector.ServerType == ServerType.IIS ? "IIS.config" : "IISExpress.config");
- transform?.Invoke(doc.Root);
- return doc.ToString();
- }
-
- protected string GetHttpsServerConfig()
- {
- return GetServerConfig(
- element => {
- element.Descendants("binding")
- .Single()
- .SetAttributeValue("protocol", "https");
-
- element.Descendants("access")
- .Single()
- .SetAttributeValue("sslFlags", "Ssl, SslNegotiateCert");
- });
- }
-
- protected string GetWindowsAuthConfig()
- {
- return GetServerConfig(
- element => {
- element.Descendants("windowsAuthentication")
- .Single()
- .SetAttributeValue("enabled", "true");
- });
- }
}
}
diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
index d8fd3342ed..787276a8fa 100644
--- a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
+++ b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
@@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
var logging = AssemblyTestLog.ForAssembly(typeof(IISTestSiteFixture).Assembly);
- var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(),
+ var deploymentParameters = new IISDeploymentParameters(Helpers.GetInProcessTestSitesPath(),
DeployerSelector.ServerType,
RuntimeFlavor.CoreClr,
RuntimeArchitecture.x64)
diff --git a/test/CommonLibTests/stdafx.h b/test/CommonLibTests/stdafx.h
index 33d3008f40..93dffac456 100644
--- a/test/CommonLibTests/stdafx.h
+++ b/test/CommonLibTests/stdafx.h
@@ -17,7 +17,7 @@
#include
#include
#include
-#include
+#include
#include
#include
diff --git a/test/IIS.Tests/Utilities/TestServer.cs b/test/IIS.Tests/Utilities/TestServer.cs
index c64fe4fbe9..4adaaff776 100644
--- a/test/IIS.Tests/Utilities/TestServer.cs
+++ b/test/IIS.Tests/Utilities/TestServer.cs
@@ -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;
diff --git a/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj b/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj
index cbd3d05b6b..3ae8fcffe8 100644
--- a/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj
+++ b/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj
@@ -29,7 +29,6 @@
-
diff --git a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
index b7e850cdb8..265907542f 100644
--- a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs
@@ -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);
diff --git a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
index 31179b1ecf..5105b753c8 100644
--- a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs
@@ -5,6 +5,7 @@ using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
@@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task Authentication_InProcess()
{
var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true);
- deploymentParameters.ServerConfigTemplateContent = GetWindowsAuthConfig();
+ deploymentParameters.AddWindowsAuthToServerConfig();
var deploymentResult = await DeployAsync(deploymentParameters);
@@ -45,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();
diff --git a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
index 179c6bd198..b1ab071c5d 100644
--- a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs
@@ -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);
}
}
}
diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs
index 4de6ceba3d..36812d3f2e 100644
--- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs
+++ b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs
@@ -8,6 +8,7 @@ using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -27,8 +28,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
// Point to dotnet installed in user profile.
await AssertStarts(
- deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%"),
- deploymentParameters => deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation);
+ deploymentParameters =>
+ {
+ deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation;
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", "%DotnetPath%"));
+ }
+ );
}
[ConditionalTheory]
@@ -38,14 +43,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task InvalidProcessPath_ExpectServerError(string path)
{
var deploymentParameters = GetBaseDeploymentParameters();
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path));
+
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", path);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
+
+ EventLogHelpers.VerifyEventLogEvent(TestSink, @"Invalid or unknown processPath provided in web\.config: processPath = '.+', ErrorCode = '0x80070002'\.");
}
[ConditionalFact]
@@ -54,16 +61,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf("."));
await AssertStarts(
- deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension));
+ deploymentParameters =>
+ {
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
+ }
+ );
}
[ConditionalFact]
public async Task StartsWithDotnetLocationUppercase()
{
var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")).ToUpperInvariant();
-
await AssertStarts(
- deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension));
+ deploymentParameters =>
+ {
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension));
+ }
+ );
}
[ConditionalTheory]
@@ -72,14 +86,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task StartsWithDotnetOnThePath(string path)
{
await AssertStarts(
- deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", path),
- deploymentParameters => deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation));
+ deploymentParameters =>
+ {
+ deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation);
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path));
+ }
+ );
// Verify that in this scenario where.exe was invoked only once by shim and request handler uses cached value
Assert.Equal(1, TestSink.Writes.Count(w => w.Message.Contains("Invoking where.exe to find dotnet.exe")));
}
- private async Task AssertStarts(Action postDeploy, Action preDeploy = null)
+ private async Task AssertStarts(Action preDeploy = null)
{
var deploymentParameters = GetBaseDeploymentParameters();
@@ -87,8 +105,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var deploymentResult = await DeployAsync(deploymentParameters);
- postDeploy?.Invoke(deploymentResult);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
var responseText = await response.Content.ReadAsStringAsync();
@@ -105,7 +121,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[MemberData(nameof(TestVariants))]
public async Task HelloWorld(TestVariant variant)
{
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetInProcessTestSitesPath(),
PublishApplicationBeforeDeployment = true
@@ -131,10 +147,25 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
Assert.Contains(TestSink.Writes, context => context.Message.Contains("Application is running inside IIS process but is not configured to use IIS server"));
}
- // Defaults to inprocess specific deployment parameters
- public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
+ [ConditionalFact]
+ public async Task CheckInvalidHostingModelParameter()
{
- return new DeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
+ var deploymentParameters = GetBaseDeploymentParameters();
+ deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("hostingModel", "bogus"));
+
+ var deploymentResult = await DeployAsync(deploymentParameters);
+
+ var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld");
+
+ Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
+
+ EventLogHelpers.VerifyEventLogEvent(TestSink, "Unknown hosting model 'bogus'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file.");
+ }
+
+ // Defaults to inprocess specific deployment parameters
+ public static IISDeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite")
+ {
+ return new IISDeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
TargetFramework = Tfm.NetCoreApp22,
ApplicationType = ApplicationType.Portable,
diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs
index fd53c0ffbb..8ad7a70665 100644
--- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs
+++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs
@@ -1,16 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
-using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
@@ -28,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
deploymentParameters.PublishApplicationBeforeDeployment = false;
- deploymentParameters.ServerConfigTemplateContent = GetServerConfig(
+ deploymentParameters.AddServerConfigAction(
element =>
{
var handlerVersionElement = new XElement("handlerSetting");
@@ -52,11 +51,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task GlobalVersion_NewVersionNumber_Fails(string version)
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
+ deploymentParameters.HandlerSettings["handlerVersion"] = version;
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest);
Assert.False(response.IsSuccessStatusCode);
}
@@ -68,11 +66,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
{
var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
deploymentParameters.AdditionalPublishParameters = $"{_outOfProcessVersionVariable}{version}";
+ deploymentParameters.HandlerSettings["handlerVersion"] = version;
var deploymentResult = await DeployAsync(deploymentParameters);
- Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version);
-
var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest);
var responseText = await response.Content.ReadAsStringAsync();
Assert.Equal(_helloWorldResponse, responseText);
@@ -140,9 +137,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
AssertLoadedVersion(version);
}
- private DeploymentParameters GetGlobalVersionBaseDeploymentParameters()
+ private IISDeploymentParameters GetGlobalVersionBaseDeploymentParameters()
{
- return new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
+ return new IISDeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
TargetFramework = Tfm.NetCoreApp22,
ApplicationType = ApplicationType.Portable,
@@ -155,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);
}
diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs b/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs
index 543481ee14..ff9996c851 100644
--- a/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs
+++ b/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -33,13 +34,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public async Task HttpsHelloWorld(TestVariant variant)
{
var port = TestPortHelper.GetNextSSLPort();
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(),
- ApplicationBaseUriHint = $"https://localhost:{port}/",
- ServerConfigTemplateContent = GetHttpsServerConfig()
+ ApplicationBaseUriHint = $"https://localhost:{port}/"
};
+ deploymentParameters.AddHttpsToServerConfig();
+
var deploymentResult = await DeployAsync(deploymentParameters);
var handler = new HttpClientHandler
@@ -71,13 +73,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
private async Task HttpsHelloWorldCerts(TestVariant variant, bool sendClientCert)
{
var port = TestPortHelper.GetNextSSLPort();
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(),
ApplicationBaseUriHint = $"https://localhost:{port}/",
- ServerConfigTemplateContent = GetHttpsServerConfig()
};
+ deploymentParameters.AddHttpsToServerConfig();
+
var deploymentResult = await DeployAsync(deploymentParameters);
var handler = new HttpClientHandler
diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs b/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs
index 9aab93a56f..437f019f52 100644
--- a/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs
+++ b/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs
@@ -6,6 +6,7 @@ using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -31,13 +32,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[MemberData(nameof(TestVariants))]
public async Task NtlmAuthentication(TestVariant variant)
{
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(),
- ApplicationBaseUriHint = $"http://localhost:0/",
- ServerConfigTemplateContent = GetWindowsAuthConfig()
+ ApplicationBaseUriHint = $"http://localhost:0/"
};
+ deploymentParameters.AddWindowsAuthToServerConfig();
+
var result = await DeployAsync(deploymentParameters);
var response = await result.RetryingHttpClient.GetAsync("/HelloWorld");
diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs
index 83d6a8e20a..038f57029d 100644
--- a/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs
+++ b/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -27,11 +28,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
[MemberData(nameof(TestVariants))]
public async Task WindowsAuthTest(TestVariant variant)
{
- var deploymentParameters = new DeploymentParameters(variant)
+ var deploymentParameters = new IISDeploymentParameters(variant)
{
ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(),
- ServerConfigTemplateContent = GetWindowsAuthConfig()
};
+ deploymentParameters.AddWindowsAuthToServerConfig();
// The default in hosting sets windows auth to true.
var deploymentResult = await DeployAsync(deploymentParameters);
diff --git a/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs b/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs
index dc64262d00..316a87f9b3 100644
--- a/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs
+++ b/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
@@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
private async Task UpgradeFeatureDetectionDeployer(bool disableWebSocket, string sitePath, string expected, HostingModel hostingModel)
{
- var deploymentParameters = new DeploymentParameters(sitePath, DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
+ var deploymentParameters = new IISDeploymentParameters(sitePath, DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
TargetFramework = Tfm.NetCoreApp22,
ApplicationType = ApplicationType.Portable,
@@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
if (disableWebSocket)
{
// For IIS, we need to modify the apphost.config file
- deploymentParameters.ServerConfigTemplateContent = GetServerConfig(
+ deploymentParameters.AddServerConfigAction(
element => element.Descendants("webSocket")
.Single()
.SetAttributeValue("enabled", "false"));