Browse Source

Merge aspnet/Hosting release/2.2

Nate McMaster 7 years ago
parent
commit
bfba741326
53 changed files with 2369 additions and 654 deletions
  1. 2 0
      build/CodeSign.props
  2. 2 0
      build/CodeSign.targets
  3. 0 2
      build/artifacts.props
  4. 1 0
      build/dependencies.props
  5. 1 1
      build/external-dependencies.props
  6. 1 0
      eng/dependencies.temp.props
  7. 8 6
      src/Hosting/Hosting/src/Internal/HostingLoggerExtensions.cs
  8. 9 8
      src/Hosting/Hosting/src/WebHostBuilder.cs
  9. 16 5
      src/Hosting/Hosting/src/WebHostExtensions.cs
  10. 125 0
      src/Hosting/Server.IntegrationTesting/src/ApplicationPublisher.cs
  11. 96 0
      src/Hosting/Server.IntegrationTesting/src/CachingApplicationPublisher.cs
  12. 12 0
      src/Hosting/Server.IntegrationTesting/src/Common/ANCMVersion.cs
  13. 7 0
      src/Hosting/Server.IntegrationTesting/src/Common/ApplicationType.cs
  14. 68 15
      src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs
  15. 71 0
      src/Hosting/Server.IntegrationTesting/src/Common/DotNetCommands.cs
  16. 4 0
      src/Hosting/Server.IntegrationTesting/src/Common/HostingModel.cs
  17. 13 0
      src/Hosting/Server.IntegrationTesting/src/Common/IWebHostExtensions.cs
  18. 3 2
      src/Hosting/Server.IntegrationTesting/src/Common/RuntimeFlavor.cs
  19. 2 1
      src/Hosting/Server.IntegrationTesting/src/Common/ServerType.cs
  20. 60 0
      src/Hosting/Server.IntegrationTesting/src/Common/TestPortHelper.cs
  21. 11 34
      src/Hosting/Server.IntegrationTesting/src/Common/TestUriHelper.cs
  22. 11 0
      src/Hosting/Server.IntegrationTesting/src/Common/TestUrlHelper.cs
  23. 20 0
      src/Hosting/Server.IntegrationTesting/src/Common/Tfm.cs
  24. 62 117
      src/Hosting/Server.IntegrationTesting/src/Deployers/ApplicationDeployer.cs
  25. 3 4
      src/Hosting/Server.IntegrationTesting/src/Deployers/ApplicationDeployerFactory.cs
  26. 0 20
      src/Hosting/Server.IntegrationTesting/src/Deployers/IApplicationDeployer.cs
  27. 0 317
      src/Hosting/Server.IntegrationTesting/src/Deployers/IISExpressDeployer.cs
  28. 71 6
      src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs
  29. 8 8
      src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs
  30. 43 29
      src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs
  31. 1034 0
      src/Hosting/Server.IntegrationTesting/src/Http.config
  32. 5 0
      src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj
  33. 36 0
      src/Hosting/Server.IntegrationTesting/src/ProcessHelpers.cs
  34. 31 0
      src/Hosting/Server.IntegrationTesting/src/PublishedApplication.cs
  35. 361 0
      src/Hosting/Server.IntegrationTesting/src/TestMatrix.cs
  36. 55 0
      src/Hosting/Server.IntegrationTesting/src/TestVariant.cs
  37. 55 0
      src/Hosting/Server.IntegrationTesting/src/xunit/IISExpressAncmSchema.cs
  38. 16 0
      src/Hosting/Server.IntegrationTesting/src/xunit/SkipIfIISExpressSchemaMissingInProcessAttribute.cs
  39. 6 17
      src/Hosting/Server.IntegrationTesting/src/xunit/SkipOn32BitOSAttribute.cs
  40. 12 26
      src/Hosting/TestHost/src/ResponseStream.cs
  41. 6 6
      src/Hosting/TestHost/test/ClientHandlerTests.cs
  42. 1 1
      src/Hosting/samples/GenericWebHost/GenericWebHost.csproj
  43. 1 1
      src/Hosting/samples/SampleStartups/SampleStartups.csproj
  44. 4 2
      src/Hosting/samples/SampleStartups/StartupExternallyControlled.cs
  45. 1 1
      src/Hosting/samples/SampleStartups/StartupFullControl.cs
  46. 1 1
      src/Hosting/test/FunctionalTests/ShutdownTests.cs
  47. 7 17
      src/Hosting/test/FunctionalTests/WebHostBuilderTests.cs
  48. 1 1
      src/Hosting/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj
  49. 1 1
      src/Hosting/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj
  50. 1 1
      src/Hosting/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj
  51. 1 1
      src/Hosting/test/testassets/IStartupInjectionAssemblyName/IStartupInjectionAssemblyName.csproj
  52. 1 1
      src/Hosting/test/testassets/Microsoft.AspNetCore.Hosting.TestSites/Microsoft.AspNetCore.Hosting.TestSites.csproj
  53. 2 2
      src/Hosting/test/testassets/TestStartupAssembly1/TestStartupAssembly1.csproj

+ 2 - 0
build/CodeSign.props

@@ -44,6 +44,8 @@
       <FilesToSign Include="Microsoft.Extensions.FileProviders.Embedded.dll"                Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
       <FilesToSign Include="Microsoft.Extensions.FileProviders.Physical.dll"                Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
       <FilesToSign Include="Microsoft.Extensions.FileSystemGlobbing.dll"                    Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
+      <FilesToSign Include="Microsoft.Extensions.Hosting.Abstractions.dll"                  Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
+      <FilesToSign Include="Microsoft.Extensions.Hosting.dll"                               Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
       <FilesToSign Include="Microsoft.Extensions.Http.dll"                                  Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
       <FilesToSign Include="Microsoft.Extensions.Logging.Abstractions.dll"                  Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />
       <FilesToSign Include="Microsoft.Extensions.Logging.Configuration.dll"                 Certificate="$(AssemblySigningCertName)" Container="Microsoft.AspNetCore.App" />

+ 2 - 0
build/CodeSign.targets

@@ -1,6 +1,8 @@
 <Project>
 
   <PropertyGroup>
+    <!-- _ProjectsOnly is for local builds and shouldn't be used on CI. -->
+    <DisableCodeSigning Condition=" '$(_ProjectsOnly)' == 'true' ">true</DisableCodeSigning>
     <CodeSignDependsOn>$(CodeSignDependsOn);CollectFileSignInfo</CodeSignDependsOn>
   </PropertyGroup>
 

+ 0 - 2
build/artifacts.props

@@ -20,7 +20,6 @@
     <PackageArtifact Include="dotnet-user-secrets" Category="ship" />
     <PackageArtifact Include="dotnet-watch" Category="ship" />
     <PackageArtifact Include="Internal.AspNetCore.Universe.Lineup" Category="noship" />
-    <PackageArtifact Include="Internal.WebHostBuilderFactory.Sources" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNet.Identity.AspNetCoreCompat" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.All" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Category="noship" />
@@ -134,7 +133,6 @@
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IIS" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IISIntegration" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting.IIS" Category="noship" />
-    <PackageArtifact Include="Microsoft.AspNetCore.Server.IntegrationTesting" Category="noship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.Kestrel.Core" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.Kestrel.Https" Category="ship" />
     <PackageArtifact Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Category="ship" />

+ 1 - 0
build/dependencies.props

@@ -97,6 +97,7 @@
     <!-- These dependencies are temporary while we refactor package refs into project refs. -->
     <MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.2.0</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
     <MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>2.2.0</MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>
+    <InternalWebHostBuilderFactorySourcesPackageVersion>2.2.0</InternalWebHostBuilderFactorySourcesPackageVersion>
     <MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.6.0-rtm-final</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
 
     <!-- 3rd party dependencies -->

+ 1 - 1
build/external-dependencies.props

@@ -79,7 +79,7 @@
     <!-- These dependencies are temporary while we refactor package refs into project refs. -->
     <ExternalDependency Include="Microsoft.Extensions.Buffers.Testing.Sources" Version="$(MicrosoftExtensionsBuffersTestingSourcesPackageVersion)" />
     <ExternalDependency Include="Microsoft.Extensions.Buffers.MemoryPool.Sources" Version="$(MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion)" />
-    <ExternalDependency Include="Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources" Version="$(MicrosoftAspNetCoreHostingWebHostBuilderFactorySourcesPackageVersion)" />
+    <ExternalDependency Include="Internal.WebHostBuilderFactory.Sources" Version="$(InternalWebHostBuilderFactorySourcesPackageVersion)" />
     <ExternalDependency Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
   </ItemGroup>
 

+ 1 - 0
eng/dependencies.temp.props

@@ -6,6 +6,7 @@ This is required to provide dependencies for samples and tests.
   <ItemGroup>
     <LatestPackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
     <LatestPackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
     <LatestPackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
   </ItemGroup>
 </Project>

+ 8 - 6
src/Hosting/Hosting/src/Internal/HostingLoggerExtensions.cs

@@ -94,7 +94,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
 
         private class HostingLogScope : IReadOnlyList<KeyValuePair<string, object>>
         {
-            private readonly HttpContext _httpContext;
+            private readonly string _path;
+            private readonly string _traceIdentifier;
             private readonly string _correlationId;
 
             private string _cachedToString;
@@ -113,11 +114,11 @@ namespace Microsoft.AspNetCore.Hosting.Internal
                 {
                     if (index == 0)
                     {
-                        return new KeyValuePair<string, object>("RequestId", _httpContext.TraceIdentifier);
+                        return new KeyValuePair<string, object>("RequestId", _traceIdentifier);
                     }
                     else if (index == 1)
                     {
-                        return new KeyValuePair<string, object>("RequestPath", _httpContext.Request.Path.ToString());
+                        return new KeyValuePair<string, object>("RequestPath", _path);
                     }
                     else if (index == 2)
                     {
@@ -130,7 +131,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
 
             public HostingLogScope(HttpContext httpContext, string correlationId)
             {
-                _httpContext = httpContext;
+                _traceIdentifier = httpContext.TraceIdentifier;
+                _path = httpContext.Request.Path.ToString();
                 _correlationId = correlationId;
             }
 
@@ -141,8 +143,8 @@ namespace Microsoft.AspNetCore.Hosting.Internal
                     _cachedToString = string.Format(
                         CultureInfo.InvariantCulture,
                         "RequestId:{0} RequestPath:{1}",
-                        _httpContext.TraceIdentifier,
-                        _httpContext.Request.Path);
+                        _traceIdentifier,
+                        _path);
                 }
 
                 return _cachedToString;

+ 9 - 8
src/Hosting/Hosting/src/WebHostBuilder.cs

@@ -174,13 +174,6 @@ namespace Microsoft.AspNetCore.Hosting
                 }
             }
 
-            var logger = hostingServiceProvider.GetRequiredService<ILogger<WebHost>>();
-            // Warn about duplicate HostingStartupAssemblies
-            foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1))
-            {
-                logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
-            }
-
             AddApplicationServices(applicationServices, hostingServiceProvider);
 
             var host = new WebHost(
@@ -193,6 +186,14 @@ namespace Microsoft.AspNetCore.Hosting
             {
                 host.Initialize();
 
+                var logger = host.Services.GetRequiredService<ILogger<WebHost>>();
+
+                // Warn about duplicate HostingStartupAssemblies
+                foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().GroupBy(a => a, StringComparer.OrdinalIgnoreCase).Where(g => g.Count() > 1))
+                {
+                    logger.LogWarning($"The assembly {assemblyName} was specified multiple times. Hosting startup assemblies should only be specified once.");
+                }
+
                 return host;
             }
             catch
@@ -208,7 +209,7 @@ namespace Microsoft.AspNetCore.Hosting
                 var provider = collection.BuildServiceProvider();
                 var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();
 
-                if (factory != null)
+                if (factory != null && !(factory is DefaultServiceProviderFactory))
                 {
                     using (provider)
                     {

+ 16 - 5
src/Hosting/Hosting/src/WebHostExtensions.cs

@@ -45,8 +45,14 @@ namespace Microsoft.AspNetCore.Hosting
             {
                 AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: string.Empty);
 
-                await host.WaitForTokenShutdownAsync(cts.Token);
-                done.Set();
+                try
+                {
+                    await host.WaitForTokenShutdownAsync(cts.Token);
+                }
+                finally
+                {
+                    done.Set();
+                }
             }
         }
 
@@ -80,8 +86,14 @@ namespace Microsoft.AspNetCore.Hosting
                 var shutdownMessage = host.Services.GetRequiredService<WebHostOptions>().SuppressStatusMessages ? string.Empty : "Application is shutting down...";
                 AttachCtrlcSigtermShutdown(cts, done, shutdownMessage: shutdownMessage);
 
-                await host.RunAsync(cts.Token, "Application started. Press Ctrl+C to shut down.");
-                done.Set();
+                try
+                {
+                    await host.RunAsync(cts.Token, "Application started. Press Ctrl+C to shut down.");
+                }
+                finally
+                {
+                    done.Set();
+                }
             }
         }
 
@@ -92,7 +104,6 @@ namespace Microsoft.AspNetCore.Hosting
                 await host.StartAsync(token);
 
                 var hostingEnvironment = host.Services.GetService<IHostingEnvironment>();
-                var applicationLifetime = host.Services.GetService<IApplicationLifetime>();
                 var options = host.Services.GetRequiredService<WebHostOptions>();
 
                 if (!options.SuppressStatusMessages)

+ 125 - 0
src/Hosting/Server.IntegrationTesting/src/ApplicationPublisher.cs

