将Windows服务与aspnetboilerplate

时间:2017-12-01 08:24:12

标签: c# dependency-injection asp.net-core console-application aspnetboilerplate

目标

好的,所以我的目标是在我的aspnetboilerplate Web应用程序旁边运行一个Windows服务。 Windows服务的原因是它将从完全独立的虚拟服务器运行Hangfire后台作业。

配置

这是我用来搞定事情的模板 enter image description here

仅供参考,一切都来自网络应用程序。

这是服务程序文件(我正在使用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:&#39;没有找到支持服务Portal.BackupMonitoring.IBackupMonitoringManager的组件&#39;

但是,如果我要运行Web应用程序,它工作正常,所以对我来说这不是IBackupMonitoringManager的问题。它必须与服务无法针对DI进行注册有关。

我在这个回购中查看了https://github.com/aspnetboilerplate/aspnetboilerplate-samples

的例子

但是这些示例要么已大量过时,要么我看不到带有网络核心Web应用程序的控制台应用程序的示例。

任何有关如何开始这方面的帮助将不胜感激。

更新

这是作业尝试执行时的新异常。

  

Castle.MicroKernel.Handlers.HandlerException:&#39;无法创建组件   &#39; Portal.Authorization.Users.UserManager&#39;因为它有依赖性   满意。

     

&#39; Portal.Authorization.Users.UserManager&#39;正在等待以下   依赖关系:    - 服务&#39; Portal.Authorization.Roles.RoleManager&#39;已注册,但也在等待依赖。   &#39; Portal.Authorization.Roles.RoleManager&#39;正在等待以下   依赖关系:    - Service&#39; 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,   公钥= adb9793829ddae60]]&#39;没有注册。    - 服务&#39; Microsoft.AspNetCore.Identity.ILookupNormalizer&#39;没有注册。    - 服务&#39; Microsoft.AspNetCore.Identity.IdentityErrorDescriber&#39;没有注册。    - Service&#39; Microsoft.Extensions.Logging.ILogger 1[[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]]&#39;哪不是   注册。    - 服务&#39; Microsoft.Extensions.Options.IOptions 1[[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]]&#39;   没有注册。    - Service&#39; System.Collections.Generic.IEnumerable 1[[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,   公钥= adb9793829ddae60]]&#39;没有注册。    - Service&#39; System.Collections.Generic.IEnumerable 1[[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,   公钥= adb9793829ddae60]]&#39;没有注册。    - 服务&#39; Microsoft.AspNetCore.Identity.ILookupNormalizer&#39;没有注册。    - 服务&#39; Microsoft.AspNetCore.Identity.IdentityErrorDescriber&#39;没有注册。    - Service&#39; System.IServiceProvider&#39;没有注册。    - Service&#39; Microsoft.Extensions.Logging.ILogger 1[[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,   公钥= adb9793829ddae60]]&#39;没有注册。 &#39;

1 个答案:

答案 0 :(得分:1)

我想我现在已经有了这个,所以我将把它作为答案发布,但是如果有任何问题请告诉我。

首先,我必须安装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服务运行后台作业,虽然我会尝试减少依赖项和重复代码。