1

我正在尝试创建一个控制台应用程序,该应用程序使用 Simple Injector 运行托管服务,我查看了generichostintegration中的示例。

现在我想更改IProcessor.DoSomeWork为一个async以取消令牌作为参数的函数,以便DoSomeWork可以取消:

public async void DoSomeWork(CancellationToken cancellationToken)
{
    await Task.Delay(_settings.Delay, cancellationToken);
}

我如何从HostedService

private void DoWork()
{
    try
    {
        using (AsyncScopedLifestyle.BeginScope(this.container))
        {
            var service = this.container.GetInstance<TService>();
            this.settings.Action(service);
        }
    }
    catch (Exception ex)
    {
        this.logger.LogError(ex, ex.Message);
    }
}

并以正确的方式配置容器

container.RegisterInstance(new TimedHostedService<IProcessor>.Settings(
    interval: TimeSpan.FromSeconds(10),
    action: processor => processor.DoSomeWork()));

我对此有点意见。也许我想错了?

*** 更新 ***

这就是我最后所做的。我尽量保持简单。

class Program
{
    public static async Task Main(string[] args)
    {
        var container = new Container();

        IHost host = CreateHostBuilder(args, container)
                .Build()
                .UseSimpleInjector(container);

        ConfigureContainer(container);

        await host.RunAsync();
    }

    private static void ConfigureContainer(Container container)
    {
        container.Register<IWorkScheduler, WorkScheduler>(Lifestyle.Singleton);
        // Sets the schedule timer interval
        container.RegisterInstance(new WorkSchedulerSettings(TimeSpan.FromSeconds(1)));

        container.Register<DoSomethingWorker>();
        container.RegisterInstance(new DoSomethingSettings(new TimeSpan(0, 0, 5)));
        container.Register<DoSomethingElseWorker>();
        container.RegisterInstance(new DoSomethingElseSettings(new TimeSpan(0, 0, 10)));

        container.Verify();
    }

    public static IHostBuilder CreateHostBuilder(string[] args, Container container) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddLogging();
                services.AddSimpleInjector(container, options =>
                {
                    // Registers the hosted service as singleton in Simple Injector
                    // and hooks it onto the .NET Core Generic Host pipeline.
                    options.AddHostedService<BackgroundHostedService>();
                    services.AddLogging();
                });
            })
        .UseConsoleLifetime();
}

托管服务

public class BackgroundHostedService
    : BackgroundService
{
    private readonly IWorkScheduler _scheduler;
    private readonly Container _container;
    private readonly ILogger _logger;

    public BackgroundHostedService(IWorkScheduler scheduler, Container container, ILogger<BackgroundHostedService> logger)
    {
        _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
        _container = container ?? throw new ArgumentNullException(nameof(container));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public override Task StartAsync(CancellationToken cancellationToken)
    {
        LoadWorkers();
        return base.StartAsync(cancellationToken);
    }

    protected override Task ExecuteAsync(CancellationToken cancellationToken)
    {
        try
        {
            _scheduler.Start();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, ex.Message);
        }
        return Task.CompletedTask;
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        await _scheduler.Stop();
    }

    private void LoadWorkers()
    {
        // Hook up triggers and specify span period and if they have to run once at time.
        WorkTrigger trigger1 = new WorkTrigger(_container.GetInstance<DoSomethingWorker>(), new TimeSpan(0, 0, 2), false);
        _scheduler.AddTrigger(trigger1);

        WorkTrigger trigger2 = new WorkTrigger(_container.GetInstance<DoSomethingElseWorker>(), new TimeSpan(0, 0, 5), true);
        _scheduler.AddTrigger(trigger2);
    }

    public override void Dispose()
    {
        _scheduler.Dispose();
        base.Dispose();
    }

“伪”调度程序

public interface IWorkScheduler : IDisposable
{
    void Start();
    Task Stop();
    void AddTrigger(WorkTrigger trigger);

}

public class WorkSchedulerSettings
{
    public readonly TimeSpan Interval;

    public WorkSchedulerSettings(TimeSpan interval)
    {
        Interval = interval;
    }
}

public class WorkScheduler
    : IWorkScheduler, IDisposable
{
    private readonly Timer _timer;
    private readonly WorkSchedulerSettings _settings;
    private readonly ILogger<WorkScheduler> _logger;
    private readonly List<Task> _tasks;
    private readonly List<WorkTrigger> _triggers;
    private readonly CancellationTokenSource _cancTokenSource;

    public WorkScheduler(WorkSchedulerSettings settings, ILogger<WorkScheduler> logger)
    {
        _settings = settings ?? throw new ArgumentNullException(nameof(settings));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _timer = new Timer(callback: _ => DoWork());
        _tasks = new List<Task>();
        _triggers = new List<WorkTrigger>();
        _cancTokenSource = new CancellationTokenSource();
    }

    public void Start()
    {
        _logger.LogInformation("Scheduler started");
        _timer.Change(dueTime: TimeSpan.Zero, period: _settings.Interval);
    }

    public async Task Stop()
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        _cancTokenSource.Cancel();
        await Task.WhenAll(_tasks);
        _tasks.Clear();
        _logger.LogInformation("Scheduler stopped");
    }

    public void AddTrigger(WorkTrigger trigger)
    {
        if (trigger == null) throw new ArgumentNullException(nameof(trigger));
        _triggers.Add(trigger);
    }

    private void DoWork()
    {
        foreach (var trigger in _triggers)
        {
            if (trigger.CanExecute(DateTime.Now))
            {
                var task = trigger
                            .Execute(_cancTokenSource.Token)
                            .ContinueWith(x => HandleError(x));
                _tasks.Add(task);
            }
        }
        _tasks.RemoveAll(x => x.IsCompleted);
    }

    private void HandleError(Task task)
    {
        if (task.IsFaulted)
            _logger.LogError(task.Exception.Message);
    }

    public void Dispose()
    {
        _timer?.Dispose();
        _cancTokenSource?.Dispose();
    }
}
4

0 回答 0