@@ -0,0 +1,125 @@
+// 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.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class ApplicationPublisher
+    {
+        public string ApplicationPath { get; }
+
+        public ApplicationPublisher(string applicationPath)
+        {
+            ApplicationPath = applicationPath;
+        }
+
+        public static readonly string DotnetCommandName = "dotnet";
+
+        public virtual Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger)
+        {
+            var publishDirectory = CreateTempDirectory();
+            using (logger.BeginScope("dotnet-publish"))
+            {
+                if (string.IsNullOrEmpty(deploymentParameters.TargetFramework))
+                {
+                    throw new Exception($"A target framework must be specified in the deployment parameters for applications that require publishing before deployment");
+                }
+
+                var parameters = $"publish "
+                                 + $" --output \"{publishDirectory.FullName}\""
+                                 + $" --framework {deploymentParameters.TargetFramework}"
+                                 + $" --configuration {deploymentParameters.Configuration}"
+                                 + " --no-restore -p:VerifyMatchingImplicitPackageVersion=false";
+                // Set VerifyMatchingImplicitPackageVersion to disable errors when Microsoft.NETCore.App's version is overridden externally
+                // This verification doesn't matter if we are skipping restore during tests.
+
+                if (deploymentParameters.ApplicationType == ApplicationType.Standalone)
+                {
+                    parameters += $" --runtime {GetRuntimeIdentifier(deploymentParameters)}";
+                }
+
+                parameters += $" {deploymentParameters.AdditionalPublishParameters}";
+
+                var startInfo = new ProcessStartInfo
+                {
+                    FileName = DotnetCommandName,
+                    Arguments = parameters,
+                    UseShellExecute = false,
+                    CreateNoWindow = true,
+                    RedirectStandardError = true,
+                    RedirectStandardOutput = true,
+                    WorkingDirectory = deploymentParameters.ApplicationPath,
+                };
+
+                ProcessHelpers.AddEnvironmentVariablesToProcess(startInfo, deploymentParameters.PublishEnvironmentVariables, logger);
+
+                var hostProcess = new Process() { StartInfo = startInfo };
+
+                logger.LogInformation($"Executing command {DotnetCommandName} {parameters}");
+
+                hostProcess.StartAndCaptureOutAndErrToLogger("dotnet-publish", logger);
+
+                // A timeout is passed to Process.WaitForExit() for two reasons:
+                //
+                // 1. When process output is read asynchronously, WaitForExit() without a timeout blocks until child processes
+                //    are killed, which can cause hangs due to MSBuild NodeReuse child processes started by dotnet.exe.
+                //    With a timeout, WaitForExit() returns when the parent process is killed and ignores child processes.
+                //    https://stackoverflow.com/a/37983587/102052
+                //
+                // 2. If "dotnet publish" does hang indefinitely for some reason, tests should fail fast with an error message.
+                const int timeoutMinutes = 5;
+                if (hostProcess.WaitForExit(milliseconds: timeoutMinutes * 60 * 1000))
+                {
+                    if (hostProcess.ExitCode != 0)
+                    {
+                        var message = $"{DotnetCommandName} publish exited with exit code : {hostProcess.ExitCode}";
+                        logger.LogError(message);
+                        throw new Exception(message);
+                    }
+                }
+                else
+                {
+                    var message = $"{DotnetCommandName} publish failed to exit after {timeoutMinutes} minutes";
+                    logger.LogError(message);
+                    throw new Exception(message);
+                }
+
+                logger.LogInformation($"{DotnetCommandName} publish finished with exit code : {hostProcess.ExitCode}");
+            }
+
+            return Task.FromResult(new PublishedApplication(publishDirectory.FullName, logger));
+        }
+
+        private static string GetRuntimeIdentifier(DeploymentParameters deploymentParameters)
+        {
+            var architecture = deploymentParameters.RuntimeArchitecture;
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                return "win7-" + architecture;
+            }
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+            {
+                return "linux-" + architecture;
+            }
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+            {
+                return "osx-" + architecture;
+            }
+            throw new InvalidOperationException("Unrecognized operation system platform");
+        }
+
+        protected static DirectoryInfo CreateTempDirectory()
+        {
+            var tempPath = Path.GetTempPath() + Guid.NewGuid().ToString("N");
+            var target = new DirectoryInfo(tempPath);
+            target.Create();
+            return target;
+        }
+    }
+}

+ 96 - 0
src/Hosting/Server.IntegrationTesting/src/CachingApplicationPublisher.cs

@@ -0,0 +1,96 @@
+// 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.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class CachingApplicationPublisher: ApplicationPublisher, IDisposable
+    {
+        private readonly Dictionary<DotnetPublishParameters, PublishedApplication> _publishCache = new Dictionary<DotnetPublishParameters, PublishedApplication>();
+
+        public CachingApplicationPublisher(string applicationPath) : base(applicationPath)
+        {
+        }
+
+        public override async Task<PublishedApplication> Publish(DeploymentParameters deploymentParameters, ILogger logger)
+        {
+            if (ApplicationPath != deploymentParameters.ApplicationPath)
+            {
+                throw new InvalidOperationException("ApplicationPath mismatch");
+            }
+
+            if (deploymentParameters.PublishEnvironmentVariables.Any())
+            {
+                throw new InvalidOperationException("DeploymentParameters.PublishEnvironmentVariables not supported");
+            }
+
+            if (!string.IsNullOrEmpty(deploymentParameters.PublishedApplicationRootPath))
+            {
+                throw new InvalidOperationException("DeploymentParameters.PublishedApplicationRootPath not supported");
+            }
+
+            var dotnetPublishParameters = new DotnetPublishParameters
+            {
+                TargetFramework = deploymentParameters.TargetFramework,
+                Configuration = deploymentParameters.Configuration,
+                ApplicationType = deploymentParameters.ApplicationType,
+                RuntimeArchitecture = deploymentParameters.RuntimeArchitecture
+            };
+
+            if (!_publishCache.TryGetValue(dotnetPublishParameters, out var publishedApplication))
+            {
+                publishedApplication = await base.Publish(deploymentParameters, logger);
+                _publishCache.Add(dotnetPublishParameters, publishedApplication);
+            }
+
+            return new PublishedApplication(CopyPublishedOutput(publishedApplication, logger), logger);
+        }
+
+        private string CopyPublishedOutput(PublishedApplication application, ILogger logger)
+        {
+            var target = CreateTempDirectory();
+
+            var source = new DirectoryInfo(application.Path);
+            CopyFiles(source, target, logger);
+            return target.FullName;
+        }
+
+        public static void CopyFiles(DirectoryInfo source, DirectoryInfo target, ILogger logger)
+        {
+            foreach (DirectoryInfo directoryInfo in source.GetDirectories())
+            {
+                CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name), logger);
+            }
+
+            logger.LogDebug($"Processing {target.FullName}");
+            foreach (FileInfo fileInfo in source.GetFiles())
+            {
+                logger.LogDebug($"  Copying {fileInfo.Name}");
+                var destFileName = Path.Combine(target.FullName, fileInfo.Name);
+                fileInfo.CopyTo(destFileName);
+            }
+        }
+
+        public void Dispose()
+        {
+            foreach (var publishedApp in _publishCache.Values)
+            {
+                publishedApp.Dispose();
+            }
+        }
+
+        private struct DotnetPublishParameters
+        {
+            public string TargetFramework { get; set; }
+            public string Configuration { get; set; }
+            public ApplicationType ApplicationType { get; set; }
+            public RuntimeArchitecture RuntimeArchitecture { get; set; }
+        }
+    }
+}

+ 12 - 0
src/Hosting/Server.IntegrationTesting/src/Common/ANCMVersion.cs

@@ -0,0 +1,12 @@
+// 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.
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public enum AncmVersion
+    {
+        None,
+        AspNetCoreModule,
+        AspNetCoreModuleV2
+    }
+}

+ 7 - 0
src/Hosting/Server.IntegrationTesting/src/Common/ApplicationType.cs

@@ -5,7 +5,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
 {
     public enum ApplicationType
     {
+        /// <summary>
+        /// Does not target a specific platform. Requires the matching runtime to be installed.
+        /// </summary>
         Portable,
+
+        /// <summary>
+        /// All dlls are published with the app for x-copy deploy. Net461 requires this because ASP.NET Core is not in the GAC.
+        /// </summary>
         Standalone
     }
 }

+ 68 - 15
src/Hosting/Server.IntegrationTesting/src/Common/DeploymentParameters.cs

@@ -13,6 +13,35 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
     /// </summary>
     public class DeploymentParameters
     {
+        public DeploymentParameters()
+        {
+            EnvironmentVariables["ASPNETCORE_DETAILEDERRORS"] = "true";
+
+            var configAttribute = Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>();
+            if (configAttribute != null && !string.IsNullOrEmpty(configAttribute.Configuration))
+            {
+                Configuration = configAttribute.Configuration;
+            }
+        }
+
+        public DeploymentParameters(TestVariant variant)
+        {
+            EnvironmentVariables["ASPNETCORE_DETAILEDERRORS"] = "true";
+
+            var configAttribute = Assembly.GetCallingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>();
+            if (configAttribute != null && !string.IsNullOrEmpty(configAttribute.Configuration))
+            {
+                Configuration = configAttribute.Configuration;
+            }
+
+            ServerType = variant.Server;
+            TargetFramework = variant.Tfm;
+            ApplicationType = variant.ApplicationType;
+            RuntimeArchitecture = variant.Architecture;
+            HostingModel = variant.HostingModel;
+            AncmVersion = variant.AncmVersion;
+        }
+
         /// <summary>
         /// Creates an instance of <see cref="DeploymentParameters"/>.
         /// </summary>
@@ -36,11 +65,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
                 throw new DirectoryNotFoundException(string.Format("Application path {0} does not exist.", applicationPath));
             }
 
-            if (runtimeArchitecture == RuntimeArchitecture.x86 && runtimeFlavor == RuntimeFlavor.CoreClr)
-            {
-                throw new NotSupportedException("32 bit deployment is not yet supported for CoreCLR. Don't remove the tests, just disable them for now.");
-            }
-
             ApplicationPath = applicationPath;
             ApplicationName = new DirectoryInfo(ApplicationPath).Name;
             ServerType = serverType;
@@ -54,11 +78,34 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
             }
         }
 
-        public ServerType ServerType { get; }
+        public DeploymentParameters(DeploymentParameters parameters)
+        {
+            foreach (var propertyInfo in typeof(DeploymentParameters).GetProperties())
+            {
+                if (propertyInfo.CanWrite)
+                {
+                    propertyInfo.SetValue(this, propertyInfo.GetValue(parameters));
+                }
+            }
+
+            foreach (var kvp in parameters.EnvironmentVariables)
+            {
+                EnvironmentVariables.Add(kvp);
+            }
+
+            foreach (var kvp in parameters.PublishEnvironmentVariables)
+            {
+                PublishEnvironmentVariables.Add(kvp);
+            }
+        }
+
+        public ApplicationPublisher ApplicationPublisher { get; set; }
+
+        public ServerType ServerType { get; set;  }
 
-        public RuntimeFlavor RuntimeFlavor { get; }
+        public RuntimeFlavor RuntimeFlavor { get; set;  }
 
-        public RuntimeArchitecture RuntimeArchitecture { get; } = RuntimeArchitecture.x64;
+        public RuntimeArchitecture RuntimeArchitecture { get; set; } = RuntimeArchitecture.x64;
 
         /// <summary>
         /// Suggested base url for the deployed application. The final deployed url could be
@@ -67,15 +114,20 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         /// </summary>
         public string ApplicationBaseUriHint { get; set; }
 
+        /// <summary>
+        /// Scheme used by the deployed application if <see cref="ApplicationBaseUriHint"/> is empty.
+        /// </summary>
+        public string Scheme { get; set; } = Uri.UriSchemeHttp;
+
         public string EnvironmentName { get; set; }
 
         public string ServerConfigTemplateContent { get; set; }
 
         public string ServerConfigLocation { get; set; }
 
-        public string SiteName { get; set; }
+        public string SiteName { get; set; } = "HttpTestSite";
 
-        public string ApplicationPath { get; }
+        public string ApplicationPath { get; set; }
 
         /// <summary>
         /// Gets or sets the name of the application. This is used to execute the application when deployed.
@@ -95,11 +147,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         /// </summary>
         public string AdditionalPublishParameters { get; set; }
 
-        /// <summary>
-        /// Publish restores by default, this property opts out by default.
-        /// </summary>
-        public bool RestoreOnPublish { get; set; }
-
         /// <summary>
         /// To publish the application before deployment.
         /// </summary>
@@ -115,6 +162,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
 
         public HostingModel HostingModel { get; set; }
 
+        /// <summary>
+        /// When using the IISExpressDeployer, determines whether to use the older or newer version
+        /// of ANCM.
+        /// </summary>
+        public AncmVersion AncmVersion { get; set; } = AncmVersion.AspNetCoreModule;
+
         /// <summary>
         /// Environment variables to be set before starting the host.
         /// Not applicable for IIS Scenarios.

+ 71 - 0
src/Hosting/Server.IntegrationTesting/src/Common/DotNetCommands.cs

@@ -0,0 +1,71 @@
+// 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.Runtime.InteropServices;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public static class DotNetCommands
+    {
+        private const string _dotnetFolderName = ".dotnet";
+
+        internal static string DotNetHome { get; } = GetDotNetHome();
+
+        // Compare to https://github.com/aspnet/BuildTools/blob/314c98e4533217a841ff9767bb38e144eb6c93e4/tools/KoreBuild.Console/Commands/CommandContext.cs#L76
+        public static string GetDotNetHome()
+        {
+            var dotnetHome = Environment.GetEnvironmentVariable("DOTNET_HOME");
+            var userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
+            var home = Environment.GetEnvironmentVariable("HOME");
+
+            var result = Path.Combine(Directory.GetCurrentDirectory(), _dotnetFolderName);
+            if (!string.IsNullOrEmpty(dotnetHome))
+            {
+                result = dotnetHome;
+            }
+            else if (!string.IsNullOrEmpty(userProfile))
+            {
+                result = Path.Combine(userProfile, _dotnetFolderName);
+            }
+            else if (!string.IsNullOrEmpty(home))
+            {
+                result = home;
+            }
+
+            return result;
+        }
+
+        public static string GetDotNetInstallDir(RuntimeArchitecture arch)
+        {
+            var dotnetDir = DotNetHome;
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                dotnetDir = Path.Combine(dotnetDir, arch.ToString());
+            }
+
+            return dotnetDir;
+        }
+
+        public static string GetDotNetExecutable(RuntimeArchitecture arch)
+        {
+            var dotnetDir = GetDotNetInstallDir(arch);
+
+            var dotnetFile = "dotnet";
+
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                dotnetFile += ".exe";
+            }
+
+            return Path.Combine(dotnetDir, dotnetFile);
+        }
+
+        public static bool IsRunningX86OnX64(RuntimeArchitecture arch)
+        {
+            return (RuntimeInformation.OSArchitecture == Architecture.X64 || RuntimeInformation.OSArchitecture == Architecture.Arm64)
+                && arch == RuntimeArchitecture.x86;
+        }
+    }
+}

+ 4 - 0
src/Hosting/Server.IntegrationTesting/src/Common/HostingModel.cs

