Fixed the bug in the windows service host where if application stop is requested, the service wouldn't know about it. (#4553)

* Fixed the bug in the windows service host where if application stop is requested, the service wouldn't know about it.

* Fixed a typo.

* Update src/Hosting/WindowsServices/test/Microsoft.AspNetCore.Hosting.WindowsServices.Tests.csproj

* Removed unneeded EditorBrowsable for internal API.

* Fixed tests to ignore Linux and MacOS.

* Added new line to end of file.

* Using [ConditionalFact] instead of [Fact].
This commit is contained in:
Ivan Zlatanov 2019-01-14 20:26:15 +02:00 committed by Chris Ross
parent 3f4622ffe0
commit c560edee28
6 changed files with 116 additions and 6 deletions

View File

@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.TestHo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Hosting.WindowsServices", "WindowsServices\src\Microsoft.AspNetCore.Hosting.WindowsServices.csproj", "{FA29445B-1BA7-448D-8ADF-56BF6D6633BB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Hosting.WindowsServices.Tests", "WindowsServices\test\Microsoft.AspNetCore.Hosting.WindowsServices.Tests.csproj", "{CCD5D010-7E06-4209-ADD5-3B010A41DCF1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{31587D24-F6B5-4A47-A962-47CA7FEA79D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildWebHostInvalidSignature", "test\testassets\BuildWebHostInvalidSignature\BuildWebHostInvalidSignature.csproj", "{BF146375-AA6C-43F3-BF0A-DCA551892DF8}"
@ -89,6 +91,10 @@ Global
{FA29445B-1BA7-448D-8ADF-56BF6D6633BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA29445B-1BA7-448D-8ADF-56BF6D6633BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA29445B-1BA7-448D-8ADF-56BF6D6633BB}.Release|Any CPU.Build.0 = Release|Any CPU
{CCD5D010-7E06-4209-ADD5-3B010A41DCF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCD5D010-7E06-4209-ADD5-3B010A41DCF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCD5D010-7E06-4209-ADD5-3B010A41DCF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCD5D010-7E06-4209-ADD5-3B010A41DCF1}.Release|Any CPU.Build.0 = Release|Any CPU
{BF146375-AA6C-43F3-BF0A-DCA551892DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF146375-AA6C-43F3-BF0A-DCA551892DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF146375-AA6C-43F3-BF0A-DCA551892DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@ -0,0 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Hosting.WindowsServices.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel;
using System.ServiceProcess;
using Microsoft.Extensions.DependencyInjection;
@ -12,7 +13,7 @@ namespace Microsoft.AspNetCore.Hosting.WindowsServices
/// </summary>
public class WebHostService : ServiceBase
{
private IWebHost _host;
private readonly IWebHost _host;
private bool _stopRequestedByWindows;
/// <summary>
@ -24,14 +25,27 @@ namespace Microsoft.AspNetCore.Hosting.WindowsServices
_host = host ?? throw new ArgumentNullException(nameof(host));
}
/// <summary>
/// This method is not intended for direct use. Its sole purpose is to allow
/// the service to be started by the tests.
/// </summary>
internal void Start() => OnStart(Array.Empty<string>());
protected sealed override void OnStart(string[] args)
{
OnStarting(args);
_host.Start();
OnStarted();
// Register callback for application stopping after we've
// started the service, because otherwise we might introduce unwanted
// race conditions.
_host
.Services
.GetRequiredService<IApplicationLifetime>()
.ApplicationStopped
.ApplicationStopping
.Register(() =>
{
if (!_stopRequestedByWindows)
@ -39,10 +53,6 @@ namespace Microsoft.AspNetCore.Hosting.WindowsServices
Stop();
}
});
_host.Start();
OnStarted();
}
protected sealed override void OnStop()

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Hosting" />
<Reference Include="Microsoft.AspNetCore.Hosting.WindowsServices" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
// 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 Microsoft.AspNetCore.Testing.xunit;
using Xunit;
[assembly: OSSkipCondition(OperatingSystems.MacOSX)]
[assembly: OSSkipCondition(OperatingSystems.Linux)]

View File

@ -0,0 +1,68 @@
// 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.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.WindowsServices;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
namespace Microsoft.AspNetCore.Hosting
{
public class WebHostServiceTests
{
// Reasonable timeout for our test operations to complete.
private static readonly TimeSpan OperationTimeout = TimeSpan.FromSeconds( 5 );
[ConditionalFact]
public async Task StopBeforeServiceStarted()
{
var host = new WebHostBuilder().UseServer(new FakeServer()).Configure(x => { }).Build();
var webHostService = new WebHostService(host);
var applicationLifetime = host.Services.GetRequiredService<IApplicationLifetime>();
applicationLifetime.StopApplication();
webHostService.Start();
await Assert.ThrowsAsync<TaskCanceledException>(
() => Task.Delay(OperationTimeout, applicationLifetime.ApplicationStopped));
}
[ConditionalFact]
public async Task StopAfterServiceStarted()
{
var host = new WebHostBuilder().UseServer( new FakeServer() ).Configure( x => { } ).Build();
var webHostService = new WebHostService(host);
var applicationLifetime = host.Services.GetRequiredService<IApplicationLifetime>();
webHostService.Start();
applicationLifetime.StopApplication();
await Assert.ThrowsAsync<TaskCanceledException>(
() => Task.Delay(OperationTimeout, applicationLifetime.ApplicationStopped));
}
private sealed class FakeServer : IServer
{
IFeatureCollection IServer.Features { get; }
public RequestDelegate RequestDelegate { get; private set; }
public void Dispose() { }
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
{
RequestDelegate = ctx => throw new NotSupportedException();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
}