diff --git a/.vsts-pipelines/templates/build-steps.yml b/.vsts-pipelines/templates/build-steps.yml index 949093b338..2ebd7b36d1 100644 --- a/.vsts-pipelines/templates/build-steps.yml +++ b/.vsts-pipelines/templates/build-steps.yml @@ -5,6 +5,14 @@ phases: beforeBuild: - powershell: "& ./tools/UpdateIISExpressCertificate.ps1; & ./tools/update_schema.ps1; Restart-Service w3svc" displayName: Prepare repo + afterBuild: + - task: PublishBuildArtifacts@1 + displayName: Upload binlog + condition: always() + inputs: + artifactName: logs + artifactType: Container + pathtoPublish: artifacts/logs/ - template: .vsts-pipelines/templates/phases/default-build.yml@buildtools parameters: diff --git a/build/repo.targets b/build/repo.targets index 5a2620ec75..4415123011 100644 --- a/build/repo.targets +++ b/build/repo.targets @@ -92,7 +92,7 @@ - + diff --git a/nuget/Microsoft.AspNetCore.AspNetCoreModule.nuspec b/nuget/Microsoft.AspNetCore.AspNetCoreModule.nuspec index 80d9490328..f05fcbbdd8 100644 --- a/nuget/Microsoft.AspNetCore.AspNetCoreModule.nuspec +++ b/nuget/Microsoft.AspNetCore.AspNetCoreModule.nuspec @@ -25,7 +25,7 @@ - + diff --git a/samples/NativeIISSample/NativeIISSample.csproj b/samples/NativeIISSample/NativeIISSample.csproj index d3c6d51b75..c1f4b88c89 100644 --- a/samples/NativeIISSample/NativeIISSample.csproj +++ b/samples/NativeIISSample/NativeIISSample.csproj @@ -4,6 +4,7 @@ netcoreapp2.2 + true diff --git a/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj b/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj index e1c11dddb6..169c79e503 100644 --- a/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj +++ b/src/AspNetCoreModuleV1/AspNetCore/AspNetCore.vcxproj @@ -213,14 +213,6 @@ - - - PreserveNewest - - - - - diff --git a/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml b/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml deleted file mode 100644 index c1590816b7..0000000000 --- a/src/AspNetCoreModuleV1/AspNetCore/aspnetcore_schema.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp index 9de2901be5..be4d124437 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp @@ -44,24 +44,40 @@ APPLICATION_MANAGER::GetOrCreateApplicationInfo( // key in the applicationInfoHash. pszApplicationId = pApplication.GetApplicationId(); - // When accessing the m_pApplicationInfoHash, we need to acquire the application manager - // lock to avoid races on setting state. - SRWSharedLock lock(m_srwLock); - if (!m_fDebugInitialize) { - DebugInitializeFromConfig(m_pHttpServer, pApplication); - m_fDebugInitialize = TRUE; - } + // When accessing the m_pApplicationInfoHash, we need to acquire the application manager + // lock to avoid races on setting state. + SRWSharedLock readLock(m_srwLock); + if (!m_fDebugInitialize) + { + DebugInitializeFromConfig(m_pHttpServer, pApplication); + m_fDebugInitialize = TRUE; + } - if (g_fInShutdown) - { - FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS)); - } + if (g_fInShutdown) + { + FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS)); + } - m_pApplicationInfoHash->FindKey(pszApplicationId, ppApplicationInfo); + m_pApplicationInfoHash->FindKey(pszApplicationId, ppApplicationInfo); + + // It's important to release read lock here so exclusive lock + // can be reacquired later as SRW lock doesn't allow upgrades + } if (*ppApplicationInfo == NULL) { + // Take exclusive lock before creating the application + SRWExclusiveLock writeLock(m_srwLock); + + // Check if other thread created the application + + m_pApplicationInfoHash->FindKey(pszApplicationId, ppApplicationInfo); + if (*ppApplicationInfo != NULL) + { + FINISHED(S_OK); + } + pApplicationInfo = new APPLICATION_INFO(m_pHttpServer); FINISHED_IF_FAILED(pApplicationInfo->Initialize(pApplication)); @@ -187,7 +203,7 @@ APPLICATION_MANAGER::RecycleApplicationFromManager( DWORD dwPreviousCounter = 0; APPLICATION_INFO_HASH* table = NULL; CONFIG_CHANGE_CONTEXT context; - + if (g_fInShutdown) { // We are already shutting down, ignore this event as a global configuration change event diff --git a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp index b2c6b69871..7cb185b0c3 100644 --- a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp @@ -6,7 +6,7 @@ #include "GlobalVersionUtility.h" -namespace fs = std::experimental::filesystem; +namespace fs = std::filesystem; // throws runtime error if no request handler versions are installed. // Throw invalid_argument if any argument is null diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp index 1468c7ee37..2e552679e0 100644 --- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp @@ -38,7 +38,7 @@ PollingAppOfflineApplication::AppOfflineExists() } -std::experimental::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(IHttpApplication& pApplication) +std::filesystem::path PollingAppOfflineApplication::GetAppOfflineLocation(IHttpApplication& pApplication) { - return std::experimental::filesystem::path(pApplication.GetApplicationPhysicalPath()) / "app_offline.htm"; + return std::filesystem::path(pApplication.GetApplicationPhysicalPath()) / "app_offline.htm"; } diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h index 48e71f6641..516e72b79f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h +++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h @@ -30,8 +30,8 @@ public: void Stop(bool fServerInitiated) override { UNREFERENCED_PARAMETER(fServerInitiated); } protected: - std::experimental::filesystem::path m_appOfflineLocation; - static std::experimental::filesystem::path GetAppOfflineLocation(IHttpApplication& pApplication); + std::filesystem::path m_appOfflineLocation; + static std::filesystem::path GetAppOfflineLocation(IHttpApplication& pApplication); private: static const int c_appOfflineRefreshIntervalMS = 200; diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp index ab827460bf..57644819be 100644 --- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp @@ -13,7 +13,7 @@ #include "HandleWrapper.h" #include "Environment.h" -namespace fs = std::experimental::filesystem; +namespace fs = std::filesystem; // // Runs a standalone appliction. @@ -98,7 +98,7 @@ HOSTFXR_UTILITY::GetStandaloneHostfxrParameters( } BOOL -HOSTFXR_UTILITY::IsDotnetExecutable(const std::experimental::filesystem::path & dotnetPath) +HOSTFXR_UTILITY::IsDotnetExecutable(const std::filesystem::path & dotnetPath) { auto name = dotnetPath.filename(); name.replace_extension(""); diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h index 1315865803..9e56fb4e28 100644 --- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h @@ -44,7 +44,7 @@ public: static BOOL IsDotnetExecutable( - _In_ const std::experimental::filesystem::path & dotnetPath + _In_ const std::filesystem::path & dotnetPath ); static @@ -74,25 +74,25 @@ public: ); static - std::optional + std::optional GetAbsolutePathToHostFxr( - _In_ const std::experimental::filesystem::path & dotnetPath, + _In_ const std::filesystem::path & dotnetPath, _In_ HANDLE hEventLog ); static - std::optional + std::optional GetAbsolutePathToDotnetFromProgramFiles(); static - std::optional + std::optional InvokeWhereToFindDotnet(); static - std::optional + std::optional GetAbsolutePathToDotnet( - _In_ const std::experimental::filesystem::path & applicationPath, - _In_ const std::experimental::filesystem::path & requestedPath + _In_ const std::filesystem::path & applicationPath, + _In_ const std::filesystem::path & requestedPath ); }; diff --git a/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj b/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj index 6025b459fb..0580c14e85 100644 --- a/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj +++ b/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.csproj @@ -34,9 +34,7 @@ - + diff --git a/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets b/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets index 85d3751b69..a25bbf3b4f 100644 --- a/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets +++ b/src/Microsoft.AspNetCore.Server.IIS/Microsoft.AspNetCore.Server.IIS.targets @@ -7,7 +7,7 @@ - V2 + AspNetCoreModuleV2 diff --git a/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.targets b/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.targets index 67c6152880..a5f7fc6088 100644 --- a/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.targets +++ b/src/Microsoft.AspNetCore.Server.IISIntegration/Microsoft.AspNetCore.Server.IISIntegration.targets @@ -1,7 +1,7 @@ - V2 + AspNetCoreModuleV2 diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs index 4a3caadd8e..81cebf1568 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting internal class IISApplication { internal const int ERROR_OBJECT_NOT_FOUND = unchecked((int)0x800710D8); + internal const int ERROR_SHARING_VIOLATION = unchecked((int)0x80070020); private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(10); private static readonly TimeSpan _retryDelay = TimeSpan.FromMilliseconds(200); @@ -109,7 +110,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting _logger.LogInformation($"Tried to start site, state: {state.ToString()}"); } } - catch (Exception ex) when (ex is DllNotFoundException || (ex is COMException && ex.HResult == ERROR_OBJECT_NOT_FOUND) ) + catch (Exception ex) when ( + ex is DllNotFoundException || + ex is COMException && + (ex.HResult == ERROR_OBJECT_NOT_FOUND || ex.HResult == ERROR_SHARING_VIOLATION)) { // Accessing the site.State property while the site // is starting up returns the COMException diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj index 766b470a50..c13eb6214b 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj @@ -27,10 +27,6 @@ PackageCopyToOutput="true" PackagePath="contentFiles/any/any/%(ShimComponents.Platform)/%(ShimComponents.PackageSubPath)"/> - - diff --git a/test/Common.FunctionalTests/AppOfflineTests.cs b/test/Common.FunctionalTests/AppOfflineTests.cs index d8d0861d3a..c191eea4c7 100644 --- a/test/Common.FunctionalTests/AppOfflineTests.cs +++ b/test/Common.FunctionalTests/AppOfflineTests.cs @@ -1,6 +1,7 @@ // 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.Net; using System.Net.Http; @@ -19,6 +20,8 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests [Collection(PublishedSitesCollection.Name)] public class AppOfflineTests : IISFunctionalTestBase { + private static readonly TimeSpan RetryDelay = TimeSpan.FromMilliseconds(100); + private readonly PublishedSitesFixture _fixture; public AppOfflineTests(PublishedSitesFixture fixture) @@ -94,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests // 1. ANCM detects app_offline before it starts the request - if AssertAppOffline succeeds we've hit it // 2. Intended scenario where app starts and then shuts down // In first case we remove app_offline and try again - await Task.Delay(100); + await Task.Delay(RetryDelay); AddAppOffline(deploymentResult.ContentRoot); @@ -182,7 +185,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests () => AddAppOffline(deploymentResult.ContentRoot), e => Logger.LogError($"Failed to create app_offline : {e.Message}"), retryCount: 3, - retryDelayMilliseconds: 100); + retryDelayMilliseconds: RetryDelay.Milliseconds); RemoveAppOffline(deploymentResult.ContentRoot); } @@ -218,7 +221,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests () => File.Delete(Path.Combine(appPath, "app_offline.htm")), e => Logger.LogError($"Failed to remove app_offline : {e.Message}"), retryCount: 3, - retryDelayMilliseconds: 100); + retryDelayMilliseconds: RetryDelay.Milliseconds); } private async Task AssertAppOffline(IISDeploymentResult deploymentResult, string expectedResponse = "The app is offline.") @@ -229,6 +232,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests { // Keep retrying until app_offline is present. response = await deploymentResult.HttpClient.GetAsync("HelloWorld"); + await Task.Delay(RetryDelay); } Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode); diff --git a/test/Common.FunctionalTests/CommonStartupTests.cs b/test/Common.FunctionalTests/CommonStartupTests.cs new file mode 100644 index 0000000000..760c1ad04b --- /dev/null +++ b/test/Common.FunctionalTests/CommonStartupTests.cs @@ -0,0 +1,48 @@ +// 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.Net; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; + +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests +{ + [Collection(PublishedSitesCollection.Name)] + public class CommonStartupTests : IISFunctionalTestBase + { + private readonly PublishedSitesFixture _fixture; + + public CommonStartupTests(PublishedSitesFixture fixture) + { + _fixture = fixture; + } + + public static TestMatrix TestVariants + => TestMatrix.ForServers(DeployerSelector.ServerType) + .WithTfms(Tfm.NetCoreApp22) + .WithAllApplicationTypes() + .WithAllAncmVersions() + .WithAllHostingModels(); + + [ConditionalTheory] + [MemberData(nameof(TestVariants))] + public async Task StartupStress(TestVariant variant) + { + var deploymentParameters = _fixture.GetBaseDeploymentParameters(variant, publish: true); + + var deploymentResult = await DeployAsync(deploymentParameters); + + await Helpers.StressLoad(deploymentResult.HttpClient, "/HelloWorld", response => { + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("Hello World", response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + }); + } + } +} diff --git a/test/CommonLibTests/FileOutputManagerTests.cpp b/test/CommonLibTests/FileOutputManagerTests.cpp index d0caa524a8..ae1085408c 100644 --- a/test/CommonLibTests/FileOutputManagerTests.cpp +++ b/test/CommonLibTests/FileOutputManagerTests.cpp @@ -41,7 +41,7 @@ namespace FileOutManagerStartupTests wprintf(expected, out); } - for (auto & p : std::experimental::filesystem::directory_iterator(tempDirectory.path())) + for (auto & p : std::filesystem::directory_iterator(tempDirectory.path())) { std::wstring filename(p.path().filename()); ASSERT_EQ(filename.substr(0, fileNamePrefix.size()), fileNamePrefix); diff --git a/test/CommonLibTests/GlobalVersionTests.cpp b/test/CommonLibTests/GlobalVersionTests.cpp index 9c74b6720e..f38c9361d2 100644 --- a/test/CommonLibTests/GlobalVersionTests.cpp +++ b/test/CommonLibTests/GlobalVersionTests.cpp @@ -7,7 +7,7 @@ namespace GlobalVersionTests { using ::testing::Test; - namespace fs = std::experimental::filesystem; + namespace fs = std::filesystem; class GlobalVersionTest : public Test { diff --git a/test/CommonLibTests/Helpers.cpp b/test/CommonLibTests/Helpers.cpp index 3e429a6665..ccca6cad5b 100644 --- a/test/CommonLibTests/Helpers.cpp +++ b/test/CommonLibTests/Helpers.cpp @@ -28,7 +28,7 @@ TempDirectory::TempDirectory() RPC_CSTR szUuid = NULL; if (UuidToStringA(&uuid, &szUuid) == RPC_S_OK) { - m_path = std::experimental::filesystem::temp_directory_path() / szUuid; + m_path = std::filesystem::temp_directory_path() / reinterpret_cast(szUuid); RpcStringFreeA(&szUuid); return; } @@ -37,5 +37,5 @@ TempDirectory::TempDirectory() TempDirectory::~TempDirectory() { - std::experimental::filesystem::remove_all(m_path); + std::filesystem::remove_all(m_path); } diff --git a/test/CommonLibTests/Helpers.h b/test/CommonLibTests/Helpers.h index 657766dd43..67256966bb 100644 --- a/test/CommonLibTests/Helpers.h +++ b/test/CommonLibTests/Helpers.h @@ -18,11 +18,11 @@ public: ~TempDirectory(); - std::experimental::filesystem::path path() const + std::filesystem::path path() const { return m_path; } private: - std::experimental::filesystem::path m_path; + std::filesystem::path m_path; }; diff --git a/tools/update_schema.ps1 b/tools/update_schema.ps1 index 64f8248af4..2a45a3152c 100644 --- a/tools/update_schema.ps1 +++ b/tools/update_schema.ps1 @@ -15,10 +15,7 @@ $ancmSchemaFiles = @( "aspnetcore_schema_v2.xml" ) -$ancmSchemaFileLocations = @( - @(Resolve-Path "$PSScriptRoot\..\src\AspNetCoreModuleV1\AspNetCore\aspnetcore_schema.xml"), - @(Resolve-Path "$PSScriptRoot\..\src\AspNetCoreModuleV2\AspNetCore\aspnetcore_schema_v2.xml") -) +$ancmSchemaFileLocation = Resolve-Path "$PSScriptRoot\..\src\AspNetCoreModuleV2\AspNetCore\aspnetcore_schema_v2.xml"; [bool]$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") @@ -46,7 +43,7 @@ if (-not $isAdmin -and -not $WhatIfPreference) { for ($i=0; $i -lt $ancmSchemaFiles.Length; $i++) { $schemaFile = $ancmSchemaFiles[$i] - $schemaSource = $ancmSchemaFileLocations[$i] + $schemaSource = $ancmSchemaFileLocation $destinations = @( "${env:ProgramFiles(x86)}\IIS Express\config\schema\",