@@ -3,8 +3,12 @@
 
 namespace Microsoft.AspNetCore.Server.IntegrationTesting
 {
+    /// <summary>
+    /// For ANCM
+    /// </summary>
     public enum HostingModel
     {
+        None,
         OutOfProcess,
         InProcess
     }

+ 13 - 0
src/Hosting/Server.IntegrationTesting/src/Common/IWebHostExtensions.cs

@@ -0,0 +1,13 @@
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using System.Linq;
+
+namespace Microsoft.AspNetCore.Hosting
+{
+    public static class IWebHostExtensions
+    {
+        public static string GetAddress(this IWebHost host)
+        {
+            return host.ServerFeatures.Get<IServerAddressesFeature>().Addresses.First();
+        }
+    }
+}

+ 3 - 2
src/Hosting/Server.IntegrationTesting/src/Common/RuntimeFlavor.cs

@@ -5,7 +5,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
 {
     public enum RuntimeFlavor
     {
-        Clr,
-        CoreClr
+        None,
+        CoreClr,
+        Clr
     }
 }

+ 2 - 1
src/Hosting/Server.IntegrationTesting/src/Common/ServerType.cs

@@ -5,9 +5,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
 {
     public enum ServerType
     {
+        None,
         IISExpress,
         IIS,
-        WebListener,
+        HttpSys,
         Kestrel,
         Nginx
     }

+ 60 - 0
src/Hosting/Server.IntegrationTesting/src/Common/TestPortHelper.cs

@@ -0,0 +1,60 @@
+// 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.Net;
+using System.Net.Sockets;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
+{
+    public static class TestPortHelper
+    {
+        // Copied from https://github.com/aspnet/KestrelHttpServer/blob/47f1db20e063c2da75d9d89653fad4eafe24446c/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/AddressRegistrationTests.cs#L508
+        //
+        // This method is an attempt to safely get a free port from the OS.  Most of the time,
+        // when binding to dynamic port "0" the OS increments the assigned port, so it's safe
+        // to re-use the assigned port in another process.  However, occasionally the OS will reuse
+        // a recently assigned port instead of incrementing, which causes flaky tests with AddressInUse
+        // exceptions.  This method should only be used when the application itself cannot use
+        // dynamic port "0" (e.g. IISExpress).  Most functional tests using raw Kestrel
+        // (with status messages enabled) should directly bind to dynamic port "0" and scrape 
+        // the assigned port from the status message, which should be 100% reliable since the port
+        // is bound once and never released.
+        public static int GetNextPort()
+        {
+            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+            {
+                socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+                return ((IPEndPoint)socket.LocalEndPoint).Port;
+            }
+        }
+
+        // IIS Express preregisteres 44300-44399 ports with SSL bindings.
+        // So some tests always have to use ports in this range, and we can't rely on OS-allocated ports without a whole lot of ceremony around
+        // creating self-signed certificates and registering SSL bindings with HTTP.sys
+        public static int GetNextSSLPort()
+        {
+            var next = 44300;
+            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+            {
+                while (true)
+                {
+                    try
+                    {
+                        var port = next++;
+                        socket.Bind(new IPEndPoint(IPAddress.Loopback, port));
+                        return port;
+                    }
+                    catch (SocketException)
+                    {
+                        // Retry unless exhausted
+                        if (next > 44399)
+                        {
+                            throw;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 11 - 34
src/Hosting/Server.IntegrationTesting/src/Common/TestUriHelper.cs

@@ -2,27 +2,24 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
-using System.Net;
-using System.Net.Sockets;
-
 namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
 {
     public static class TestUriHelper
     {
-        public static Uri BuildTestUri()
+        public static Uri BuildTestUri(ServerType serverType)
         {
-            return BuildTestUri(null);
+            return BuildTestUri(serverType, hint: null);
         }
 
-        public static Uri BuildTestUri(string hint)
+        public static Uri BuildTestUri(ServerType serverType, string hint)
         {
-            // If this method is called directly, there is no way to know the server type or whether status messages
-            // are enabled.  It's safest to assume the server is WebListener (which doesn't support binding to dynamic
-            // port "0") and status messages are not enabled (so the assigned port cannot be scraped from console output).
-            return BuildTestUri(hint, serverType: ServerType.WebListener, statusMessagesEnabled: false);
+            // Assume status messages are enabled for Kestrel and disabled for all other servers.
+            var statusMessagesEnabled = (serverType == ServerType.Kestrel);
+
+            return BuildTestUri(serverType, Uri.UriSchemeHttp, hint, statusMessagesEnabled);
         }
 
-        internal static Uri BuildTestUri(string hint, ServerType serverType, bool statusMessagesEnabled)
+        internal static Uri BuildTestUri(ServerType serverType, string scheme, string hint, bool statusMessagesEnabled)
         {
             if (string.IsNullOrEmpty(hint))
             {
@@ -33,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
                     // once and never released.  Binding to dynamic port "0" on "localhost" (both IPv4 and IPv6) is not
                     // supported, so the port is only bound on "127.0.0.1" (IPv4).  If a test explicitly requires IPv6,
                     // it should provide a hint URL with "localhost" (IPv4 and IPv6) or "[::1]" (IPv6-only).
-                    return new UriBuilder("http", "127.0.0.1", 0).Uri;
+                    return new UriBuilder(scheme, "127.0.0.1", 0).Uri;
                 }
                 else
                 {
@@ -41,7 +38,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
                     // from which to scrape the assigned port, so the less reliable GetNextPort() must be used.  The
                     // port is bound on "localhost" (both IPv4 and IPv6), since this is supported when using a specific
                     // (non-zero) port.
-                    return new UriBuilder("http", "localhost", GetNextPort()).Uri;
+                    return new UriBuilder(scheme, "localhost", TestPortHelper.GetNextPort()).Uri;
                 }
             }
             else
@@ -52,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
                     // Only a few tests use this codepath, so it's fine to use the less reliable GetNextPort() for simplicity.
                     // The tests using this codepath will be reviewed to see if they can be changed to directly bind to dynamic
                     // port "0" on "127.0.0.1" and scrape the assigned port from the status message (the default codepath).
-                    return new UriBuilder(uriHint) { Port = GetNextPort() }.Uri;
+                    return new UriBuilder(uriHint) { Port = TestPortHelper.GetNextPort() }.Uri;
                 }
                 else
                 {
@@ -61,25 +58,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
                 }
             }
         }
-
-        // Copied from https://github.com/aspnet/KestrelHttpServer/blob/47f1db20e063c2da75d9d89653fad4eafe24446c/test/Microsoft.AspNetCore.Server.Kestrel.FunctionalTests/AddressRegistrationTests.cs#L508
-        //
-        // This method is an attempt to safely get a free port from the OS.  Most of the time,
-        // when binding to dynamic port "0" the OS increments the assigned port, so it's safe
-        // to re-use the assigned port in another process.  However, occasionally the OS will reuse
-        // a recently assigned port instead of incrementing, which causes flaky tests with AddressInUse
-        // exceptions.  This method should only be used when the application itself cannot use
-        // dynamic port "0" (e.g. IISExpress).  Most functional tests using raw Kestrel
-        // (with status messages enabled) should directly bind to dynamic port "0" and scrape 
-        // the assigned port from the status message, which should be 100% reliable since the port
-        // is bound once and never released.
-        public static int GetNextPort()
-        {
-            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
-            {
-                socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
-                return ((IPEndPoint)socket.LocalEndPoint).Port;
-            }
-        }
     }
 }

+ 11 - 0
src/Hosting/Server.IntegrationTesting/src/Common/TestUrlHelper.cs

@@ -0,0 +1,11 @@
+namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
+{
+    // Public for use in other test projects
+    public static class TestUrlHelper
+    {
+        public static string GetTestUrl(ServerType serverType)
+        {
+            return TestUriHelper.BuildTestUri(serverType).ToString();
+        }
+    }
+}

+ 20 - 0
src/Hosting/Server.IntegrationTesting/src/Common/Tfm.cs

@@ -0,0 +1,20 @@
+// 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;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public static class Tfm
+    {
+        public const string Net461 = "net461";
+        public const string NetCoreApp20 = "netcoreapp2.0";
+        public const string NetCoreApp21 = "netcoreapp2.1";
+        public const string NetCoreApp22 = "netcoreapp2.2";
+
+        public static bool Matches(string tfm1, string tfm2)
+        {
+            return string.Equals(tfm1, tfm2, StringComparison.OrdinalIgnoreCase);
+        }
+    }
+}

+ 62 - 117
src/Hosting/Server.IntegrationTesting/src/Deployers/ApplicationDeployer.cs

@@ -16,88 +16,73 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
     /// <summary>
     /// Abstract base class of all deployers with implementation of some of the common helpers.
     /// </summary>
-    public abstract class ApplicationDeployer : IApplicationDeployer
+    public abstract class ApplicationDeployer : IDisposable
     {
         public static readonly string DotnetCommandName = "dotnet";
 
-        // This is the argument that separates the dotnet arguments for the args being passed to the
-        // app being run when running dotnet run
-        public static readonly string DotnetArgumentSeparator = "--";
-
         private readonly Stopwatch _stopwatch = new Stopwatch();
 
+        private PublishedApplication _publishedApplication;
+
         public ApplicationDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
         {
             DeploymentParameters = deploymentParameters;
             LoggerFactory = loggerFactory;
             Logger = LoggerFactory.CreateLogger(GetType().FullName);
-        }
-
-        protected DeploymentParameters DeploymentParameters { get; }
 
-        protected ILoggerFactory LoggerFactory { get; }
-        protected ILogger Logger { get; }
-
-        public abstract Task<DeploymentResult> DeployAsync();
+            ValidateParameters();
+        }
 
-        protected void DotnetPublish(string publishRoot = null)
+        private void ValidateParameters()
         {
-            using (Logger.BeginScope("dotnet-publish"))
+            if (DeploymentParameters.ServerType == ServerType.None)
             {
-                if (string.IsNullOrEmpty(DeploymentParameters.TargetFramework))
-                {
-                    throw new Exception($"A target framework must be specified in the deployment parameters for applications that require publishing before deployment");
-                }
-
-                DeploymentParameters.PublishedApplicationRootPath = publishRoot ?? Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
-
-                var parameters = $"publish "
-                    + $" --output \"{DeploymentParameters.PublishedApplicationRootPath}\""
-                    + $" --framework {DeploymentParameters.TargetFramework}"
-                    + $" --configuration {DeploymentParameters.Configuration}"
-                    + (DeploymentParameters.RestoreOnPublish 
-                        ? string.Empty
-                        : " --no-restore -p:VerifyMatchingImplicitPackageVersion=false");
-                        // Set VerifyMatchingImplicitPackageVersion to disable errors when Microsoft.NETCore.App's version is overridden externally
-                        // This verification doesn't matter if we are skipping restore during tests.
+                throw new ArgumentException($"Invalid ServerType '{DeploymentParameters.ServerType}'.");
+            }
 
-                if (DeploymentParameters.ApplicationType == ApplicationType.Standalone)
-                {
-                    parameters += $" --runtime {GetRuntimeIdentifier()}";
-                }
+            if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.None && !string.IsNullOrEmpty(DeploymentParameters.TargetFramework))
+            {
+                DeploymentParameters.RuntimeFlavor = GetRuntimeFlavor(DeploymentParameters.TargetFramework);
+            }
 
-                parameters += $" {DeploymentParameters.AdditionalPublishParameters}";
+            if (string.IsNullOrEmpty(DeploymentParameters.ApplicationPath))
+            {
+                throw new ArgumentException("ApplicationPath cannot be null.");
+            }
 
-                var startInfo = new ProcessStartInfo
-                {
-                    FileName = DotnetCommandName,
-                    Arguments = parameters,
-                    UseShellExecute = false,
-                    CreateNoWindow = true,
-                    RedirectStandardError = true,
-                    RedirectStandardOutput = true,
-                    WorkingDirectory = DeploymentParameters.ApplicationPath,
-                };
+            if (!Directory.Exists(DeploymentParameters.ApplicationPath))
+            {
+                throw new DirectoryNotFoundException(string.Format("Application path {0} does not exist.", DeploymentParameters.ApplicationPath));
+            }
 
-                AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.PublishEnvironmentVariables);
+            if (string.IsNullOrEmpty(DeploymentParameters.ApplicationName))
+            {
+                DeploymentParameters.ApplicationName = new DirectoryInfo(DeploymentParameters.ApplicationPath).Name;
+            }
+        }
 
-                var hostProcess = new Process() { StartInfo = startInfo };
+        private RuntimeFlavor GetRuntimeFlavor(string tfm)
+        {
+            if (Tfm.Matches(Tfm.Net461, tfm))
+            {
+                return RuntimeFlavor.Clr;
+            }
+            return RuntimeFlavor.CoreClr;
+        }
 
-                Logger.LogInformation($"Executing command {DotnetCommandName} {parameters}");
+        protected DeploymentParameters DeploymentParameters { get; }
 
-                hostProcess.StartAndCaptureOutAndErrToLogger("dotnet-publish", Logger);
+        protected ILoggerFactory LoggerFactory { get; }
 
-                hostProcess.WaitForExit();
+        protected ILogger Logger { get; }
 
-                if (hostProcess.ExitCode != 0)
-                {
-                    var message = $"{DotnetCommandName} publish exited with exit code : {hostProcess.ExitCode}";
-                    Logger.LogError(message);
-                    throw new Exception(message);
-                }
+        public abstract Task<DeploymentResult> DeployAsync();
 
-                Logger.LogInformation($"{DotnetCommandName} publish finished with exit code : {hostProcess.ExitCode}");
-            }
+        protected void DotnetPublish(string publishRoot = null)
+        {
+            var publisher = DeploymentParameters.ApplicationPublisher ?? new ApplicationPublisher(DeploymentParameters.ApplicationPath);
+            _publishedApplication = publisher.Publish(DeploymentParameters, Logger).GetAwaiter().GetResult();
+            DeploymentParameters.PublishedApplicationRootPath = _publishedApplication.Path;
         }
 
         protected void CleanPublishedOutput()
@@ -112,13 +97,25 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
                 }
                 else
                 {
-                    RetryHelper.RetryOperation(
-                        () => Directory.Delete(DeploymentParameters.PublishedApplicationRootPath, true),
-                        e => Logger.LogWarning($"Failed to delete directory : {e.Message}"),
-                        retryCount: 3,
-                        retryDelayMilliseconds: 100);
+                    _publishedApplication.Dispose();
+                }
+            }
+        }
+
+        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)
@@ -147,26 +144,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         protected void AddEnvironmentVariablesToProcess(ProcessStartInfo startInfo, IDictionary<string, string> environmentVariables)
         {
             var environment = startInfo.Environment;
-            SetEnvironmentVariable(environment, "ASPNETCORE_ENVIRONMENT", DeploymentParameters.EnvironmentName);
-
-            foreach (var environmentVariable in environmentVariables)
-            {
-                SetEnvironmentVariable(environment, environmentVariable.Key, environmentVariable.Value);
-            }
-        }
-
-        protected void SetEnvironmentVariable(IDictionary<string, string> environment, string name, string value)
-        {
-            if (value == null)
-            {
-                Logger.LogInformation("Removing environment variable {name}", name);
-                environment.Remove(name);
-            }
-            else
-            {
-                Logger.LogInformation("SET {name}={value}", name, value);
-                environment[name] = value;
-            }
+            ProcessHelpers.SetEnvironmentVariable(environment, "ASPNETCORE_ENVIRONMENT", DeploymentParameters.EnvironmentName, Logger);
+            ProcessHelpers.AddEnvironmentVariablesToProcess(startInfo, environmentVariables, Logger);
         }
 
         protected void InvokeUserApplicationCleanup()
