From 8d55a447d480bb826cf0088718bbea200b2537bb Mon Sep 17 00:00:00 2001 From: "Chris Ross (ASP.NET)" Date: Fri, 25 May 2018 15:19:25 -0700 Subject: [PATCH] Allow running some IIS Express variants without publishing #1431 --- .../Common/DeploymentParameters.cs | 2 +- .../Common/DotNetCommands.cs | 2 +- .../Deployers/ApplicationDeployer.cs | 16 + .../Deployers/IISExpressDeployer.cs | 232 ++-- .../RemoteWindowsDeployer.cs | 12 +- .../Deployers/SelfHostDeployer.cs | 16 - .../Http.config | 1034 +++++++++++++++++ ...spNetCore.Server.IntegrationTesting.csproj | 4 + .../TestMatrix.cs | 2 +- 9 files changed, 1229 insertions(+), 91 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting/Http.config diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DeploymentParameters.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DeploymentParameters.cs index a687a542b3..968647edba 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DeploymentParameters.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DeploymentParameters.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting public string ServerConfigLocation { get; set; } - public string SiteName { get; set; } + public string SiteName { get; set; } = "HttpTestSite"; public string ApplicationPath { get; set; } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DotNetCommands.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DotNetCommands.cs index 38f84d5044..d9f5577056 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DotNetCommands.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Common/DotNetCommands.cs @@ -5,7 +5,7 @@ using System; using System.IO; using System.Runtime.InteropServices; -namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common +namespace Microsoft.AspNetCore.Server.IntegrationTesting { internal static class DotNetCommands { diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/ApplicationDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/ApplicationDeployer.cs index ddaac89711..a9212b0d54 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/ApplicationDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/ApplicationDeployer.cs @@ -161,6 +161,22 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting } } + protected string GetDotNetExeForArchitecture() + { + var executableName = DotnetCommandName; + // We expect x64 dotnet.exe to be on the path but we have to go searching for the x86 version. + if (DotNetCommands.IsRunningX86OnX64(DeploymentParameters.RuntimeArchitecture)) + { + executableName = DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture); + if (!File.Exists(executableName)) + { + throw new Exception($"Unable to find '{executableName}'.'"); + } + } + + return executableName; + } + protected void ShutDownIfAnyHostProcess(Process hostProcess) { if (hostProcess != null && !hostProcess.HasExited) diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/IISExpressDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/IISExpressDeployer.cs index 91c9c7eae3..1bdc58ec8a 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/IISExpressDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/IISExpressDeployer.cs @@ -3,9 +3,9 @@ using System; 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; @@ -42,15 +42,52 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting // Start timer StartTimer(); - // For now we always auto-publish. Otherwise we'll have to write our own local web.config for the HttpPlatformHandler - DotnetPublish(); + // For an unpublished application the dllroot points pre-built dlls like projectdir/bin/debug/net461/ + // and contentRoot points to the project directory so you get things like static assets. + // For a published app both point to the publish directory. + var dllRoot = CheckIfPublishIsRequired(); + var contentRoot = string.Empty; + if (DeploymentParameters.PublishApplicationBeforeDeployment) + { + DotnetPublish(); + contentRoot = DeploymentParameters.PublishedApplicationRootPath; + dllRoot = contentRoot; + } + else + { + // Core+Standalone always publishes. This must be Clr+Standalone or Core+Portable. + // Update processPath and arguments for our current scenario + contentRoot = DeploymentParameters.ApplicationPath; - var contentRoot = DeploymentParameters.PublishedApplicationRootPath; + var executableExtension = DeploymentParameters.ApplicationType == ApplicationType.Portable ? ".dll" : ".exe"; + var entryPoint = Path.Combine(dllRoot, DeploymentParameters.ApplicationName + executableExtension); + + var executableName = string.Empty; + var executableArgs = string.Empty; + + if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Portable) + { + executableName = GetDotNetExeForArchitecture(); + executableArgs = entryPoint; + } + else + { + executableName = entryPoint; + } + + Logger.LogInformation("Executing: {exe} {args}", executableName, executableArgs); + DeploymentParameters.EnvironmentVariables["LAUNCHER_PATH"] = executableName; + DeploymentParameters.EnvironmentVariables["LAUNCHER_ARGS"] = executableArgs; + + // CurrentDirectory will point to bin/{config}/{tfm}, but the config and static files aren't copied, point to the app base instead. + Logger.LogInformation("ContentRoot: {path}", DeploymentParameters.ApplicationPath); + DeploymentParameters.EnvironmentVariables["ASPNETCORE_CONTENTROOT"] = DeploymentParameters.ApplicationPath; + } var testUri = TestUriHelper.BuildTestUri(ServerType.IISExpress, DeploymentParameters.ApplicationBaseUriHint); // Launch the host process. - var (actualUri, hostExitToken) = await StartIISExpressAsync(testUri, contentRoot); + var (actualUri, hostExitToken) = await StartIISExpressAsync(testUri, contentRoot, dllRoot); Logger.LogInformation("Application ready at URL: {appUrl}", actualUri); @@ -64,7 +101,43 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting } } - private async Task<(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot) + private string CheckIfPublishIsRequired() + { + var targetFramework = DeploymentParameters.TargetFramework; + + // IISIntegration uses this layout + var dllRoot = Path.Combine(DeploymentParameters.ApplicationPath, "bin", DeploymentParameters.RuntimeArchitecture.ToString(), + DeploymentParameters.Configuration, targetFramework); + + if (!Directory.Exists(dllRoot)) + { + // Most repos use this layout + dllRoot = Path.Combine(DeploymentParameters.ApplicationPath, "bin", DeploymentParameters.Configuration, targetFramework); + + if (!Directory.Exists(dllRoot)) + { + // The bits we need weren't pre-compiled, compile on publish + DeploymentParameters.PublishApplicationBeforeDeployment = true; + } + else if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr + && DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86) + { + // x64 is the default. Publish to rebuild for the right bitness + DeploymentParameters.PublishApplicationBeforeDeployment = true; + } + } + + if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr + && DeploymentParameters.ApplicationType == ApplicationType.Standalone) + { + // Publish is always required to get the correct standalone files in the output directory + DeploymentParameters.PublishApplicationBeforeDeployment = true; + } + + return dllRoot; + } + + private async Task<(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot, string dllRoot) { using (Logger.BeginScope("StartIISExpress")) { @@ -74,60 +147,17 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting port = (uri.Scheme == "https") ? TestPortHelper.GetNextSSLPort() : TestPortHelper.GetNextPort(); } + Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); + PrepareConfig(contentRoot, dllRoot, port); + + var parameters = string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) ? + string.Format("/port:{0} /path:\"{1}\" /trace:error", uri.Port, contentRoot) : + string.Format("/site:{0} /config:{1} /trace:error", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); + + var iisExpressPath = GetIISExpressPath(); + for (var attempt = 0; attempt < MaximumAttempts; attempt++) { - Logger.LogInformation("Attempting to start IIS Express on port: {port}", port); - - if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigTemplateContent)) - { - var serverConfig = DeploymentParameters.ServerConfigTemplateContent; - - // Pass on the applicationhost.config to iis express. With this don't need to pass in the /path /port switches as they are in the applicationHost.config - // We take a copy of the original specified applicationHost.Config to prevent modifying the one in the repo. - serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMPath]", dllName: "aspnetcore.dll", serverConfig, contentRoot); - - serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMV2Path]", dllName: "aspnetcorev2.dll", serverConfig, contentRoot); - - Logger.LogDebug("Writing ApplicationPhysicalPath '{applicationPhysicalPath}' to config", contentRoot); - Logger.LogDebug("Writing Port '{port}' to config", port); - serverConfig = - serverConfig - .Replace("[ApplicationPhysicalPath]", contentRoot) - .Replace("[PORT]", port.ToString()); - - DeploymentParameters.ServerConfigLocation = Path.GetTempFileName(); - - if (serverConfig.Contains("[HostingModel]")) - { - var hostingModel = DeploymentParameters.HostingModel.ToString(); - serverConfig.Replace("[HostingModel]", hostingModel); - Logger.LogDebug("Writing HostingModel '{hostingModel}' to config", hostingModel); - } - - Logger.LogDebug("Saving Config to {configPath}", DeploymentParameters.ServerConfigLocation); - - if (Logger.IsEnabled(LogLevel.Trace)) - { - Logger.LogTrace($"Config File Content:{Environment.NewLine}===START CONFIG==={Environment.NewLine}{{configContent}}{Environment.NewLine}===END CONFIG===", serverConfig); - } - - File.WriteAllText(DeploymentParameters.ServerConfigLocation, serverConfig); - } - - if (DeploymentParameters.HostingModel == HostingModel.InProcess) - { - ModifyAspNetCoreSectionInWebConfig(key: "hostingModel", value: "inprocess"); - } - - ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString()); - ModifyDotNetExePathInWebConfig(); - - var parameters = string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation) ? - string.Format("/port:{0} /path:\"{1}\" /trace:error", uri.Port, contentRoot) : - string.Format("/site:{0} /config:{1} /trace:error", DeploymentParameters.SiteName, DeploymentParameters.ServerConfigLocation); - - var iisExpressPath = GetIISExpressPath(); - Logger.LogInformation("Executing command : {iisExpress} {parameters}", iisExpressPath, parameters); var startInfo = new ProcessStartInfo @@ -197,7 +227,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting // just in case we missed one -anurse if (!await started.Task.TimeoutAfter(TimeSpan.FromMinutes(10))) { - Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", _hostProcess.Id, port); + Logger.LogInformation("iisexpress Process {pid} failed to bind to port {port}, trying again", process.Id, port); // Wait for the process to exit and try again process.WaitForExit(30 * 1000); @@ -217,15 +247,69 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting } } - private string ModifyANCMPathInConfig(string replaceFlag, string dllName, string serverConfig, string contentRoot) + private void PrepareConfig(string contentRoot, string dllRoot, int port) + { + // Config is required. If not present then fall back to one we carry with us. + if (string.IsNullOrEmpty(DeploymentParameters.ServerConfigTemplateContent)) + { + using (var stream = GetType().Assembly.GetManifestResourceStream("Microsoft.AspNetCore.Server.IntegrationTesting.Http.config")) + using (var reader = new StreamReader(stream)) + { + DeploymentParameters.ServerConfigTemplateContent = reader.ReadToEnd(); + } + } + + var serverConfig = DeploymentParameters.ServerConfigTemplateContent; + + // Pass on the applicationhost.config to iis express. With this don't need to pass in the /path /port switches as they are in the applicationHost.config + // We take a copy of the original specified applicationHost.Config to prevent modifying the one in the repo. + serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMPath]", dllName: "aspnetcore.dll", serverConfig, dllRoot); + serverConfig = ModifyANCMPathInConfig(replaceFlag: "[ANCMV2Path]", dllName: "aspnetcorev2.dll", serverConfig, dllRoot); + + serverConfig = ReplacePlaceholder(serverConfig, "[PORT]", port.ToString(CultureInfo.InvariantCulture)); + serverConfig = ReplacePlaceholder(serverConfig, "[ApplicationPhysicalPath]", contentRoot); + + 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()); + ModifyDotNetExePathInWebConfig(); + serverConfig = RemoveRedundantElements(serverConfig); + } + else + { + // The elements normally in the web.config are in the applicationhost.config for unpublished apps. + serverConfig = ReplacePlaceholder(serverConfig, "[HostingModel]", DeploymentParameters.HostingModel.ToString()); + serverConfig = ReplacePlaceholder(serverConfig, "[AspNetCoreModule]", DeploymentParameters.AncmVersion.ToString()); + } + + DeploymentParameters.ServerConfigLocation = Path.GetTempFileName(); + Logger.LogDebug("Saving Config to {configPath}", DeploymentParameters.ServerConfigLocation); + + File.WriteAllText(DeploymentParameters.ServerConfigLocation, serverConfig); + } + + private string ReplacePlaceholder(string content, string field, string value) + { + if (content.Contains(field)) + { + content = content.Replace(field, value); + Logger.LogDebug("Writing {field} '{value}' to config", field, value); + } + return content; + } + + private string ModifyANCMPathInConfig(string replaceFlag, string dllName, string serverConfig, string dllRoot) { if (serverConfig.Contains(replaceFlag)) { var arch = DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x64 ? $@"x64\{dllName}" : $@"x86\{dllName}"; - var ancmFile = Path.Combine(contentRoot, arch); + var ancmFile = Path.Combine(dllRoot, arch); if (!File.Exists(Environment.ExpandEnvironmentVariables(ancmFile))) { - ancmFile = Path.Combine(contentRoot, dllName); + ancmFile = Path.Combine(dllRoot, dllName); if (!File.Exists(Environment.ExpandEnvironmentVariables(ancmFile))) { throw new FileNotFoundException("AspNetCoreModule could not be found.", ancmFile); @@ -263,7 +347,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting { ShutDownIfAnyHostProcess(_hostProcess); - if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation) + if (!string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) && File.Exists(DeploymentParameters.ServerConfigLocation)) { // Delete the temp applicationHostConfig that we created. @@ -317,7 +401,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting // Transforms the web.config file to set attributes like hostingModel="inprocess" element private void ModifyAspNetCoreSectionInWebConfig(string key, string value) { - var webConfigFile = $"{DeploymentParameters.PublishedApplicationRootPath}/web.config"; + var webConfigFile = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"); var config = XDocument.Load(webConfigFile); var element = config.Descendants("aspNetCore").FirstOrDefault(); element.SetAttributeValue(key, value); @@ -326,11 +410,27 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting private void ModifyHandlerSectionInWebConfig(string key, string value) { - var webConfigFile = $"{DeploymentParameters.PublishedApplicationRootPath}/web.config"; + 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); + 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) + { + var hostConfig = XDocument.Parse(serverConfig); + + var coreElement = hostConfig.Descendants("aspNetCore").FirstOrDefault(); + coreElement?.Remove(); + + var handlersElement = hostConfig.Descendants("handlers").First(); + var handlerElement = handlersElement.Descendants("add") + .Where(x => x.Attribute("name").Value == "aspNetCore").FirstOrDefault(); + handlerElement?.Remove(); + + return hostConfig.ToString(); } } } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs index dc764bf98a..f33b285d63 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs @@ -39,37 +39,37 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting $" Supported server types are {nameof(ServerType.Kestrel)}, {nameof(ServerType.IIS)} and {nameof(ServerType.HttpSys)}"); } - if (string.IsNullOrWhiteSpace(_deploymentParameters.ServerName)) + if (string.IsNullOrEmpty(_deploymentParameters.ServerName)) { throw new ArgumentException($"Invalid value '{_deploymentParameters.ServerName}' for {nameof(RemoteWindowsDeploymentParameters.ServerName)}"); } - if (string.IsNullOrWhiteSpace(_deploymentParameters.ServerAccountName)) + if (string.IsNullOrEmpty(_deploymentParameters.ServerAccountName)) { throw new ArgumentException($"Invalid value '{_deploymentParameters.ServerAccountName}' for {nameof(RemoteWindowsDeploymentParameters.ServerAccountName)}." + " Account credentials are required to enable creating a powershell session to the remote server."); } - if (string.IsNullOrWhiteSpace(_deploymentParameters.ServerAccountPassword)) + if (string.IsNullOrEmpty(_deploymentParameters.ServerAccountPassword)) { throw new ArgumentException($"Invalid value '{_deploymentParameters.ServerAccountPassword}' for {nameof(RemoteWindowsDeploymentParameters.ServerAccountPassword)}." + " Account credentials are required to enable creating a powershell session to the remote server."); } if (_deploymentParameters.ApplicationType == ApplicationType.Portable - && string.IsNullOrWhiteSpace(_deploymentParameters.DotnetRuntimePath)) + && string.IsNullOrEmpty(_deploymentParameters.DotnetRuntimePath)) { throw new ArgumentException($"Invalid value '{_deploymentParameters.DotnetRuntimePath}' for {nameof(RemoteWindowsDeploymentParameters.DotnetRuntimePath)}. " + "It must be non-empty for portable apps."); } - if (string.IsNullOrWhiteSpace(_deploymentParameters.RemoteServerFileSharePath)) + if (string.IsNullOrEmpty(_deploymentParameters.RemoteServerFileSharePath)) { throw new ArgumentException($"Invalid value for {nameof(RemoteWindowsDeploymentParameters.RemoteServerFileSharePath)}." + " . A file share is required to copy the application's published output."); } - if (string.IsNullOrWhiteSpace(_deploymentParameters.ApplicationBaseUriHint)) + if (string.IsNullOrEmpty(_deploymentParameters.ApplicationBaseUriHint)) { throw new ArgumentException($"Invalid value for {nameof(RemoteWindowsDeploymentParameters.ApplicationBaseUriHint)}."); } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs index 8a9f6d6a4e..ae6a7a08af 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Deployers/SelfHostDeployer.cs @@ -194,22 +194,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting } } - private string GetDotNetExeForArchitecture() - { - var executableName = DotnetCommandName; - // We expect x64 dotnet.exe to be on the path but we have to go searching for the x86 version. - if (DotNetCommands.IsRunningX86OnX64(DeploymentParameters.RuntimeArchitecture)) - { - executableName = DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture); - if (!File.Exists(executableName)) - { - throw new Exception($"Unable to find '{executableName}'.'"); - } - } - - return executableName; - } - public override void Dispose() { using (Logger.BeginScope("SelfHost.Dispose")) diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Http.config b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Http.config new file mode 100644 index 0000000000..4508dea843 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Http.config @@ -0,0 +1,1034 @@ + + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Microsoft.AspNetCore.Server.IntegrationTesting.csproj b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Microsoft.AspNetCore.Server.IntegrationTesting.csproj index 76b5ed9fb2..9e304fde5e 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/Microsoft.AspNetCore.Server.IntegrationTesting.csproj +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/Microsoft.AspNetCore.Server.IntegrationTesting.csproj @@ -13,6 +13,10 @@ false + + + + diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting/TestMatrix.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting/TestMatrix.cs index 76785d20c7..d577e25dc7 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting/TestMatrix.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting/TestMatrix.cs @@ -305,7 +305,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting if (hostingModel == HostingModel.InProcess) { // Not supported - if (Tfm.Matches(Tfm.Net461, tfm) || version == AncmVersion.AspNetCoreModule) + if (Tfm.Matches(Tfm.Net461, tfm) || Tfm.Matches(Tfm.NetCoreApp20, tfm) || version == AncmVersion.AspNetCoreModule) { continue; }