我正在尝试创建一个控制台应用程序,该应用程序使用 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();
}
}