@@ -214,39 +193,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         }
 
         public abstract void Dispose();
-
-        private string GetRuntimeIdentifier()
-        {
-            var architecture = GetArchitecture();
-            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
-            {
-                return "win7-" + architecture;
-            }
-            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
-            {
-                return "linux-" + architecture;
-            }
-            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-            {
-                return "osx-" + architecture;
-            }
-            else
-            {
-                throw new InvalidOperationException("Unrecognized operation system platform");
-            }
-        }
-
-        private string GetArchitecture()
-        {
-            switch (RuntimeInformation.OSArchitecture)
-            {
-                case Architecture.X86:
-                    return "x86";
-                case Architecture.X64:
-                    return "x64";
-                default:
-                    throw new NotSupportedException($"Unsupported architecture: {RuntimeInformation.OSArchitecture}");
-            }
-        }
     }
 }

+ 3 - 4
src/Hosting/Server.IntegrationTesting/src/Deployers/ApplicationDeployerFactory.cs

@@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         /// <param name="deploymentParameters"></param>
         /// <param name="loggerFactory"></param>
         /// <returns></returns>
-        public static IApplicationDeployer Create(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
+        public static ApplicationDeployer Create(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
         {
             if (deploymentParameters == null)
             {
@@ -32,10 +32,9 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
             switch (deploymentParameters.ServerType)
             {
                 case ServerType.IISExpress:
-                    return new IISExpressDeployer(deploymentParameters, loggerFactory);
                 case ServerType.IIS:
-                    throw new NotSupportedException("The IIS deployer is no longer supported");
-                case ServerType.WebListener:
+                    throw new NotSupportedException("Use Microsoft.AspNetCore.Server.IntegrationTesting.IIS package and IISApplicationDeployerFactory for IIS support.");
+                case ServerType.HttpSys:
                 case ServerType.Kestrel:
                     return new SelfHostDeployer(deploymentParameters, loggerFactory);
                 case ServerType.Nginx:

+ 0 - 20
src/Hosting/Server.IntegrationTesting/src/Deployers/IApplicationDeployer.cs

@@ -1,20 +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;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Server.IntegrationTesting
-{
-    /// <summary>
-    /// Common operations on an application deployer.
-    /// </summary>
-    public interface IApplicationDeployer : IDisposable
-    {
-        /// <summary>
-        /// Deploys the application to the target with specified <see cref="DeploymentParameters"/>.
-        /// </summary>
-        /// <returns></returns>
-        Task<DeploymentResult> DeployAsync();
-    }
-}

+ 0 - 317
src/Hosting/Server.IntegrationTesting/src/Deployers/IISExpressDeployer.cs

@@ -1,317 +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;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
-using Microsoft.AspNetCore.Testing;
-using Microsoft.Extensions.Logging;
-
-namespace Microsoft.AspNetCore.Server.IntegrationTesting
-{
-    /// <summary>
-    /// Deployment helper for IISExpress.
-    /// </summary>
-    public class IISExpressDeployer : ApplicationDeployer
-    {
-        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 static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?<url>[^""]+)"" for site.*$");
-
-        private Process _hostProcess;
-
-        public IISExpressDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
-            : base(deploymentParameters, loggerFactory)
-        {
-        }
-
-        public bool IsWin8OrLater
-        {
-            get
-            {
-                var win8Version = new Version(6, 2);
-
-                return (Environment.OSVersion.Version >= win8Version);
-            }
-        }
-
-        public bool Is64BitHost
-        {
-            get
-            {
-                return Environment.Is64BitOperatingSystem;
-            }
-        }
-
-        public override async Task<DeploymentResult> DeployAsync()
-        {
-            using (Logger.BeginScope("Deployment"))
-            {
-                // Start timer
-                StartTimer();
-
-                // For now we always auto-publish. Otherwise we'll have to write our own local web.config for the HttpPlatformHandler
-                DeploymentParameters.PublishApplicationBeforeDeployment = true;
-                if (DeploymentParameters.PublishApplicationBeforeDeployment)
-                {
-                    DotnetPublish();
-                }
-
-                var contentRoot = DeploymentParameters.PublishApplicationBeforeDeployment ? DeploymentParameters.PublishedApplicationRootPath : DeploymentParameters.ApplicationPath;
-
-                var testUri = TestUriHelper.BuildTestUri(DeploymentParameters.ApplicationBaseUriHint);
-
-                // Launch the host process.
-                var (actualUri, hostExitToken) = await StartIISExpressAsync(testUri, contentRoot);
-
-                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(
-                    LoggerFactory,
-                    DeploymentParameters,
-                    applicationBaseUri: actualUri.ToString(),
-                    contentRoot: contentRoot,
-                    hostShutdownToken: hostExitToken);
-            }
-        }
-
-        private async Task<(Uri url, CancellationToken hostExitToken)> StartIISExpressAsync(Uri uri, string contentRoot)
-        {
-            using (Logger.BeginScope("StartIISExpress"))
-            {
-                var port = uri.Port;
-                if (port == 0)
-                {
-                    port = TestUriHelper.GetNextPort();
-                }
-
-                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.
-
-                        if (serverConfig.Contains("[ANCMPath]"))
-                        {
-                            // We need to pick the bitness based the OS / IIS Express, not the application.
-                            // We'll eventually add support for choosing which IIS Express bitness to run: https://github.com/aspnet/Hosting/issues/880
-                            var ancmFile = Path.Combine(contentRoot, Is64BitHost ? @"x64\aspnetcore.dll" : @"x86\aspnetcore.dll");
-                            // Bin deployed by Microsoft.AspNetCore.AspNetCoreModule.nupkg
-
-                            if (!File.Exists(Environment.ExpandEnvironmentVariables(ancmFile)))
-                            {
-                                throw new FileNotFoundException("AspNetCoreModule could not be found.", ancmFile);
-                            }
-
-                            Logger.LogDebug("Writing ANCMPath '{ancmPath}' to config", ancmFile);
-                            serverConfig =
-                                serverConfig.Replace("[ANCMPath]", ancmFile);
-                        }
-
-                        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)
-                    {
-                        ModifyWebConfigToInProcess();
-                    }
-
-                    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
-                    {
-                        FileName = iisExpressPath,
-                        Arguments = parameters,
-                        UseShellExecute = false,
-                        CreateNoWindow = true,
-                        RedirectStandardError = true,
-                        RedirectStandardOutput = true
-                    };
-
-                    AddEnvironmentVariablesToProcess(startInfo, DeploymentParameters.EnvironmentVariables);
-
-                    Uri url = null;
-                    var started = new TaskCompletionSource<bool>();
-
-                    var process = new Process() { StartInfo = startInfo };
-                    process.OutputDataReceived += (sender, dataArgs) =>
-                    {
-                        if (string.Equals(dataArgs.Data, UnableToStartIISExpressMessage))
-                        {
-                            // We completely failed to start and we don't really know why
-                            started.TrySetException(new InvalidOperationException("Failed to start IIS Express"));
-                        }
-                        else if (string.Equals(dataArgs.Data, FailedToInitializeBindingsMessage))
-                        {
-                            started.TrySetResult(false);
-                        }
-                        else if (string.Equals(dataArgs.Data, IISExpressRunningMessage))
-                        {
-                            started.TrySetResult(true);
-                        }
-                        else if (!string.IsNullOrEmpty(dataArgs.Data))
-                        {
-                            var m = UrlDetectorRegex.Match(dataArgs.Data);
-                            if (m.Success)
-                            {
-                                url = new Uri(m.Groups["url"].Value);
-                            }
-                        }
-                    };
-
-                    process.EnableRaisingEvents = true;
-                    var hostExitTokenSource = new CancellationTokenSource();
-                    process.Exited += (sender, e) =>
-                    {
-                        Logger.LogInformation("iisexpress Process {pid} shut down", process.Id);
-
-                        // If TrySetResult was called above, this will just silently fail to set the new state, which is what we want
-                        started.TrySetException(new Exception($"Command exited unexpectedly with exit code: {process.ExitCode}"));
-
-                        TriggerHostShutdown(hostExitTokenSource);
-                    };
-                    process.StartAndCaptureOutAndErrToLogger("iisexpress", Logger);
-                    Logger.LogInformation("iisexpress Process {pid} started", process.Id);
-
-                    if (process.HasExited)
-                    {
-                        Logger.LogError("Host process {processName} {pid} exited with code {exitCode} or failed to start.", startInfo.FileName, process.Id, process.ExitCode);
-                        throw new Exception("Failed to start host");
-                    }
-
-                    // Wait for the app to start
-                    // The timeout here is large, because we don't know how long the test could need
-                    // We cover a lot of error cases above, but I want to make sure we eventually give up and don't hang the build
-                    // 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);
-
-                        // Wait for the process to exit and try again
-                        process.WaitForExit(30 * 1000);
-                        await Task.Delay(1000); // Wait a second to make sure the socket is completely cleaned up
-                    }
-                    else
-                    {
-                        _hostProcess = process;
-                        Logger.LogInformation("Started iisexpress successfully. Process Id : {processId}, Port: {port}", _hostProcess.Id, port);
-                        return (url: url, hostExitToken: hostExitTokenSource.Token);
-                    }
-                }
-
-                var message = $"Failed to initialize IIS Express after {MaximumAttempts} attempts to select a port";
-                Logger.LogError(message);
-                throw new TimeoutException(message);
-            }
-        }
-
-        private string GetIISExpressPath()
-        {
-            // Get path to program files
-            var iisExpressPath = Path.Combine(Environment.GetEnvironmentVariable("SystemDrive") + "\\", "Program Files", "IIS Express", "iisexpress.exe");
-
-            if (!File.Exists(iisExpressPath))
-            {
-                throw new Exception("Unable to find IISExpress on the machine: " + iisExpressPath);
-            }
-
-            return iisExpressPath;
-        }
-
-        public override void Dispose()
-        {
-            using (Logger.BeginScope("Dispose"))
-            {
-                ShutDownIfAnyHostProcess(_hostProcess);
-
-                if (!string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation)
-                    && File.Exists(DeploymentParameters.ServerConfigLocation))
-                {
-                    // Delete the temp applicationHostConfig that we created.
-                    Logger.LogDebug("Deleting applicationHost.config file from {configLocation}", DeploymentParameters.ServerConfigLocation);
-                    try
-                    {
-                        File.Delete(DeploymentParameters.ServerConfigLocation);
-                    }
-                    catch (Exception exception)
-                    {
-                        // Ignore delete failures - just write a log.
-                        Logger.LogWarning("Failed to delete '{config}'. Exception : {exception}", DeploymentParameters.ServerConfigLocation, exception.Message);
-                    }
-                }
-
-                if (DeploymentParameters.PublishApplicationBeforeDeployment)
-                {
-                    CleanPublishedOutput();
-                }
-
-                InvokeUserApplicationCleanup();
-
-                StopTimer();
-            }
-
-            // If by this point, the host process is still running (somehow), throw an error.
-            // A test failure is better than a silent hang and unknown failure later on
-            if (_hostProcess != null && !_hostProcess.HasExited)
-            {
-                throw new Exception($"iisexpress Process {_hostProcess.Id} failed to shutdown");
-            }
-        }
-
-        // Transforms the web.config file to include the hostingModel="inprocess" element
-        // and adds the server type = Microsoft.AspNetServer.IIS such that Kestrel isn't added again in ServerTests
-        private void ModifyWebConfigToInProcess()
-        {
-            var webConfigFile = $"{DeploymentParameters.PublishedApplicationRootPath}/web.config";
-            var config = XDocument.Load(webConfigFile);
-            var element = config.Descendants("aspNetCore").FirstOrDefault();
-            element.SetAttributeValue("hostingModel", "inprocess");
-            config.Save(webConfigFile);
-        }
-    }
-}

+ 71 - 6
src/Hosting/Server.IntegrationTesting/src/Deployers/NginxDeployer.cs

@@ -4,7 +4,10 @@
 using System;
 using System.Diagnostics;
 using System.IO;
+using System.Net;
 using System.Net.Http;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
 using Microsoft.Extensions.Logging;
@@ -18,6 +21,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
     {
         private string _configFile;
         private readonly int _waitTime = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;
+        private Socket _portSelector;
 
         public NginxDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory)
             : base(deploymentParameters, loggerFactory)
@@ -29,11 +33,37 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
             using (Logger.BeginScope("Deploy"))
             {
                 _configFile = Path.GetTempFileName();
+
                 var uri = string.IsNullOrEmpty(DeploymentParameters.ApplicationBaseUriHint) ?
-                    TestUriHelper.BuildTestUri() :
+                    new Uri("http://localhost:0") :
                     new Uri(DeploymentParameters.ApplicationBaseUriHint);
 
-                var redirectUri = TestUriHelper.BuildTestUri();
+                if (uri.Port == 0)
+                {
+                    var builder = new UriBuilder(uri);
+                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+                    {
+                        // This works with nginx 1.9.1 and later using the reuseport flag, available on Ubuntu 16.04.
+                        // Keep it open so nobody else claims the port
+                        _portSelector = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+                        _portSelector.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+                        builder.Port = ((IPEndPoint)_portSelector.LocalEndPoint).Port;
+                    }
+                    else
+                    {
+                        builder.Port = TestPortHelper.GetNextPort();
+                    }
+                    uri = builder.Uri;
+                }
+
+                var redirectUri = TestUriHelper.BuildTestUri(ServerType.Nginx);
+
+                if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr
+                        && DeploymentParameters.ApplicationType == ApplicationType.Standalone)
+                {
+                    // Publish is required to get the correct files in the output directory
+                    DeploymentParameters.PublishApplicationBeforeDeployment = true;
+                }
 
                 if (DeploymentParameters.PublishApplicationBeforeDeployment)
                 {
@@ -70,19 +100,51 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
             }
         }
 
