简体   繁体   中英

.net core 3.1 HostBuilder not having RunAsServiceAsync method (IHostBuilder does not contain definition for RunAsServiceAsync)

I have .net core 3.1 console application and I want to run it as a windows service, my program.cs looks like

public class Program
    {
        public static async Task Main(string[] args)
        {
            var isService = !(Debugger.IsAttached || args.Contains("--console"));

            var builder = CreateHostBuilder(args);

            if (isService)
            {
                await builder.RunAsServiceAsync();
            }
            else
            {
                await builder.RunConsoleAsync();
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker1>();
                    services.AddHostedService<Worker2>();
                });
    }

and the .csproj is

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UserSecretsId>dotnet-MyWorkerService-16487890-DF99-45C2-8DC4-5475A21D6B75</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.16" />
    <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.16" />
  </ItemGroup>
</Project>

but for RunAsServiceAsync() error is coming like "IHostBuilder does not contain definition for RunAsServiceAsync"

Can anyone please point to me where / what I am missing?

RunAsServiceAsync appears to be 3rd party extension on IHostBuilder .

It does not appear to be a built in function, native to .NET Core.

I found an old implementation on GitHub here that you could probably implement yourself

public static class ServiceBaseLifetimeHostExtensions
{
    public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
    {
        return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
    }

    public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default)
    {
        return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken);
    }
}

public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
    private TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();

    public ServiceBaseLifetime(IApplicationLifetime applicationLifetime)
    {
        ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
    }

    private IApplicationLifetime ApplicationLifetime { get; }

    public Task WaitForStartAsync(CancellationToken cancellationToken)
    {
        cancellationToken.Register(() => _delayStart.TrySetCanceled());
        ApplicationLifetime.ApplicationStopping.Register(Stop);

        new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
        return _delayStart.Task;
    }

    private void Run()
    {
        try
        {
            Run(this); // This blocks until the service is stopped.
            _delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
        }
        catch (Exception ex)
        {
            _delayStart.TrySetException(ex);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        Stop();
        return Task.CompletedTask;
    }

    // Called by base.Run when the service is ready to start.
    protected override void OnStart(string[] args)
    {
        _delayStart.TrySetResult(null);
        base.OnStart(args);
    }

    // Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
    // That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
    protected override void OnStop()
    {
        ApplicationLifetime.StopApplication();
        base.OnStop();
    }
}

But it appears that this service based functionality is now built in when UseWindowsService is called on the builder.

So in that case you would need to refactor your code accordingly to get the desired behavior

public class Program {
    public static async Task Main(string[] args) {
        var isService = !(Debugger.IsAttached || args.Contains("--console"));

        var builder = CreateHostBuilder(args);

        if (isService) {
            await builder.RunAsServiceAsync();
        } else {
            await builder.RunConsoleAsync();
        }
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)            
            .ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<Worker1>();
                services.AddHostedService<Worker2>();
            });
}

public static class ServiceBaseLifetimeHostExtensions {
    public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default) {
        return hostBuilder.UseWindowsService().Build().RunAsync(cancellationToken);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM