我使用TopShelf和Quartz将某些作业安排为Windows服务。对于依赖注入,我使用Microsoft.Extensions.DependencyInjection包。我的问题是作用域功能,我想在作用域生命周期中配置服务时(例如ISampleService),每轮运行作业,处置作用域生命周期服务,并在下一轮再次实例化,但是作用域生命周期的行为类似于单例生命周期。以下是我的代码:
依赖项:
using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Topshelf;
主要方法:
static void Main(string[] args)
{
var provider = RegisterServices();
HostFactory.Run(cfg =>
{
cfg.Service<SampleTask>(s =>
{
s.ConstructUsing(() => provider.GetService<SampleTask>());
s.WhenStarted(async f => await f.Start(provider));
s.WhenStopped(f => f.Stop());
});
cfg.RunAsLocalSystem();
cfg.SetDescription("description");
cfg.SetDisplayName("name");
cfg.SetServiceName("service");
});
}
RegisterServices方法
public static ServiceProvider RegisterServices()
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddTransient<SampleTask>();
services.AddTransient<IJob, SampleJob>();
services.AddScoped<ISampleService, SampleService>
var provider = services.BuildServiceProvider();
return provider;
}
JobFactory:
public class JobFactory : IJobFactory
{
protected readonly IServiceProvider Container;
public JobFactory(IServiceProvider container)
{
Container = container;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return Container.GetService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
(job as IDisposable)?.Dispose();
}
}
任务:
public class SampleTask
{
private readonly ISchedulerFactory _schedulerFactory;
public SampleTask(ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
}
public async Task Start(ServiceProvider provider)
{
var scheduler = await _schedulerFactory.GetScheduler();
scheduler.JobFactory = new JobFactory(provider);
var job = JobBuilder.Create<IJob>().Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("Sample1", "SampleGroup")
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(10)
.RepeatForever())
.StartNow()
.Build();
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();
}
public bool Stop()
{
return true;
}
}
工作:
public class SampleJob : IJob
{
private readonly ISampleService _sampleService;
public SampleJob(ISampleService sampleService)
{
_sampleService = sampleService;
}
public async Task Execute(IJobExecutionContext context)
{
await Task.FromResult(0);
}
}
答案 0 :(得分:1)
我创建了一个WorkerService项目,并在csproj
文件中添加了一些必需的软件包,如下所示:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.9" />
<PackageReference Include="Topshelf" Version="4.2.1" />
<PackageReference Include="Topshelf.Extensions.Hosting" Version="0.4.0" />
<PackageReference Include="Quartz" Version="3.2.2" />
</ItemGroup>
</Project>
要支持瞬态,作用域和单例,我们需要添加一些类
public class JobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public JobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService<QuartzJobRunner>();
}
public void ReturnJob(IJob job)
{
// we let the DI container handler this
}
}
[DisallowConcurrentExecution]
public class QuartzJobRunner : IJob
{
private readonly IServiceProvider _serviceProvider;
public QuartzJobRunner(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task Execute(IJobExecutionContext context)
{
using (var scope = _serviceProvider.CreateScope())
{
if (scope.ServiceProvider
.GetRequiredService(context.JobDetail.JobType) is IJob job)
await job.Execute(context);
}
}
}
public class QuartzHostedService : BackgroundService
{
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
public QuartzHostedService(ISchedulerFactory schedulerFactory,
IJobFactory jobFactory)
{
_schedulerFactory = schedulerFactory;
_jobFactory = jobFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var scheduler = await _schedulerFactory.GetScheduler(stoppingToken);
scheduler.JobFactory = _jobFactory;
var jobDetail = JobBuilder
.Create<Job1>()
.WithIdentity("Job1")
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("Trigger1")
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(15)
.RepeatForever())
.StartNow()
.Build();
await scheduler.ScheduleJob(jobDetail, trigger, stoppingToken);
await scheduler.Start(stoppingToken);
}
}
然后我创建要实现我的逻辑的工作
[DisallowConcurrentExecution]
public class Job1 : IJob
{
private readonly ILogger<Job1> _logger;
private readonly Service1 _service1;
public Job1(ILogger<Job1> logger, Service1 service1)
{
_logger = logger;
_service1 = service1;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation($"Service Id: {_service1.Id}");
return Task.CompletedTask;
}
}
public class Service1
{
public string Id { get; set; }
public Service1()
{
Id = Guid.NewGuid().ToString();
}
}
主班
public class Program
{
public static void Main(string[] args)
{
var hostBuilder = CreateHostBuilder(args);
if (Debugger.IsAttached)
{
hostBuilder.Build().Run();
}
else
{
hostBuilder.RunAsTopshelfService(hc =>
{
hc.SetDisplayName("Task1");
hc.SetDescription("Task1");
hc.SetServiceName("Task1");
});
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IJobFactory, JobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<QuartzJobRunner>();
services.AddScoped<Job1>();
services.AddSingleton<Service1>();
//services.AddScoped<Service1>();
//services.AddTransient<Service1>();
services.AddHostedService<QuartzHostedService>();
});
}
运行项目后,您可以检查日志并通过检查Service1 Id
确认解决方案是否有效。
请注意,在ConfigureServices
中,以下依赖项定义不得更改
services.AddSingleton<IJobFactory, JobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<QuartzJobRunner>();
services.AddScoped<Job1>();
通过更改Service1
类的依赖范围,您可以看到所有依赖级别都受支持。