+        private string GetUserName()
+        {
+            var retVal = Environment.GetEnvironmentVariable("LOGNAME")
+                ?? Environment.GetEnvironmentVariable("USER")
+                ?? Environment.GetEnvironmentVariable("USERNAME");
+
+            if (!string.IsNullOrEmpty(retVal))
+            {
+                return retVal;
+            }
+
+            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                using (var process = new Process
+                {
+                    StartInfo =
+                    {
+                        FileName = "whoami",
+                        RedirectStandardOutput = true,
+                    }
+                })
+                {
+                    process.Start();
+                    process.WaitForExit(10_000);
+                    return process.StandardOutput.ReadToEnd();
+                }
+            }
+
+            return null;
+        }
+
         private void SetupNginx(string redirectUri, Uri originalUri)
         {
             using (Logger.BeginScope("SetupNginx"))
             {
+                var userName = GetUserName() ?? throw new InvalidOperationException("Could not identify the current username");
                 // copy nginx.conf template and replace pertinent information
                 var pidFile = Path.Combine(DeploymentParameters.ApplicationPath, $"{Guid.NewGuid()}.nginx.pid");
                 var errorLog = Path.Combine(DeploymentParameters.ApplicationPath, "nginx.error.log");
                 var accessLog = Path.Combine(DeploymentParameters.ApplicationPath, "nginx.access.log");
                 DeploymentParameters.ServerConfigTemplateContent = DeploymentParameters.ServerConfigTemplateContent
-                    .Replace("[user]", Environment.GetEnvironmentVariable("LOGNAME"))
+                    .Replace("[user]", userName)
                     .Replace("[errorlog]", errorLog)
                     .Replace("[accesslog]", accessLog)
-                    .Replace("[listenPort]", originalUri.Port.ToString())
+                    .Replace("[listenPort]", originalUri.Port.ToString() + (_portSelector != null ? " reuseport" : ""))
                     .Replace("[redirectUri]", redirectUri)
                     .Replace("[pidFile]", pidFile);
                 Logger.LogDebug("Using PID file: {pidFile}", pidFile);
@@ -110,13 +172,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
                 {
                     runNginx.StartAndCaptureOutAndErrToLogger("nginx start", Logger);
                     runNginx.WaitForExit(_waitTime);
+
                     if (runNginx.ExitCode != 0)
                     {
-                        throw new Exception("Failed to start nginx");
+                        throw new InvalidOperationException("Failed to start nginx");
                     }
 
                     // Read the PID file
-                    if(!File.Exists(pidFile))
+                    if (!File.Exists(pidFile))
                     {
                         Logger.LogWarning("Unable to find nginx PID file: {pidFile}", pidFile);
                     }
@@ -158,6 +221,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
                     File.Delete(_configFile);
                 }
 
+                _portSelector?.Dispose();
+
                 base.Dispose();
             }
         }

+ 8 - 8
src/Hosting/Server.IntegrationTesting/src/Deployers/RemoteWindowsDeployer/RemoteWindowsDeployer.cs

@@ -33,43 +33,43 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
 
             if (_deploymentParameters.ServerType != ServerType.IIS
                 && _deploymentParameters.ServerType != ServerType.Kestrel
-                && _deploymentParameters.ServerType != ServerType.WebListener)
+                && _deploymentParameters.ServerType != ServerType.HttpSys)
             {
                 throw new InvalidOperationException($"Server type {_deploymentParameters.ServerType} is not supported for remote deployment." +
-                    $" Supported server types are {nameof(ServerType.Kestrel)}, {nameof(ServerType.IIS)} and {nameof(ServerType.WebListener)}");
+                    $" 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)}.");
             }

+ 43 - 29
src/Hosting/Server.IntegrationTesting/src/Deployers/SelfHostDeployer.cs

@@ -36,14 +36,29 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
                 // Start timer
                 StartTimer();
 
+                if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr
+                        && DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86)
+                {
+                    // Publish is required to rebuild for the right bitness
+                    DeploymentParameters.PublishApplicationBeforeDeployment = true;
+                }
+
+                if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr
+                        && DeploymentParameters.ApplicationType == ApplicationType.Standalone)
+                {
+                    // Publish is required to get the correct files in the output directory
+                    DeploymentParameters.PublishApplicationBeforeDeployment = true;
+                }
+
                 if (DeploymentParameters.PublishApplicationBeforeDeployment)
                 {
                     DotnetPublish();
                 }
 
                 var hintUrl = TestUriHelper.BuildTestUri(
-                    DeploymentParameters.ApplicationBaseUriHint,
                     DeploymentParameters.ServerType,
+                    DeploymentParameters.Scheme,
+                    DeploymentParameters.ApplicationBaseUriHint,
                     DeploymentParameters.StatusMessagesEnabled);
 
                 // Launch the host process.
@@ -64,43 +79,42 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
         {
             using (Logger.BeginScope("StartSelfHost"))
             {
-                string executableName;
-                string executableArgs = string.Empty;
-                string workingDirectory = string.Empty;
+                var executableName = string.Empty;
+                var executableArgs = string.Empty;
+                var workingDirectory = string.Empty;
+                var executableExtension = DeploymentParameters.ApplicationType == ApplicationType.Portable ? ".dll"
+                    : (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "");
+
                 if (DeploymentParameters.PublishApplicationBeforeDeployment)
                 {
                     workingDirectory = DeploymentParameters.PublishedApplicationRootPath;
-                    var executableExtension =
-                        DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? ".exe" :
-                        DeploymentParameters.ApplicationType == ApplicationType.Portable ? ".dll" : "";
-                    var executable = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, DeploymentParameters.ApplicationName + executableExtension);
-
-                    if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
-                    {
-                        executableName = "mono";
-                        executableArgs = executable;
-                    }
-                    else if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Portable)
-                    {
-                        executableName = "dotnet";
-                        executableArgs = executable;
-                    }
-                    else
-                    {
-                        executableName = executable;
-                    }
                 }
                 else
                 {
-                    workingDirectory = DeploymentParameters.ApplicationPath;
-                    var targetFramework = DeploymentParameters.TargetFramework ?? (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0");
+                    // Core+Standalone always publishes. This must be Clr+Standalone or Core+Portable.
+                    // Run from the pre-built bin/{config}/{tfm} directory.
+                    var targetFramework = DeploymentParameters.TargetFramework
+                        ?? (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? Tfm.Net461 : Tfm.NetCoreApp22);
+                    workingDirectory = Path.Combine(DeploymentParameters.ApplicationPath, "bin", DeploymentParameters.Configuration, targetFramework);
+                    // CurrentDirectory will point to bin/{config}/{tfm}, but the config and static files aren't copied, point to the app base instead.
+                    DeploymentParameters.EnvironmentVariables["ASPNETCORE_CONTENTROOT"] = DeploymentParameters.ApplicationPath;
+                }
 
-                    executableName = DotnetCommandName;
-                    executableArgs = $"run --no-build -c {DeploymentParameters.Configuration} --framework {targetFramework} {DotnetArgumentSeparator}";
+                var executable = Path.Combine(workingDirectory, DeploymentParameters.ApplicationName + executableExtension);
+
+                if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Portable)
+                {
+                    executableName = GetDotNetExeForArchitecture();
+                    executableArgs = executable;
+                }
+                else
+                {
+                    executableName = executable;
                 }
 
-                executableArgs += $" --server.urls {hintUrl} "
-                + $" --server {(DeploymentParameters.ServerType == ServerType.WebListener ? "Microsoft.AspNetCore.Server.HttpSys" : "Microsoft.AspNetCore.Server.Kestrel")}";
+                var server = DeploymentParameters.ServerType == ServerType.HttpSys
+                    ? "Microsoft.AspNetCore.Server.HttpSys" : "Microsoft.AspNetCore.Server.Kestrel";
+                executableArgs += $" --urls {hintUrl} --server {server}";
 
                 Logger.LogInformation($"Executing {executableName} {executableArgs}");
 

+ 1034 - 0
src/Hosting/Server.IntegrationTesting/src/Http.config

