使用 Microsoft.Extensions.Hosting.WindowsServices 时无法启动 windows 服务
Cannot start windows service when using Microsoft.Extensions.Hosting.WindowsServices
我尝试按照建议 here 使用 Microsoft.Extensions.Hosting.WindowsServices
创建 Windows 服务。到目前为止一切顺利,我的后台服务 ExecuteAsync
被调用并且日志显示一切正常。作为控制台应用程序启动应用程序也很好,我可以启动它,做我需要做的任何事情,然后停止它。
但是,我随后尝试使用以下方法安装 Windows 服务:
sc create myservice binPath= "\"<path-to-the-exe-file>\" service" start= auto DisplayName= "My Service"
我得到 [SC] CreateService SUCCESS
。但是当我尝试手动启动该服务时,它告诉我它没有及时响应。同样,日志很好,没有错误。事件查看器没有告诉我它可能出错的更多信息,我不知道接下来我该怎么做才能找到问题的原因。
这是我用来配置主机的大概代码:
var containerBuilder = new ContainerBuilder();
IContainer container = null;
var hostBuilder = Host.CreateDefaultBuilder(appArgs);
hostBuilder
.UseServiceProviderFactory(new CustomAutofacServiceProviderFactory(() => container))
.ConfigureServices(services =>
{
services.AddHostedService<BackgroundWorker>();
containerBuilder.Populate(services);
container = containerBuilder.Build();
})
.UseWindowsService();
这是我用于后台服务的class。
public class BackgroundWorker : BackgroundService
{
private readonly IAppContext appContext;
private CancellationTokenRegistration stopRegistration;
public BackgroundWorker(ILogger<BackgroundWorker> logger, IAppContext appContext)
{
this.Logger = logger;
this.appContext = appContext;
}
public ILogger<BackgroundWorker> Logger { get; }
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
this.Logger.Info("Background worker started.");
this.stopRegistration = stoppingToken.Register(() =>
{
this.Logger.Info("Background worker stopping...");
this.stopRegistration.Dispose();
this.Logger.Info("Background worker stopped.");
});
return Task.CompletedTask;
}
}
经过几个小时的努力,我刚刚找到了答案。
我正在使用 Autofac 作为依赖注入容器,在 HostBuilder.ConfigureServices()
我正在构建 Autofac 容器。
在我调用 .UseWindowsService()
之后,为时已晚,因为 Autofac 已经完成了容器的构建。
所以,答案是,在构建容器之前使用.UseWindowsService()
,否则对组合服务没有影响。
这是正在运行的更改代码:
var containerBuilder = new ContainerBuilder();
IContainer container = null;
var hostBuilder = Host.CreateDefaultBuilder(appArgs);
hostBuilder
.UseServiceProviderFactory(new CustomAutofacServiceProviderFactory(() => container))
.ConfigureServices(services =>
{
services.AddHostedService<BackgroundWorker>();
})
.UseWindowsService() //<-- Done BEFORE building container
.ConfigureServices(services =>
{
containerBuilder.Populate(services);
container = containerBuilder.Build();
})
理想情况下,容器不应位于其余设置的外部。
您已经在使用一个自定义服务提供商工厂,它应该包含您手动执行的操作。
Autofac 已经有 AutofacServiceProviderFactory
/// <summary>
/// A factory for creating a <see cref="ContainerBuilder"/> and an <see cref="IServiceProvider" />.
/// </summary>
public class AutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
private readonly Action<ContainerBuilder> _configurationAction;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceProviderFactory"/> class.
/// </summary>
/// <param name="configurationAction">Action on a <see cref="ContainerBuilder"/> that adds component registrations to the conatiner.</param>
public AutofacServiceProviderFactory(Action<ContainerBuilder> configurationAction = null)
{
_configurationAction = configurationAction ?? (builder => { });
}
/// <summary>
/// Creates a container builder from an <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The collection of services.</param>
/// <returns>A container builder that can be used to create an <see cref="IServiceProvider" />.</returns>
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
_configurationAction(builder);
return builder;
}
/// <summary>
/// Creates an <see cref="IServiceProvider" /> from the container builder.
/// </summary>
/// <param name="containerBuilder">The container builder.</param>
/// <returns>An <see cref="IServiceProvider" />.</returns>
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
}
请注意容器构建器是如何由工厂和服务提供者创建和填充的IContainer
这应该允许完成原始设置,而无需在外部手动创建容器
var hostBuilder = Host.CreateDefaultBuilder(appArgs)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureServices(services => {
services.AddHostedService<BackgroundWorker>();
});
参考NuGet
我尝试按照建议 here 使用 Microsoft.Extensions.Hosting.WindowsServices
创建 Windows 服务。到目前为止一切顺利,我的后台服务 ExecuteAsync
被调用并且日志显示一切正常。作为控制台应用程序启动应用程序也很好,我可以启动它,做我需要做的任何事情,然后停止它。
但是,我随后尝试使用以下方法安装 Windows 服务:
sc create myservice binPath= "\"<path-to-the-exe-file>\" service" start= auto DisplayName= "My Service"
我得到 [SC] CreateService SUCCESS
。但是当我尝试手动启动该服务时,它告诉我它没有及时响应。同样,日志很好,没有错误。事件查看器没有告诉我它可能出错的更多信息,我不知道接下来我该怎么做才能找到问题的原因。
这是我用来配置主机的大概代码:
var containerBuilder = new ContainerBuilder();
IContainer container = null;
var hostBuilder = Host.CreateDefaultBuilder(appArgs);
hostBuilder
.UseServiceProviderFactory(new CustomAutofacServiceProviderFactory(() => container))
.ConfigureServices(services =>
{
services.AddHostedService<BackgroundWorker>();
containerBuilder.Populate(services);
container = containerBuilder.Build();
})
.UseWindowsService();
这是我用于后台服务的class。
public class BackgroundWorker : BackgroundService
{
private readonly IAppContext appContext;
private CancellationTokenRegistration stopRegistration;
public BackgroundWorker(ILogger<BackgroundWorker> logger, IAppContext appContext)
{
this.Logger = logger;
this.appContext = appContext;
}
public ILogger<BackgroundWorker> Logger { get; }
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
this.Logger.Info("Background worker started.");
this.stopRegistration = stoppingToken.Register(() =>
{
this.Logger.Info("Background worker stopping...");
this.stopRegistration.Dispose();
this.Logger.Info("Background worker stopped.");
});
return Task.CompletedTask;
}
}
经过几个小时的努力,我刚刚找到了答案。
我正在使用 Autofac 作为依赖注入容器,在 HostBuilder.ConfigureServices()
我正在构建 Autofac 容器。
在我调用 .UseWindowsService()
之后,为时已晚,因为 Autofac 已经完成了容器的构建。
所以,答案是,在构建容器之前使用.UseWindowsService()
,否则对组合服务没有影响。
这是正在运行的更改代码:
var containerBuilder = new ContainerBuilder();
IContainer container = null;
var hostBuilder = Host.CreateDefaultBuilder(appArgs);
hostBuilder
.UseServiceProviderFactory(new CustomAutofacServiceProviderFactory(() => container))
.ConfigureServices(services =>
{
services.AddHostedService<BackgroundWorker>();
})
.UseWindowsService() //<-- Done BEFORE building container
.ConfigureServices(services =>
{
containerBuilder.Populate(services);
container = containerBuilder.Build();
})
理想情况下,容器不应位于其余设置的外部。
您已经在使用一个自定义服务提供商工厂,它应该包含您手动执行的操作。
Autofac 已经有 AutofacServiceProviderFactory
/// <summary>
/// A factory for creating a <see cref="ContainerBuilder"/> and an <see cref="IServiceProvider" />.
/// </summary>
public class AutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
private readonly Action<ContainerBuilder> _configurationAction;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceProviderFactory"/> class.
/// </summary>
/// <param name="configurationAction">Action on a <see cref="ContainerBuilder"/> that adds component registrations to the conatiner.</param>
public AutofacServiceProviderFactory(Action<ContainerBuilder> configurationAction = null)
{
_configurationAction = configurationAction ?? (builder => { });
}
/// <summary>
/// Creates a container builder from an <see cref="IServiceCollection" />.
/// </summary>
/// <param name="services">The collection of services.</param>
/// <returns>A container builder that can be used to create an <see cref="IServiceProvider" />.</returns>
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
_configurationAction(builder);
return builder;
}
/// <summary>
/// Creates an <see cref="IServiceProvider" /> from the container builder.
/// </summary>
/// <param name="containerBuilder">The container builder.</param>
/// <returns>An <see cref="IServiceProvider" />.</returns>
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
}
请注意容器构建器是如何由工厂和服务提供者创建和填充的IContainer
这应该允许完成原始设置,而无需在外部手动创建容器
var hostBuilder = Host.CreateDefaultBuilder(appArgs)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureServices(services => {
services.AddHostedService<BackgroundWorker>();
});
参考NuGet