Dependency injection 在TopShelf和Quartz示波器问题中使用Microsoft DependencyInjection

Dependency injection 在TopShelf和Quartz示波器问题中使用Microsoft DependencyInjection,dependency-injection,windows-services,quartz-scheduler,topshelf,Dependency Injection,Windows Services,Quartz Scheduler,Topshelf,我使用TopShelf和Quartz作为Windows服务来安排一些作业。对于依赖项注入,我使用Microsoft.Extensions.DependencyInjection包。我的问题是关于范围功能,我希望在范围生命周期中配置服务(例如ISampleService)时,在每轮运行的作业中,处置范围生命周期服务,并在下一轮中再次实例化,但范围生命周期的行为类似于单例生命周期。以下是我的代码: 依赖项: using Microsoft.Extensions.DependencyInjection

我使用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");
    });
}
任务:


我创建了一个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>
    

通过更改
Service1
类的依赖范围,您可以看到所有的依赖级别都得到了支持。

我创建了一个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>
    

通过更改
Service1
类的依赖范围,您可以看到所有的依赖级别都得到了支持。

您解决过这个问题吗?@DaImTo是的,我添加了我的解决方案tomorrow@MohammadAkbari很多时间过去了,但也许你仍然可以发布解决方案?@MohammadAkbari你的解决方案是什么?@HeikoScholze我已经添加了我的解决方案你解决过这个问题吗?@DaImTo是的,我添加了我的解决方案tomorrow@MohammadAkbari很多时间过去了,但也许你仍然可以发布解决方案?@MohammadAkbari你的解决方案是什么?@HeikoScholze我已经添加了我的解决方案
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);
    }
}
<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>();
            });
}
services.AddSingleton<IJobFactory, JobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<QuartzJobRunner>();
services.AddScoped<Job1>();