@@ -0,0 +1,1034 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    IIS configuration sections.
+
+    For schema documentation, see
+    %IIS_BIN%\config\schema\IIS_schema.xml.
+
+    Please make a backup of this file before making any changes to it.
+
+    NOTE: The following environment variables are available to be used
+          within this file and are understood by the IIS Express.
+
+          %IIS_USER_HOME% - The IIS Express home directory for the user
+          %IIS_SITES_HOME% - The default home directory for sites
+          %IIS_BIN% - The location of the IIS Express binaries
+          %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+
+<configuration>
+
+    <!--
+
+        The <configSections> section controls the registration of sections.
+        Section is the basic unit of deployment, locking, searching and
+        containment for configuration settings.
+
+        Every section belongs to one section group.
+        A section group is a container of logically-related sections.
+
+        Sections cannot be nested.
+        Section groups may be nested.
+
+        <section
+            name=""  [Required, Collection Key] [XML name of the section]
+            allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+            overrideModeDefault="Allow"  [Allow|Deny] [Default delegation mode]
+            allowLocation="true"  [true|false] [Allowed in location tags]
+        />
+
+        The recommended way to unlock sections is by using a location tag:
+        <location path="Default Web Site" overrideMode="Allow">
+            <system.webServer>
+                <asp />
+            </system.webServer>
+        </location>
+
+    -->
+    <configSections>
+        <sectionGroup name="system.applicationHost">
+            <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="preloadProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+        </sectionGroup>
+
+        <sectionGroup name="system.webServer">
+            <section name="asp" overrideModeDefault="Deny" />
+            <section name="caching" overrideModeDefault="Allow" />
+            <section name="cgi" overrideModeDefault="Deny" />
+            <section name="defaultDocument" overrideModeDefault="Allow" />
+            <section name="directoryBrowse" overrideModeDefault="Allow" />
+            <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="handlers" overrideModeDefault="Deny" />
+            <section name="httpCompression" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+            <section name="httpErrors" overrideModeDefault="Allow" />
+            <section name="httpLogging" overrideModeDefault="Deny" />
+            <section name="httpProtocol" overrideModeDefault="Allow" />
+            <section name="httpRedirect" overrideModeDefault="Allow" />
+            <section name="httpTracing" overrideModeDefault="Deny" />
+            <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+            <section name="odbcLogging" overrideModeDefault="Deny" />
+            <sectionGroup name="security">
+                <section name="access" overrideModeDefault="Deny" />
+                <section name="applicationDependencies" overrideModeDefault="Deny" />
+                <sectionGroup name="authentication">
+                    <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+                    <section name="basicAuthentication" overrideModeDefault="Deny" />
+                    <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="digestAuthentication" overrideModeDefault="Deny" />
+                    <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+                    <section name="windowsAuthentication" overrideModeDefault="Deny" />
+                </sectionGroup>
+                <section name="authorization" overrideModeDefault="Allow" />
+                <section name="ipSecurity" overrideModeDefault="Deny" />
+                <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+                <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+                <section name="requestFiltering" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="serverRuntime" overrideModeDefault="Deny" />
+            <section name="serverSideInclude" overrideModeDefault="Deny" />
+            <section name="staticContent" overrideModeDefault="Allow" />
+            <sectionGroup name="tracing">
+                <section name="traceFailedRequests" overrideModeDefault="Allow" />
+                <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <section name="urlCompression" overrideModeDefault="Allow" />
+            <section name="validation" overrideModeDefault="Allow" />
+            <sectionGroup name="webdav">
+                <section name="globalSettings" overrideModeDefault="Deny" />
+                <section name="authoring" overrideModeDefault="Deny" />
+                <section name="authoringRules" overrideModeDefault="Deny" />
+            </sectionGroup>
+            <sectionGroup name="rewrite">
+                <section name="allowedServerVariables" overrideModeDefault="Deny" />
+                <section name="rules" overrideModeDefault="Allow" />
+                <section name="outboundRules" overrideModeDefault="Allow" />
+                <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+                <section name="providers" overrideModeDefault="Allow" />
+                <section name="rewriteMaps" overrideModeDefault="Allow" />
+            </sectionGroup>
+            <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+            <section name="webSocket" overrideModeDefault="Deny" />
+            <section name="aspNetCore" overrideModeDefault="Allow" />
+        </sectionGroup>
+    </configSections>
+
+    <configProtectedData>
+        <providers>
+            <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+            <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+            <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+        </providers>
+    </configProtectedData>
+
+    <system.applicationHost>
+
+        <applicationPools>
+            <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+            <add name="IISExpressAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_BIN%\config\templates\PersonalWebServer\aspnet.config" autoStart="true" />
+            <applicationPoolDefaults managedRuntimeLoader="v4.0">
+                <processModel />
+            </applicationPoolDefaults>
+        </applicationPools>
+
+        <!--
+
+          The <listenerAdapters> section defines the protocols with which the
+          Windows Process Activation Service (WAS) binds.
+
+        -->
+        <listenerAdapters>
+            <add name="http" />
+        </listenerAdapters>
+
+        <sites>
+            <site name="HttpTestSite" id="1" serverAutoStart="true">
+                <application path="/">
+                    <virtualDirectory path="/" physicalPath="[ApplicationPhysicalPath]" />
+                </application>
+                <bindings>
+                    <binding protocol="http" bindingInformation=":[PORT]:localhost" />
+                </bindings>
+            </site>
+            <siteDefaults>
+                <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+                <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+            </siteDefaults>
+            <applicationDefaults applicationPool="IISExpressAppPool" />
+            <virtualDirectoryDefaults allowSubDirConfig="true" />
+        </sites>
+
+        <webLimits />
+
+    </system.applicationHost>
+
+    <system.webServer>
+
+        <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" hostingModel="[HostingModel]" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
+      
+        <serverRuntime />
+
+        <asp scriptErrorSentToBrowser="true">
+            <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+            <limits />
+        </asp>
+
+        <caching enabled="true" enableKernelCache="true">
+        </caching>
+
+        <cgi />
+
+        <defaultDocument enabled="true">
+            <files>
+                <add value="Default.htm" />
+                <add value="Default.asp" />
+                <add value="index.htm" />
+                <add value="index.html" />
+                <add value="iisstart.htm" />
+                <add value="default.aspx" />
+            </files>
+        </defaultDocument>
+
+        <directoryBrowse enabled="false" />
+
+        <fastCgi />
+
+        <!--
+
+          The <globalModules> section defines all native-code modules.
+          To enable a module, specify it in the <modules> section.
+
+        -->
+        <globalModules>
+            <add name="UriCacheModule" image="%IIS_BIN%\cachuri.dll" />
+<!--            <add name="FileCacheModule" image="%IIS_BIN%\cachfile.dll" />  -->
+            <add name="TokenCacheModule" image="%IIS_BIN%\cachtokn.dll" />
+<!--            <add name="HttpCacheModule" image="%IIS_BIN%\cachhttp.dll" /> -->
+            <add name="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+            <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+            <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+            <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+            <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+            <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+            <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+            <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+            <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+            <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+            <add name="UrlAuthorizationModule" image="%IIS_BIN%\urlauthz.dll" />
+            <add name="BasicAuthenticationModule" image="%IIS_BIN%\authbas.dll" />
+            <add name="WindowsAuthenticationModule" image="%IIS_BIN%\authsspi.dll" />
+<!--            <add name="DigestAuthenticationModule" image="%IIS_BIN%\authmd5.dll" /> -->
+            <add name="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+            <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+            <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+            <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+            <add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
+            <add name="CustomErrorModule" image="%IIS_BIN%\custerr.dll" />
+            <add name="HttpLoggingModule" image="%IIS_BIN%\loghttp.dll" />
+<!--            <add name="TracingModule" image="%IIS_BIN%\iisetw.dll" /> -->
+            <add name="FailedRequestsTracingModule" image="%IIS_BIN%\iisfreb.dll" />
+            <add name="RequestMonitorModule" image="%IIS_BIN%\iisreqs.dll" />
+            <add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
+            <add name="IsapiFilterModule" image="%IIS_BIN%\filter.dll" />
+            <add name="CgiModule" image="%IIS_BIN%\cgi.dll" />
+            <add name="FastCgiModule" image="%IIS_BIN%\iisfcgi.dll" />
+<!--            <add name="WebDAVModule" image="%IIS_BIN%\webdav.dll" /> -->
+            <add name="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+            <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+            <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+            <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+            <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+            <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+            <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+            <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+            <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+            <add name="AspNetCoreModule" image="[ANCMPath]" />
+            <add name="AspNetCoreModuleV2" image="[ANCMV2Path]" />
+        </globalModules>
+
+        <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+            <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+            <dynamicTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </dynamicTypes>
+            <staticTypes>
+                <add mimeType="text/*" enabled="true" />
+                <add mimeType="message/*" enabled="true" />
+                <add mimeType="application/x-javascript" enabled="true" />
+                <add mimeType="application/atom+xml" enabled="true" />
+                <add mimeType="application/xaml+xml" enabled="true" />
+                <add mimeType="*/*" enabled="false" />
+            </staticTypes>
+        </httpCompression>
+
+        <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+            <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+            <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+            <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+            <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+            <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+            <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+            <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+            <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+            <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+        </httpErrors>
+
+        <httpLogging dontLog="false" />
+
+        <httpProtocol>
+            <customHeaders>
+                <clear />
+                <add name="X-Powered-By" value="ASP.NET" />
+            </customHeaders>
+            <redirectHeaders>
+                <clear />
+            </redirectHeaders>
+        </httpProtocol>
+
+        <httpRedirect enabled="false" />
+
+        <httpTracing>
+        </httpTracing>
+
+        <isapiFilters>
+            <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+            <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+            <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+            <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+        </isapiFilters>
+
+        <odbcLogging />
+
+        <security>
+
+            <access sslFlags="None" />
+
+            <applicationDependencies>
+                <application name="Active Server Pages" groupId="ASP" />
+            </applicationDependencies>
+
+            <authentication>
+
+                <anonymousAuthentication enabled="true" userName="" />
+
+                <basicAuthentication enabled="false" />
+
+                <clientCertificateMappingAuthentication enabled="false" />
+
+                <digestAuthentication enabled="false" />
+
+                <iisClientCertificateMappingAuthentication enabled="false">
+                </iisClientCertificateMappingAuthentication>
+
+                <windowsAuthentication enabled="true">
+                    <providers>
+                        <add value="Negotiate" />
+                        <add value="NTLM" />
+                    </providers>
+                </windowsAuthentication>
+
+            </authentication>
+
+            <authorization>
+                <add accessType="Allow" users="*" />
+            </authorization>
+
+            <ipSecurity allowUnlisted="true" />
+
+            <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+                <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+                <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+                <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+            </isapiCgiRestriction>
+
+            <requestFiltering>
+                <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+                    <add fileExtension=".asa" allowed="false" />
+                    <add fileExtension=".asax" allowed="false" />
+                    <add fileExtension=".ascx" allowed="false" />
+                    <add fileExtension=".master" allowed="false" />
+                    <add fileExtension=".skin" allowed="false" />
+                    <add fileExtension=".browser" allowed="false" />
+                    <add fileExtension=".sitemap" allowed="false" />
+                    <add fileExtension=".config" allowed="false" />
+                    <add fileExtension=".cs" allowed="false" />
+                    <add fileExtension=".csproj" allowed="false" />
+                    <add fileExtension=".vb" allowed="false" />
+                    <add fileExtension=".vbproj" allowed="false" />
+                    <add fileExtension=".webinfo" allowed="false" />
+                    <add fileExtension=".licx" allowed="false" />
+                    <add fileExtension=".resx" allowed="false" />
+                    <add fileExtension=".resources" allowed="false" />
+                    <add fileExtension=".mdb" allowed="false" />
+                    <add fileExtension=".vjsproj" allowed="false" />
+                    <add fileExtension=".java" allowed="false" />
+                    <add fileExtension=".jsl" allowed="false" />
+                    <add fileExtension=".ldb" allowed="false" />
+                    <add fileExtension=".dsdgm" allowed="false" />
+                    <add fileExtension=".ssdgm" allowed="false" />
+                    <add fileExtension=".lsad" allowed="false" />
+                    <add fileExtension=".ssmap" allowed="false" />
+                    <add fileExtension=".cd" allowed="false" />
+                    <add fileExtension=".dsprototype" allowed="false" />
+                    <add fileExtension=".lsaprototype" allowed="false" />
+                    <add fileExtension=".sdm" allowed="false" />
+                    <add fileExtension=".sdmDocument" allowed="false" />
+                    <add fileExtension=".mdf" allowed="false" />
+                    <add fileExtension=".ldf" allowed="false" />
+                    <add fileExtension=".ad" allowed="false" />
+                    <add fileExtension=".dd" allowed="false" />
+                    <add fileExtension=".ldd" allowed="false" />
+                    <add fileExtension=".sd" allowed="false" />
+                    <add fileExtension=".adprototype" allowed="false" />
+                    <add fileExtension=".lddprototype" allowed="false" />
+                    <add fileExtension=".exclude" allowed="false" />
+                    <add fileExtension=".refresh" allowed="false" />
+                    <add fileExtension=".compiled" allowed="false" />
+                    <add fileExtension=".msgx" allowed="false" />
+                    <add fileExtension=".vsdisco" allowed="false" />
+                    <add fileExtension=".rules" allowed="false" />
+                </fileExtensions>
+                <verbs allowUnlisted="true" applyToWebDAV="true" />
+                <hiddenSegments applyToWebDAV="true">
+                    <add segment="web.config" />
+                    <add segment="bin" />
+                    <add segment="App_code" />
+                    <add segment="App_GlobalResources" />
+                    <add segment="App_LocalResources" />
+                    <add segment="App_WebReferences" />
+                    <add segment="App_Data" />
+                    <add segment="App_Browsers" />
+                </hiddenSegments>
+            </requestFiltering>
+
+        </security>
+
+        <serverSideInclude ssiExecDisable="false" />
+
+        <staticContent lockAttributes="isDocFooterFileName">
+            <mimeMap fileExtension=".323" mimeType="text/h323" />
+            <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+            <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+            <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+            <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+            <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+            <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+            <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+            <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+            <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+            <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+            <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+            <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".asm" mimeType="text/plain" />
+            <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+            <mimeMap fileExtension=".au" mimeType="audio/basic" />
+            <mimeMap fileExtension=".avi" mimeType="video/x-msvideo" />
+            <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+            <mimeMap fileExtension=".bas" mimeType="text/plain" />
+            <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+            <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+            <mimeMap fileExtension=".c" mimeType="text/plain" />
+            <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+            <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+            <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+            <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+            <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+            <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+            <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+            <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+            <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+            <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+            <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+            <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+            <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+            <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+            <mimeMap fileExtension=".css" mimeType="text/css" />
+            <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+            <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+            <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+            <mimeMap fileExtension=".disco" mimeType="text/xml" />
+            <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+            <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+            <mimeMap fileExtension=".doc" mimeType="application/msword" />
+            <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+            <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+            <mimeMap fileExtension=".dot" mimeType="application/msword" />
+            <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+            <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+            <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+            <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+            <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+            <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+            <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+            <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+            <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+            <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+            <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+            <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+            <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+            <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+            <mimeMap fileExtension=".gif" mimeType="image/gif" />
+            <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+            <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+            <mimeMap fileExtension=".h" mimeType="text/plain" />
+            <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+            <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+            <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+            <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+            <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+            <mimeMap fileExtension=".hta" mimeType="application/hta" />
+            <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+            <mimeMap fileExtension=".htm" mimeType="text/html" />
+            <mimeMap fileExtension=".html" mimeType="text/html" />
+            <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+            <mimeMap fileExtension=".hxt" mimeType="text/html" />
+            <mimeMap fileExtension=".ical" mimeType="text/calendar" />
+            <mimeMap fileExtension=".icalendar" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+            <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+            <mimeMap fileExtension=".ief" mimeType="image/ief" />
+            <mimeMap fileExtension=".ifb" mimeType="text/calendar" />
+            <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+            <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+            <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+            <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+            <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+            <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+            <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+            <mimeMap fileExtension=".js" mimeType="application/javascript" />
+            <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+            <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+            <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+            <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+            <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+            <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+            <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+            <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+            <mimeMap fileExtension=".map" mimeType="text/plain" />
+            <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+            <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+            <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+            <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+            <mimeMap fileExtension=".mno" mimeType="text/xml" />
+            <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+            <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+            <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+            <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+            <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+            <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+            <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+            <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+            <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+            <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+            <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+            <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+            <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".oda" mimeType="application/oda" />
+            <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+            <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+            <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+            <mimeMap fileExtension=".ogx" mimeType="application/ogg" />
+            <mimeMap fileExtension=".one" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+            <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+            <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+            <mimeMap fileExtension=".otf" mimeType="font/otf" />
+            <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+            <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+            <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+            <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+            <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+            <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+            <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+            <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+            <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+            <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+            <mimeMap fileExtension=".png" mimeType="image/png" />
+            <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+            <mimeMap fileExtension=".pnz" mimeType="image/png" />
+            <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+            <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+            <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+            <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+            <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+            <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+            <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+            <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+            <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+            <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+            <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+            <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+            <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+            <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+            <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+            <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+            <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+            <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+            <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+            <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+            <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+            <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+            <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+            <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+            <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+            <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+            <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+            <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+            <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+            <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+            <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+            <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+            <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+            <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+            <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+            <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+            <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+            <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+            <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+            <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+            <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+            <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+            <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+            <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+            <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+            <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+            <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+            <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+            <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+            <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+            <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+            <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+            <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+            <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+            <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+            <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+            <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+            <mimeMap fileExtension=".txt" mimeType="text/plain" />
+            <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+            <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+            <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+            <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+            <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+            <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+            <mimeMap fileExtension=".vml" mimeType="text/xml" />
+            <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+            <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+            <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+            <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+            <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+            <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".webm" mimeType="video/webm" />
+            <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+            <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+            <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+            <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+            <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+            <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+            <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+            <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+            <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+            <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+            <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+            <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+            <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+            <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+            <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+            <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+            <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+            <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+            <mimeMap fileExtension=".x" mimeType="application/directx" />
+            <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+            <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+            <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+            <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+            <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+            <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+            <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+            <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+            <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+            <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+            <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+            <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+            <mimeMap fileExtension=".xml" mimeType="text/xml" />
+            <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+            <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+            <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+            <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+            <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+            <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+            <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+            <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+            <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+        </staticContent>
+
+        <tracing>
+
+             <traceProviderDefinitions>
+                <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+                    <areas>
+                        <clear />
+                        <add name="Authentication" value="2" />
+                        <add name="Security" value="4" />
+                        <add name="Filter" value="8" />
+                        <add name="StaticFile" value="16" />
+                        <add name="CGI" value="32" />
+                        <add name="Compression" value="64" />
+                        <add name="Cache" value="128" />
+                        <add name="RequestNotifications" value="256" />
+                        <add name="Module" value="512" />
+                        <add name="Rewrite" value="1024" />
+                        <add name="FastCGI" value="4096" />
+                        <add name="WebSocket" value="16384" />
+                    </areas>
+                </add>
+                <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+                    <areas>
+                        <clear />
+                    </areas>
+                </add>
+                <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+                    <areas>
+                        <add name="Infrastructure" value="1" />
+                        <add name="Module" value="2" />
+                        <add name="Page" value="4" />
+                        <add name="AppServices" value="8" />
+                    </areas>
+                </add>
+            </traceProviderDefinitions>
+
+            <traceFailedRequests>
+                <add path="*">
+                    <traceAreas>
+                        <add provider="ASP" verbosity="Verbose" />
+                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+                        <add provider="ISAPI Extension" verbosity="Verbose" />
+                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+                    </traceAreas>
+                    <failureDefinitions statusCodes="200-999" />
+                </add>
+            </traceFailedRequests>
+
+        </tracing>
+
+        <urlCompression />
+
+        <validation />
+        <webdav>
+            <globalSettings>
+                <propertyStores>
+                    <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+                </propertyStores>
+                <lockStores>
+                    <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+                </lockStores>
+
+            </globalSettings>
+            <authoring>
+                <locks enabled="true" lockStore="webdav_simple_lock" />
+            </authoring>
+            <authoringRules />
+        </webdav>
+        <applicationInitialization />
+        <webSocket />
+
+    </system.webServer>
+    <location path="" overrideMode="Allow">
+        <system.webServer>
+            <modules>
+                <!--
+                <add name="HttpCacheModule" lockItem="true" />
+-->
+                <add name="DynamicCompressionModule" lockItem="true" />
+                <add name="StaticCompressionModule" lockItem="true" />
+                <add name="DefaultDocumentModule" lockItem="true" />
+                <add name="DirectoryListingModule" lockItem="true" />
+                <add name="IsapiFilterModule" lockItem="true" />
+                <add name="ProtocolSupportModule" lockItem="true" />
+                <add name="HttpRedirectionModule" lockItem="true" />
+                <add name="ServerSideIncludeModule" lockItem="true" />
+                <add name="StaticFileModule" lockItem="true" />
+                <add name="AnonymousAuthenticationModule" lockItem="true" />
+                <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="UrlAuthorizationModule" lockItem="true" />
+                <add name="BasicAuthenticationModule" lockItem="true" />
+                <add name="WindowsAuthenticationModule" lockItem="true" />
+                <!--
+                <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+                <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+                <add name="WebMatrixSupportModule" lockItem="true" />
+                <add name="IpRestrictionModule" lockItem="true" />
+                <add name="DynamicIpRestrictionModule" lockItem="true" />
+                <add name="RequestFilteringModule" lockItem="true" />
+                <add name="CustomLoggingModule" lockItem="true" />
+                <add name="CustomErrorModule" lockItem="true" />
+                <add name="IsapiModule" lockItem="true" />
+                <add name="HttpLoggingModule" lockItem="true" />
+                <add name="FailedRequestsTracingModule" lockItem="true" />
+                <add name="CgiModule" lockItem="true" />
+                <add name="FastCgiModule" lockItem="true" />
+                <!--                <add name="WebDAVModule" /> -->
+                <add name="RewriteModule" />
+                <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+                <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+                <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+                <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+                <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+                <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+                <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+                <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+                <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+                <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+                <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+                <add name="ApplicationInitializationModule" lockItem="true" />
+                <add name="WebSocketModule" lockItem="true" />
+                <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ConfigurationValidationModule" lockItem="true" />
+                <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+                <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+                <add name="AspNetCoreModule" />
+                <add name="AspNetCoreModuleV2"/>
+            </modules>
+            <handlers accessPolicy="Read, Script">
+                <add name="aspNetCore" path="*" verb="*" modules="[AspNetCoreModule]" resourceType="Unspecified" />
+                <!--                <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+                <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+                <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+                <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+                <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+                <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+                <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+                <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+                <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+                <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+                <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+                <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+                <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+                <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+                <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+                <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+                <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+            </handlers>
+        </system.webServer>
+    </location>
+</configuration>

