将 Windows 服务与 aspnetboilerplate 集成
Integrate a Windows service with aspnetboilerplate
目标
好的,所以我的目标是在我的 aspnetboilerplate Web 应用程序旁边有一个 windows 服务 运行。 windows 服务的原因是它将 运行 来自完全独立的虚拟服务器的 Hangfire 后台作业。
配置
这是我用来让事情顺利进行的模板
仅供参考,一切都在网络应用程序中运行。
这是服务程序文件(我正在使用 Topshelf,但我认为这不重要)。
HostFactory.Run(x =>
{
x.Service<PortalService>(sc =>
{
sc.ConstructUsing(() => new PortalService());
sc.WhenStarted((tc, hostControl) => tc.Start(hostControl));
sc.WhenStopped((tc, hostControl) => tc.Stop(hostControl));
});
x.UseLog4Net();
x.RunAsLocalSystem();
x.SetServiceName(PortalService.ServiceName);
x.SetDisplayName(PortalService.ServiceDisplayName);
x.SetDescription(PortalService.ServiceDescription);
x.StartAutomatically();
});
这是服务模块
[DependsOn(typeof(PortalCoreModule), typeof(PortalEntityFrameworkModule), typeof(PortalApplicationModule), typeof(AbpHangfireModule))]
public class PortalServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(PortalServiceModule).GetAssembly());
}
public override void PreInitialize()
{
Configuration.BackgroundJobs.UseHangfire(config =>
{
config.GlobalConfiguration.UseSqlServerStorage(PortalConsts.ConnectionStringName, new SqlServerStorageOptions
{
PrepareSchemaIfNecessary = true
});
config.Server = new BackgroundJobServer(new BackgroundJobServerOptions
{
Queues = new[] {BackgroundJobQueueNames.Critical, BackgroundJobQueueNames.Autotask, BackgroundJobQueueNames.Default}
});
config.GlobalConfiguration.UseConsole();
});
GlobalJobFilters.Filters.Add(new DisableMultipleQueuedItemsFilter());
}
}
然后这是我的服务代码
public class PortalService : ServiceControl
{
public const string ServiceName = "PortalWorker";
public const string ServiceDisplayName = "Portal Worker";
public const string ServiceDescription = "Process the background jobs for the Portal.";
private AbpBootstrapper _bootstrapper;
public bool Start(HostControl hostControl)
{
_bootstrapper = AbpBootstrapper.Create<PortalServiceModule>();
_bootstrapper.IocManager
.IocContainer
.AddFacility<LoggingFacility>(f => f.UseAbpLog4Net().WithConfig("log4net.config"));
_bootstrapper.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
_bootstrapper.Dispose();
return true;
}
}
然而每次我 运行 服务时,我都会收到以下异常
Castle.MicroKernel.ComponentNotFoundException: 'No component for supporting the service Portal.BackupMonitoring.IBackupMonitoringManager was found'
但是,如果我要 运行 Web 应用程序,它工作正常,所以对我来说这不是 IBackupMonitoringManager 的问题。一定是Service不能注册DI的问题。
我查看了这个 repo 中的示例 https://github.com/aspnetboilerplate/aspnetboilerplate-samples
但是这些示例要么已经过时,要么我看不到带有 .net 核心 Web 应用程序的控制台应用程序示例。
如能提供有关从何处着手的任何帮助,我们将不胜感激。
更新
这是作业尝试执行时的新异常。
Castle.MicroKernel.Handlers.HandlerException: 'Can't create component
'Portal.Authorization.Users.UserManager' as it has dependencies to be
satisfied.
'Portal.Authorization.Users.UserManager' is waiting for the following
dependencies:
- Service 'Portal.Authorization.Roles.RoleManager' which was registered but is also waiting for dependencies.
'Portal.Authorization.Roles.RoleManager' is waiting for the following
dependencies:
- Service 'System.Collections.Generic.IEnumerable1[[Microsoft.AspNetCore.Identity.IRoleValidator
1[[Portal.Authorization.Roles.Role,
Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]],
Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60]]' which was not registered.
- Service 'Microsoft.AspNetCore.Identity.ILookupNormalizer' which was not registered.
- Service 'Microsoft.AspNetCore.Identity.IdentityErrorDescriber' which was not registered.
- Service 'Microsoft.Extensions.Logging.ILogger1[[Abp.Authorization.Roles.AbpRoleManager
2[[Portal.Authorization.Roles.Role,
Portal.Core, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null],[Portal.Authorization.Users.User, Portal.Core,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Abp.ZeroCore,
Version=3.2.4.0, Culture=neutral, PublicKeyToken=null]]' which was not
registered.
- Service 'Microsoft.Extensions.Options.IOptions1[[Microsoft.AspNetCore.Identity.IdentityOptions,
Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60]]' which was not registered.
- Service 'Microsoft.AspNetCore.Identity.IPasswordHasher
1[[Portal.Authorization.Users.User,
Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
which was not registered.
- Service 'System.Collections.Generic.IEnumerable1[[Microsoft.AspNetCore.Identity.IUserValidator
1[[Portal.Authorization.Users.User,
Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]],
Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60]]' which was not registered.
- Service 'System.Collections.Generic.IEnumerable1[[Microsoft.AspNetCore.Identity.IPasswordValidator
1[[Portal.Authorization.Users.User,
Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]],
Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60]]' which was not registered.
- Service 'Microsoft.AspNetCore.Identity.ILookupNormalizer' which was not registered.
- Service 'Microsoft.AspNetCore.Identity.IdentityErrorDescriber' which was not registered.
- Service 'System.IServiceProvider' which was not registered.
- Service 'Microsoft.Extensions.Logging.ILogger1[[Microsoft.AspNetCore.Identity.UserManager
1[[Portal.Authorization.Users.User,
Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]],
Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral,
PublicKeyToken=adb9793829ddae60]]' which was not registered. '
我想我现在已经明白了,所以我打算 post 它作为答案,但如果有任何问题请告诉我。
首先我必须安装 Abp.AspNetCore 包。这允许访问 IServiceCollection.AddAbp()
扩展方法。
所以我的Program.cs
变成了这个
static void Main(string[] args)
{
Clock.Provider = ClockProviders.Utc;
var services = new ServiceCollection();
IdentityRegistrar.Register(services);
services.AddAbp<PortalServiceModule>(options =>
{
//Configure Log4Net logging
options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
);
});
HostFactory.Run(x =>
{
x.Service<PortalService>(sc =>
{
sc.ConstructUsing(() => new PortalService());
sc.WhenStarted((tc, hostControl) => tc.Start(hostControl));
sc.WhenStopped((tc, hostControl) => tc.Stop(hostControl));
});
x.UseLog4Net();
x.RunAsLocalSystem();
x.SetServiceName(PortalService.ServiceName);
x.SetDisplayName(PortalService.ServiceDisplayName);
x.SetDescription(PortalService.ServiceDescription);
x.StartAutomatically();
});
}
我在使用 PortalServiceModule 时遇到了一些问题。自动映射器配置已经在 PortalApplicationModule 中,因此我可能需要重新访问它以删除重复代码。目前,这就是我的工作。
[DependsOn(typeof(PortalCoreModule), typeof(PortalEntityFrameworkModule), typeof(PortalApplicationModule), typeof(AbpHangfireModule), typeof(AbpZeroCoreModule), typeof(AbpAutoMapperModule))]
public class PortalServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(PortalServiceModule).GetAssembly());
Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
{
cfg.CreateMap<object, int?>().ConvertUsing<NullableIntTypeConverter>();
// Scan the assembly for classes which inherit from AutoMapper.Profile
cfg.AddProfiles(typeof(PortalApplicationModule).GetAssembly());
});
Configuration.BackgroundJobs.UseHangfire(config =>
{
config.GlobalConfiguration.UseSqlServerStorage(PortalConsts.ConnectionStringName, new SqlServerStorageOptions
{
PrepareSchemaIfNecessary = true
});
config.Server = new BackgroundJobServer(new BackgroundJobServerOptions
{
Queues = new[] { BackgroundJobQueueNames.Critical, BackgroundJobQueueNames.Autotask, BackgroundJobQueueNames.Default }
});
config.GlobalConfiguration.UseConsole();
});
GlobalJobFilters.Filters.Add(new DisableMultipleQueuedItemsFilter());
}
public override void PostInitialize()
{
HangfireJobsConfigurer.Configure();
}
}
然后我的实际服务代码变成了这个
public class PortalService : ServiceControl
{
public const string ServiceName = "PortalWorker";
public const string ServiceDisplayName = "Portal Worker";
public const string ServiceDescription = "Process the background jobs for the Portal.";
private AbpBootstrapper _bootstrapper;
public bool Start(HostControl hostControl)
{
_bootstrapper = AbpBootstrapper.Create<PortalServiceModule>();
_bootstrapper.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
_bootstrapper.Dispose();
return true;
}
}
现在我可以 运行 来自 windows 服务的后台作业,尽管我会尝试减少依赖性和重复代码。
目标
好的,所以我的目标是在我的 aspnetboilerplate Web 应用程序旁边有一个 windows 服务 运行。 windows 服务的原因是它将 运行 来自完全独立的虚拟服务器的 Hangfire 后台作业。
配置
这是我用来让事情顺利进行的模板
仅供参考,一切都在网络应用程序中运行。
这是服务程序文件(我正在使用 Topshelf,但我认为这不重要)。
HostFactory.Run(x =>
{
x.Service<PortalService>(sc =>
{
sc.ConstructUsing(() => new PortalService());
sc.WhenStarted((tc, hostControl) => tc.Start(hostControl));
sc.WhenStopped((tc, hostControl) => tc.Stop(hostControl));
});
x.UseLog4Net();
x.RunAsLocalSystem();
x.SetServiceName(PortalService.ServiceName);
x.SetDisplayName(PortalService.ServiceDisplayName);
x.SetDescription(PortalService.ServiceDescription);
x.StartAutomatically();
});
这是服务模块
[DependsOn(typeof(PortalCoreModule), typeof(PortalEntityFrameworkModule), typeof(PortalApplicationModule), typeof(AbpHangfireModule))]
public class PortalServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(PortalServiceModule).GetAssembly());
}
public override void PreInitialize()
{
Configuration.BackgroundJobs.UseHangfire(config =>
{
config.GlobalConfiguration.UseSqlServerStorage(PortalConsts.ConnectionStringName, new SqlServerStorageOptions
{
PrepareSchemaIfNecessary = true
});
config.Server = new BackgroundJobServer(new BackgroundJobServerOptions
{
Queues = new[] {BackgroundJobQueueNames.Critical, BackgroundJobQueueNames.Autotask, BackgroundJobQueueNames.Default}
});
config.GlobalConfiguration.UseConsole();
});
GlobalJobFilters.Filters.Add(new DisableMultipleQueuedItemsFilter());
}
}
然后这是我的服务代码
public class PortalService : ServiceControl
{
public const string ServiceName = "PortalWorker";
public const string ServiceDisplayName = "Portal Worker";
public const string ServiceDescription = "Process the background jobs for the Portal.";
private AbpBootstrapper _bootstrapper;
public bool Start(HostControl hostControl)
{
_bootstrapper = AbpBootstrapper.Create<PortalServiceModule>();
_bootstrapper.IocManager
.IocContainer
.AddFacility<LoggingFacility>(f => f.UseAbpLog4Net().WithConfig("log4net.config"));
_bootstrapper.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
_bootstrapper.Dispose();
return true;
}
}
然而每次我 运行 服务时,我都会收到以下异常
Castle.MicroKernel.ComponentNotFoundException: 'No component for supporting the service Portal.BackupMonitoring.IBackupMonitoringManager was found'
但是,如果我要 运行 Web 应用程序,它工作正常,所以对我来说这不是 IBackupMonitoringManager 的问题。一定是Service不能注册DI的问题。
我查看了这个 repo 中的示例 https://github.com/aspnetboilerplate/aspnetboilerplate-samples
但是这些示例要么已经过时,要么我看不到带有 .net 核心 Web 应用程序的控制台应用程序示例。
如能提供有关从何处着手的任何帮助,我们将不胜感激。
更新
这是作业尝试执行时的新异常。
Castle.MicroKernel.Handlers.HandlerException: 'Can't create component 'Portal.Authorization.Users.UserManager' as it has dependencies to be satisfied.
'Portal.Authorization.Users.UserManager' is waiting for the following dependencies: - Service 'Portal.Authorization.Roles.RoleManager' which was registered but is also waiting for dependencies. 'Portal.Authorization.Roles.RoleManager' is waiting for the following dependencies: - Service 'System.Collections.Generic.IEnumerable
1[[Microsoft.AspNetCore.Identity.IRoleValidator
1[[Portal.Authorization.Roles.Role, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' which was not registered. - Service 'Microsoft.AspNetCore.Identity.ILookupNormalizer' which was not registered. - Service 'Microsoft.AspNetCore.Identity.IdentityErrorDescriber' which was not registered. - Service 'Microsoft.Extensions.Logging.ILogger1[[Abp.Authorization.Roles.AbpRoleManager
2[[Portal.Authorization.Roles.Role, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Portal.Authorization.Users.User, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Abp.ZeroCore, Version=3.2.4.0, Culture=neutral, PublicKeyToken=null]]' which was not registered. - Service 'Microsoft.Extensions.Options.IOptions1[[Microsoft.AspNetCore.Identity.IdentityOptions, Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' which was not registered. - Service 'Microsoft.AspNetCore.Identity.IPasswordHasher
1[[Portal.Authorization.Users.User, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' which was not registered. - Service 'System.Collections.Generic.IEnumerable1[[Microsoft.AspNetCore.Identity.IUserValidator
1[[Portal.Authorization.Users.User, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' which was not registered. - Service 'System.Collections.Generic.IEnumerable1[[Microsoft.AspNetCore.Identity.IPasswordValidator
1[[Portal.Authorization.Users.User, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' which was not registered. - Service 'Microsoft.AspNetCore.Identity.ILookupNormalizer' which was not registered. - Service 'Microsoft.AspNetCore.Identity.IdentityErrorDescriber' which was not registered. - Service 'System.IServiceProvider' which was not registered. - Service 'Microsoft.Extensions.Logging.ILogger1[[Microsoft.AspNetCore.Identity.UserManager
1[[Portal.Authorization.Users.User, Portal.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Extensions.Identity.Core, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' which was not registered. '
我想我现在已经明白了,所以我打算 post 它作为答案,但如果有任何问题请告诉我。
首先我必须安装 Abp.AspNetCore 包。这允许访问 IServiceCollection.AddAbp()
扩展方法。
所以我的Program.cs
变成了这个
static void Main(string[] args)
{
Clock.Provider = ClockProviders.Utc;
var services = new ServiceCollection();
IdentityRegistrar.Register(services);
services.AddAbp<PortalServiceModule>(options =>
{
//Configure Log4Net logging
options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
);
});
HostFactory.Run(x =>
{
x.Service<PortalService>(sc =>
{
sc.ConstructUsing(() => new PortalService());
sc.WhenStarted((tc, hostControl) => tc.Start(hostControl));
sc.WhenStopped((tc, hostControl) => tc.Stop(hostControl));
});
x.UseLog4Net();
x.RunAsLocalSystem();
x.SetServiceName(PortalService.ServiceName);
x.SetDisplayName(PortalService.ServiceDisplayName);
x.SetDescription(PortalService.ServiceDescription);
x.StartAutomatically();
});
}
我在使用 PortalServiceModule 时遇到了一些问题。自动映射器配置已经在 PortalApplicationModule 中,因此我可能需要重新访问它以删除重复代码。目前,这就是我的工作。
[DependsOn(typeof(PortalCoreModule), typeof(PortalEntityFrameworkModule), typeof(PortalApplicationModule), typeof(AbpHangfireModule), typeof(AbpZeroCoreModule), typeof(AbpAutoMapperModule))]
public class PortalServiceModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(PortalServiceModule).GetAssembly());
Configuration.Modules.AbpAutoMapper().Configurators.Add(cfg =>
{
cfg.CreateMap<object, int?>().ConvertUsing<NullableIntTypeConverter>();
// Scan the assembly for classes which inherit from AutoMapper.Profile
cfg.AddProfiles(typeof(PortalApplicationModule).GetAssembly());
});
Configuration.BackgroundJobs.UseHangfire(config =>
{
config.GlobalConfiguration.UseSqlServerStorage(PortalConsts.ConnectionStringName, new SqlServerStorageOptions
{
PrepareSchemaIfNecessary = true
});
config.Server = new BackgroundJobServer(new BackgroundJobServerOptions
{
Queues = new[] { BackgroundJobQueueNames.Critical, BackgroundJobQueueNames.Autotask, BackgroundJobQueueNames.Default }
});
config.GlobalConfiguration.UseConsole();
});
GlobalJobFilters.Filters.Add(new DisableMultipleQueuedItemsFilter());
}
public override void PostInitialize()
{
HangfireJobsConfigurer.Configure();
}
}
然后我的实际服务代码变成了这个
public class PortalService : ServiceControl
{
public const string ServiceName = "PortalWorker";
public const string ServiceDisplayName = "Portal Worker";
public const string ServiceDescription = "Process the background jobs for the Portal.";
private AbpBootstrapper _bootstrapper;
public bool Start(HostControl hostControl)
{
_bootstrapper = AbpBootstrapper.Create<PortalServiceModule>();
_bootstrapper.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
_bootstrapper.Dispose();
return true;
}
}
现在我可以 运行 来自 windows 服务的后台作业,尽管我会尝试减少依赖性和重复代码。