+ 5 - 0
src/Hosting/Server.IntegrationTesting/src/Microsoft.AspNetCore.Server.IntegrationTesting.csproj

@@ -15,11 +15,16 @@
     <IsPackable>false</IsPackable>
   </PropertyGroup>
 
+  <ItemGroup>
+    <EmbeddedResource Include="Http.config" />
+  </ItemGroup>
+
   <ItemGroup>
     <EmbeddedResource Include="Deployers\RemoteWindowsDeployer\RemotePSSessionHelper.ps1;Deployers\RemoteWindowsDeployer\StartServer.ps1;Deployers\RemoteWindowsDeployer\StopServer.ps1" Exclude="bin\**;obj\**;**\*.xproj;packages\**;@(EmbeddedResource)" />
   </ItemGroup>
 
   <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore.Hosting.Abstractions" />
     <Reference Include="Microsoft.AspNetCore.Testing" />
     <Reference Include="Microsoft.Extensions.FileProviders.Embedded" />
     <Reference Include="Microsoft.Extensions.Logging" />

+ 36 - 0
src/Hosting/Server.IntegrationTesting/src/ProcessHelpers.cs

@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    internal class ProcessHelpers
+    {
+        public static void AddEnvironmentVariablesToProcess(ProcessStartInfo startInfo, IDictionary<string, string> environmentVariables, ILogger logger)
+        {
+            var environment = startInfo.Environment;
+
+            foreach (var environmentVariable in environmentVariables)
+            {
+                SetEnvironmentVariable(environment, environmentVariable.Key, environmentVariable.Value, logger);
+            }
+        }
+
+        public static void SetEnvironmentVariable(IDictionary<string, string> environment, string name, string value, ILogger logger)
+        {
+            if (value == null)
+            {
+                logger.LogInformation("Removing environment variable {name}", name);
+                environment.Remove(name);
+            }
+            else
+            {
+                logger.LogInformation("SET {name}={value}", name, value);
+                environment[name] = value;
+            }
+        }
+    }
+}

+ 31 - 0
src/Hosting/Server.IntegrationTesting/src/PublishedApplication.cs

@@ -0,0 +1,31 @@
+// 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 Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class PublishedApplication: IDisposable
+    {
+        private readonly ILogger _logger;
+
+        public string Path { get; }
+
+        public PublishedApplication(string path, ILogger logger)
+        {
+            _logger = logger;
+            Path = path;
+        }
+
+        public void Dispose()
+        {
+            RetryHelper.RetryOperation(
+                () => Directory.Delete(Path, true),
+                e => _logger.LogWarning($"Failed to delete directory : {e.Message}"),
+                retryCount: 3,
+                retryDelayMilliseconds: 100);
+        }
+    }
+}

+ 361 - 0
src/Hosting/Server.IntegrationTesting/src/TestMatrix.cs

@@ -0,0 +1,361 @@
+// 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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class TestMatrix : IEnumerable<object[]>
+    {
+        public IList<ServerType> Servers { get; set; } = new List<ServerType>();
+        public IList<string> Tfms { get; set; } = new List<string>();
+        public IList<ApplicationType> ApplicationTypes { get; set; } = new List<ApplicationType>();
+        public IList<RuntimeArchitecture> Architectures { get; set; } = new List<RuntimeArchitecture>();
+
+        // ANCM specific...
+        public IList<HostingModel> HostingModels { get; set; } = new List<HostingModel>();
+        public IList<AncmVersion> AncmVersions { get; set; } = new List<AncmVersion>();
+
+        private IList<Tuple<Func<TestVariant, bool>, string>> Skips { get; } = new List<Tuple<Func<TestVariant, bool>, string>>();
+
+        public static TestMatrix ForServers(params ServerType[] types)
+        {
+            return new TestMatrix()
+            {
+                Servers = types
+            };
+        }
+
+        public TestMatrix WithTfms(params string[] tfms)
+        {
+            Tfms = tfms;
+            return this;
+        }
+
+        public TestMatrix WithApplicationTypes(params ApplicationType[] types)
+        {
+            ApplicationTypes = types;
+            return this;
+        }
+
+        public TestMatrix WithAllApplicationTypes()
+        {
+            ApplicationTypes.Add(ApplicationType.Portable);
+            ApplicationTypes.Add(ApplicationType.Standalone);
+            return this;
+        }
+        public TestMatrix WithArchitectures(params RuntimeArchitecture[] archs)
+        {
+            Architectures = archs;
+            return this;
+        }
+
+        public TestMatrix WithAllArchitectures()
+        {
+            Architectures.Add(RuntimeArchitecture.x64);
+            Architectures.Add(RuntimeArchitecture.x86);
+            return this;
+        }
+
+        public TestMatrix WithHostingModels(params HostingModel[] models)
+        {
+            HostingModels = models;
+            return this;
+        }
+
+        public TestMatrix WithAllHostingModels()
+        {
+            HostingModels.Add(HostingModel.OutOfProcess);
+            HostingModels.Add(HostingModel.InProcess);
+            return this;
+        }
+
+        public TestMatrix WithAncmVersions(params AncmVersion[] versions)
+        {
+            AncmVersions = versions;
+            return this;
+        }
+
+        public TestMatrix WithAllAncmVersions()
+        {
+            AncmVersions.Add(AncmVersion.AspNetCoreModule);
+            AncmVersions.Add(AncmVersion.AspNetCoreModuleV2);
+            return this;
+        }
+
+        /// <summary>
+        /// V2 + InProc
+        /// </summary>
+        /// <returns></returns>
+        public TestMatrix WithAncmV2InProcess() => WithAncmVersions(AncmVersion.AspNetCoreModuleV2).WithHostingModels(HostingModel.InProcess);
+
+        public TestMatrix Skip(string message, Func<TestVariant, bool> check)
+        {
+            Skips.Add(new Tuple<Func<TestVariant, bool>, string>(check, message));
+            return this;
+        }
+
+        private IEnumerable<TestVariant> Build()
+        {
+            if (!Servers.Any())
+            {
+                throw new ArgumentException("No servers were specified.");
+            }
+
+            // TFMs.
+            if (!Tfms.Any())
+            {
+                throw new ArgumentException("No TFMs were specified.");
+            }
+
+            ResolveDefaultArchitecture();
+
+            if (!ApplicationTypes.Any())
+            {
+                ApplicationTypes.Add(ApplicationType.Portable);
+            }
+
+            if (!AncmVersions.Any())
+            {
+                AncmVersions.Add(AncmVersion.AspNetCoreModule);
+            }
+
+            if (!HostingModels.Any())
+            {
+                HostingModels.Add(HostingModel.OutOfProcess);
+            }
+
+            var variants = new List<TestVariant>();
+            VaryByServer(variants);
+
+            CheckForSkips(variants);
+
+            return variants;
+        }
+
+        private void ResolveDefaultArchitecture()
+        {
+            if (!Architectures.Any())
+            {
+                switch (RuntimeInformation.OSArchitecture)
+                {
+                    case Architecture.X86:
+                        Architectures.Add(RuntimeArchitecture.x86);
+                        break;
+                    case Architecture.X64:
+                        Architectures.Add(RuntimeArchitecture.x64);
+                        break;
+                    default:
+                        throw new ArgumentException(RuntimeInformation.OSArchitecture.ToString());
+                }
+            }
+        }
+
+        private void VaryByServer(List<TestVariant> variants)
+        {
+            foreach (var server in Servers)
+            {
+                var skip = SkipIfServerIsNotSupportedOnThisOS(server);
+
+                VaryByTfm(variants, server, skip);
+            }
+        }
+
+        private static string SkipIfServerIsNotSupportedOnThisOS(ServerType server)
+        {
+            var skip = false;
+            switch (server)
+            {
+                case ServerType.IIS:
+                case ServerType.IISExpress:
+                case ServerType.HttpSys:
+                    skip = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+                    break;
+                case ServerType.Kestrel:
+                    break;
+                case ServerType.Nginx:
+                    // Technically it's possible but we don't test it.
+                    skip = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+                    break;
+                default:
+                    throw new ArgumentException(server.ToString());
+            }
+
+            return skip ? "This server is not supported on this operating system." : null;
+        }
+
+        private void VaryByTfm(List<TestVariant> variants, ServerType server, string skip)
+        {
+            foreach (var tfm in Tfms)
+            {
+                if (!CheckTfmIsSupportedForServer(tfm, server))
+                {
+                    // Don't generate net461 variations for nginx server.
+                    continue;
+                }
+
+                var skipTfm = skip ?? SkipIfTfmIsNotSupportedOnThisOS(tfm);
+
+                VaryByApplicationType(variants, server, tfm, skipTfm);
+            }
+        }
+
+        private bool CheckTfmIsSupportedForServer(string tfm, ServerType server)
+        {
+            // Not a combination we test
+            return !(Tfm.Matches(Tfm.Net461, tfm) && ServerType.Nginx == server);
+        }
+
+        private static string SkipIfTfmIsNotSupportedOnThisOS(string tfm)
+        {
+            if (Tfm.Matches(Tfm.Net461, tfm) && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                return "This TFM is not supported on this operating system.";
+            }
+
+            return null;
+        }
+
+        private void VaryByApplicationType(List<TestVariant> variants, ServerType server, string tfm, string skip)
+        {
+            foreach (var t in ApplicationTypes)
+            {
+                var type = t;
+                if (Tfm.Matches(Tfm.Net461, tfm) && type == ApplicationType.Portable)
+                {
+                    if (ApplicationTypes.Count == 1)
+                    {
+                        // Override the default
+                        type = ApplicationType.Standalone;
+                    }
+                    else
+                    {
+                        continue;
+                    }
+                }
+
+                VaryByArchitecture(variants, server, tfm, skip, type);
+            }
+        }
+
+        private void VaryByArchitecture(List<TestVariant> variants, ServerType server, string tfm, string skip, ApplicationType type)
+        {
+            foreach (var arch in Architectures)
+            {
+                if (!IsArchitectureSupportedOnServer(arch, server))
+                {
+                    continue;
+                }
+                var archSkip = skip ?? SkipIfArchitectureNotSupportedOnCurrentSystem(arch);
+
+                if (server == ServerType.IISExpress || server == ServerType.IIS)
+                {
+                    VaryByAncmVersion(variants, server, tfm, type, arch, archSkip);
+                }
+                else
+                {
+                    variants.Add(new TestVariant()
+                    {
+                        Server = server,
+                        Tfm = tfm,
+                        ApplicationType = type,
+                        Architecture = arch,
+                        Skip = archSkip,
+                    });
+                }
+            }
+        }
+
+        private string SkipIfArchitectureNotSupportedOnCurrentSystem(RuntimeArchitecture arch)
+        {
+            if (arch == RuntimeArchitecture.x64)
+            {
+                // Can't run x64 on a x86 OS.
+                return (RuntimeInformation.OSArchitecture == Architecture.Arm || RuntimeInformation.OSArchitecture == Architecture.X86)
+                    ? $"Cannot run {arch} on your current system." : null;
+            }
+
+            // No x86 runtimes available on MacOS or Linux.
+            return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? null : $"No {arch} available for non-Windows systems.";
+        }
+
+        private bool IsArchitectureSupportedOnServer(RuntimeArchitecture arch, ServerType server)
+        {
+            // No x86 Mac/Linux runtime, don't generate a test variation that will always be skipped.
+            return !(arch == RuntimeArchitecture.x86 && ServerType.Nginx == server);
+        }
+
+        private void VaryByAncmVersion(IList<TestVariant> variants, ServerType server, string tfm, ApplicationType type, RuntimeArchitecture arch, string skip)
+        {
+            foreach (var version in AncmVersions)
+            {
+                VaryByAncmHostingModel(variants, server, tfm, type, arch, skip, version);
+            }
+        }
+
+        private void VaryByAncmHostingModel(IList<TestVariant> variants, ServerType server, string tfm, ApplicationType type, RuntimeArchitecture arch, string skip, AncmVersion version)
+        {
+            foreach (var hostingModel in HostingModels)
+            {
+                var skipAncm = skip;
+                if (hostingModel == HostingModel.InProcess)
+                {
+                    // Not supported
+                    if (Tfm.Matches(Tfm.Net461, tfm) || Tfm.Matches(Tfm.NetCoreApp20, tfm) || version == AncmVersion.AspNetCoreModule)
+                    {
+                        continue;
+                    }
+
+                    if (!IISExpressAncmSchema.SupportsInProcessHosting)
+                    {
+                        skipAncm = skipAncm ?? IISExpressAncmSchema.SkipReason;
+                    }
+                }
+
+                variants.Add(new TestVariant()
+                {
+                    Server = server,
+                    Tfm = tfm,
+                    ApplicationType = type,
+                    Architecture = arch,
+                    AncmVersion = version,
+                    HostingModel = hostingModel,
+                    Skip = skipAncm,
+                });
+            }
+        }
+
+        private void CheckForSkips(List<TestVariant> variants)
+        {
+            foreach (var variant in variants)
+            {
+                foreach (var skipPair in Skips)
+                {
+                    if (skipPair.Item1(variant))
+                    {
+                        variant.Skip = skipPair.Item2;
+                        break;
+                    }
+                }
+            }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return ((IEnumerable<object[]>)this).GetEnumerator();
+        }
+
+        // This is what Xunit MemberData expects
+        public IEnumerator<object[]> GetEnumerator()
+        {
+            foreach (var v in Build())
+            {
+                yield return new[] { v };
+            }
+        }
+    }
+}

+ 55 - 0
src/Hosting/Server.IntegrationTesting/src/TestVariant.cs

@@ -0,0 +1,55 @@
+// 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 Xunit.Abstractions;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class TestVariant : IXunitSerializable
+    {
+        public ServerType Server { get; set; }
+        public string Tfm { get; set; }
+        public ApplicationType ApplicationType { get; set; }
+        public RuntimeArchitecture Architecture { get; set; }
+
+        public string Skip { get; set; }
+
+        // ANCM specifics...
+        public HostingModel HostingModel { get; set; }
+        public AncmVersion AncmVersion { get; set; }
+
+        public override string ToString()
+        {
+            // For debug and test explorer view
+            var description = $"Server: {Server}, TFM: {Tfm}, Type: {ApplicationType}, Arch: {Architecture}";
+            if (Server == ServerType.IISExpress || Server == ServerType.IIS)
+            {
+                var version = AncmVersion == AncmVersion.AspNetCoreModule ? "V1" : "V2";
+                description += $", ANCM: {version}, Host: {HostingModel}";
+            }
+            return description;
+        }
+
+        public void Serialize(IXunitSerializationInfo info)
+        {
+            info.AddValue(nameof(Skip), Skip, typeof(string));
+            info.AddValue(nameof(Server), Server, typeof(ServerType));
+            info.AddValue(nameof(Tfm), Tfm, typeof(string));
+            info.AddValue(nameof(ApplicationType), ApplicationType, typeof(ApplicationType));
+            info.AddValue(nameof(Architecture), Architecture, typeof(RuntimeArchitecture));
+            info.AddValue(nameof(HostingModel), HostingModel, typeof(HostingModel));
+            info.AddValue(nameof(AncmVersion), AncmVersion, typeof(AncmVersion));
+        }
+
+        public void Deserialize(IXunitSerializationInfo info)
+        {
+            Skip = info.GetValue<string>(nameof(Skip));
+            Server = info.GetValue<ServerType>(nameof(Server));
+            Tfm = info.GetValue<string>(nameof(Tfm));
+            ApplicationType = info.GetValue<ApplicationType>(nameof(ApplicationType));
+            Architecture = info.GetValue<RuntimeArchitecture>(nameof(Architecture));
+            HostingModel = info.GetValue<HostingModel>(nameof(HostingModel));
+            AncmVersion = info.GetValue<AncmVersion>(nameof(AncmVersion));
+        }
+    }
+}

+ 55 - 0
src/Hosting/Server.IntegrationTesting/src/xunit/IISExpressAncmSchema.cs

@@ -0,0 +1,55 @@
+// 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.Runtime.InteropServices;
+using System.Xml.Linq;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    public class IISExpressAncmSchema
+    {
+        public static bool SupportsInProcessHosting { get; }
+        public static string SkipReason { get; }
+
+        static IISExpressAncmSchema()
+        {
+            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+            {
+                SkipReason = "IIS Express tests can only be run on Windows";
+                return;
+            }
+
+            var ancmConfigPath = Path.Combine(
+                Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
+                "IIS Express", "config", "schema", "aspnetcore_schema.xml");
+
+            if (!File.Exists(ancmConfigPath))
+            {
+                SkipReason = "IIS Express is not installed.";
+                return;
+            }
+
+            XDocument ancmConfig;
+
+            try
+            {
+                ancmConfig = XDocument.Load(ancmConfigPath);
+            }
+            catch
+            {
+                SkipReason = "Could not read ANCM schema configuration";
+                return;
+            }
+
+            SupportsInProcessHosting = ancmConfig
+                .Root
+                .Descendants("attribute")
+                .Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal));
+
+            SkipReason = SupportsInProcessHosting ? null : "IIS Express must be upgraded to support in-process hosting.";
+        }
+    }
+}

+ 16 - 0
src/Hosting/Server.IntegrationTesting/src/xunit/SkipIfIISExpressSchemaMissingInProcessAttribute.cs

@@ -0,0 +1,16 @@
+// 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 Microsoft.AspNetCore.Testing.xunit;
+
+namespace Microsoft.AspNetCore.Server.IntegrationTesting
+{
+    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Assembly | AttributeTargets.Class)]
+    public sealed partial class SkipIfIISExpressSchemaMissingInProcessAttribute : Attribute, ITestCondition
+    {
+        public bool IsMet => IISExpressAncmSchema.SupportsInProcessHosting;
+
+        public string SkipReason => IISExpressAncmSchema.SkipReason;
+    }
+}

+ 6 - 17
src/Hosting/Server.IntegrationTesting/src/xunit/SkipOn32BitOSAttribute.cs

@@ -2,32 +2,21 @@
 // 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.Runtime.InteropServices;
 using Microsoft.AspNetCore.Testing.xunit;
 
 namespace Microsoft.AspNetCore.Server.IntegrationTesting
 {
     /// <summary>
-    /// Skips a 64 bit test if the current Windows OS is 32-bit.
+    /// Skips a 64 bit test if the current OS is 32-bit.
     /// </summary>
     [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
     public class SkipOn32BitOSAttribute : Attribute, ITestCondition
     {
-        public bool IsMet
-        {
-            get
-            {
-                // Directory found only on 64-bit OS.
-                return Directory.Exists(Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "SysWOW64"));
-            }
-        }
+        public bool IsMet =>
+            RuntimeInformation.OSArchitecture == Architecture.Arm64
+            || RuntimeInformation.OSArchitecture == Architecture.X64;
 
-        public string SkipReason
-        {
-            get
-            {
-                return "Skipping the x64 test since Windows is 32-bit";
-            }
-        }
+        public string SkipReason => "Skipping the x64 test since Windows is 32-bit";
     }
 }

+ 12 - 26
src/Hosting/TestHost/src/ResponseStream.cs

@@ -109,34 +109,20 @@ namespace Microsoft.AspNetCore.TestHost
             var registration = cancellationToken.Register(Cancel);
             try
             {
-                // TODO: Usability issue. dotnet/corefx#27732 Flush or zero byte write causes ReadAsync to complete without data so I have to call ReadAsync in a loop.
-                while (true)
+                var result = await _pipe.Reader.ReadAsync(cancellationToken);
+
+                if (result.Buffer.IsEmpty && result.IsCompleted)
                 {
-                    var result = await _pipe.Reader.ReadAsync(cancellationToken);
-
-                    var readableBuffer = result.Buffer;
-                    if (!readableBuffer.IsEmpty)
-                    {
-                        var actual = Math.Min(readableBuffer.Length, count);
-                        readableBuffer = readableBuffer.Slice(0, actual);
-                        readableBuffer.CopyTo(new Span<byte>(buffer, offset, count));
-                        _pipe.Reader.AdvanceTo(readableBuffer.End, readableBuffer.End);
-                        return (int)actual;
-                    }
-
-                    if (result.IsCompleted)
-                    {
-                        _pipe.Reader.AdvanceTo(readableBuffer.End, readableBuffer.End); // TODO: Remove after https://github.com/dotnet/corefx/pull/27596
-                        _pipe.Reader.Complete();
-                        return 0;
-                    }
-
-                    cancellationToken.ThrowIfCancellationRequested();
-                    Debug.Assert(!result.IsCanceled); // It should only be canceled by cancellationToken.
-
-                    // Try again. TODO: dotnet/corefx#27732 I shouldn't need to do this, there wasn't any data.
-                    _pipe.Reader.AdvanceTo(readableBuffer.End, readableBuffer.End);
+                    _pipe.Reader.Complete();
+                    return 0;
                 }
+
+                var readableBuffer = result.Buffer;
+                var actual = Math.Min(readableBuffer.Length, count);
+                readableBuffer = readableBuffer.Slice(0, actual);
+                readableBuffer.CopyTo(new Span<byte>(buffer, offset, count));
+                _pipe.Reader.AdvanceTo(readableBuffer.End, readableBuffer.End);
+                return (int)actual;
             }
             finally
             {

+ 6 - 6
src/Hosting/TestHost/test/ClientHandlerTests.cs

@@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Hosting.Server;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Testing;
 using Microsoft.AspNetCore.Testing.xunit;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
@@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.TestHost
             var handler = new ClientHandler(new PathString("/A/Path/"), new DummyApplication(context =>
             {
                 // TODO: Assert.True(context.RequestAborted.CanBeCanceled);
-#if NETCOREAPP2_1
+#if NETCOREAPP2_2
                 Assert.Equal("HTTP/2.0", context.Request.Protocol);
 #elif NET461 || NETCOREAPP2_0
                 Assert.Equal("HTTP/1.1", context.Request.Protocol);
@@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.TestHost
             var handler = new ClientHandler(new PathString("/A/Path/"), new InspectingApplication(features =>
             {
                 // TODO: Assert.True(context.RequestAborted.CanBeCanceled);
-#if NETCOREAPP2_1
+#if NETCOREAPP2_2
                 Assert.Equal("HTTP/2.0", features.Get<IHttpRequestFeature>().Protocol);
 #elif NET461 || NETCOREAPP2_0
                 Assert.Equal("HTTP/1.1", features.Get<IHttpRequestFeature>().Protocol);
@@ -210,8 +211,8 @@ namespace Microsoft.AspNetCore.TestHost
             Task<int> readTask = responseStream.ReadAsync(new byte[100], 0, 100);
             Assert.False(readTask.IsCompleted);
             responseStream.Dispose();
-            Assert.True(readTask.Wait(TimeSpan.FromSeconds(10)), "Finished");
-            Assert.Equal(0, readTask.Result);
+            var result = await readTask.TimeoutAfter(TimeSpan.FromSeconds(10));
+            Assert.Equal(0, result);
             block.Set();
         }
 
@@ -235,8 +236,7 @@ namespace Microsoft.AspNetCore.TestHost
             Task<int> readTask = responseStream.ReadAsync(new byte[100], 0, 100, cts.Token);
             Assert.False(readTask.IsCompleted, "Not Completed");
             cts.Cancel();
-            var ex = Assert.Throws<AggregateException>(() => readTask.Wait(TimeSpan.FromSeconds(10)));
-            Assert.IsAssignableFrom<OperationCanceledException>(ex.GetBaseException());
+            await Assert.ThrowsAsync<OperationCanceledException>(() => readTask.TimeoutAfter(TimeSpan.FromSeconds(10)));
             block.Set();
         }
 

+ 1 - 1
src/Hosting/samples/GenericWebHost/GenericWebHost.csproj

@@ -2,7 +2,7 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
     <LangVersion>latest</LangVersion>
     <SignAssembly>true</SignAssembly>
   </PropertyGroup>

+ 1 - 1
src/Hosting/samples/SampleStartups/SampleStartups.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
     <StartupObject>SampleStartups.StartupInjection</StartupObject>
     <OutputType>exe</OutputType>
   </PropertyGroup>

+ 4 - 2
src/Hosting/samples/SampleStartups/StartupExternallyControlled.cs

@@ -38,8 +38,10 @@ namespace SampleStartups
 
         public async Task StopAsync()
         {
-            await _host.StopAsync(TimeSpan.FromSeconds(5));
-            _host.Dispose();
+            using (_host)
+            {
+                await _host.StopAsync(TimeSpan.FromSeconds(5));
+            }
         }
 
         public void AddUrl(string url)

+ 1 - 1
src/Hosting/samples/SampleStartups/StartupFullControl.cs

@@ -15,9 +15,9 @@ namespace SampleStartups
         public static void Main(string[] args)
         {
             var config = new ConfigurationBuilder()
-                .AddCommandLine(args)
                 .AddEnvironmentVariables(prefix: "ASPNETCORE_")
                 .AddJsonFile("hosting.json", optional: true)
+                .AddCommandLine(args)
                 .Build();
 
             var host = new WebHostBuilder()

+ 1 - 1
src/Hosting/test/FunctionalTests/ShutdownTests.cs

@@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Hosting.FunctionalTests
                     RuntimeArchitecture.x64)
                 {
                     EnvironmentName = "Shutdown",
-                    TargetFramework = "netcoreapp2.0",
+                    TargetFramework = Tfm.NetCoreApp22,
                     ApplicationType = ApplicationType.Portable,
                     PublishApplicationBeforeDeployment = true,
                     StatusMessagesEnabled = false

+ 7 - 17
src/Hosting/test/FunctionalTests/WebHostBuilderTests.cs

@@ -17,17 +17,12 @@ namespace Microsoft.AspNetCore.Hosting.FunctionalTests
     {
         public WebHostBuilderTests(ITestOutputHelper output) : base(output) { }
 
-        [Fact]
-        public async Task InjectedStartup_DefaultApplicationNameIsEntryAssembly_CoreClr()
-            => await InjectedStartup_DefaultApplicationNameIsEntryAssembly(RuntimeFlavor.CoreClr);
+        public static TestMatrix TestVariants => TestMatrix.ForServers(ServerType.Kestrel)
+                .WithTfms(Tfm.Net461, Tfm.NetCoreApp22);
 
-        [ConditionalFact]
-        [OSSkipCondition(OperatingSystems.MacOSX)]
-        [OSSkipCondition(OperatingSystems.Linux)]
-        public async Task InjectedStartup_DefaultApplicationNameIsEntryAssembly_Clr()
-            => await InjectedStartup_DefaultApplicationNameIsEntryAssembly(RuntimeFlavor.Clr);
-
-        private async Task InjectedStartup_DefaultApplicationNameIsEntryAssembly(RuntimeFlavor runtimeFlavor)
+        [ConditionalTheory]
+        [MemberData(nameof(TestVariants))]
+        public async Task InjectedStartup_DefaultApplicationNameIsEntryAssembly(TestVariant variant)
         {
             using (StartLog(out var loggerFactory))
             {
@@ -35,14 +30,9 @@ namespace Microsoft.AspNetCore.Hosting.FunctionalTests
 
                 var applicationPath = Path.Combine(TestPathUtilities.GetSolutionRootDirectory("Hosting"), "test", "TestAssets", "IStartupInjectionAssemblyName");
 
-                var deploymentParameters = new DeploymentParameters(
-                    applicationPath,
-                    ServerType.Kestrel,
-                    runtimeFlavor,
-                    RuntimeArchitecture.x64)
+                var deploymentParameters = new DeploymentParameters(variant)
                 {
-                    TargetFramework = runtimeFlavor == RuntimeFlavor.Clr ? "net461" : "netcoreapp2.0",
-                    ApplicationType = ApplicationType.Portable,
+                    ApplicationPath = applicationPath,
                     StatusMessagesEnabled = false
                 };
 

+ 1 - 1
src/Hosting/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;netcoreapp2.0;net461</TargetFrameworks>
     <OutputType>Exe</OutputType>
   </PropertyGroup>
 

+ 1 - 1
src/Hosting/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;netcoreapp2.0;net461</TargetFrameworks>
     <OutputType>Exe</OutputType>
   </PropertyGroup>
 

+ 1 - 1
src/Hosting/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;netcoreapp2.0;net461</TargetFrameworks>
     <OutputType>Exe</OutputType>
   </PropertyGroup>
 

+ 1 - 1
src/Hosting/test/testassets/IStartupInjectionAssemblyName/IStartupInjectionAssemblyName.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;netcoreapp2.0;net461</TargetFrameworks>
     <OutputType>Exe</OutputType>
   </PropertyGroup>
 

+ 1 - 1
src/Hosting/test/testassets/Microsoft.AspNetCore.Hosting.TestSites/Microsoft.AspNetCore.Hosting.TestSites.csproj

@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;netcoreapp2.0;net461</TargetFrameworks>
     <OutputType>Exe</OutputType>
   </PropertyGroup>
 

+ 2 - 2
src/Hosting/test/testassets/TestStartupAssembly1/TestStartupAssembly1.csproj

@@ -1,7 +1,7 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
+    <TargetFrameworks>netcoreapp2.2;net461</TargetFrameworks>
   </PropertyGroup>
 
   <ItemGroup>