有什么方法可以将字符串传递给IHostedService定时后台任务?

时间:2019-08-17 08:30:51

标签: c# asp.net-core asp.net-core-mvc

我正在执行定时后台任务以发送电子邮件,并且我想在电子邮件中包含生成的链接。

当我通过控制器中的用户交互发送其他电子邮件时,我正在使用这种小方法来生成链接:

public string BuildUrl(string controller, string action, int id)
{
    Uri domain = new Uri(Request.GetDisplayUrl());
    return domain.Host + (domain.IsDefaultPort ? "" : ":" + domain.Port) +
        $@"/{controller}/{action}/{id}";
}

当然,后台任务对Http上下文一无所知,因此我需要替换链接的域部分,如下所示:

public string BuildUrl(string controller, string action, int id)
{
    return aStringPassedInFromSomewhere + $@"/{controller}/{action}/{id}";
}

我正在启动startup.cs ConfigureServices中的后台任务,如下所示:

services.AddHostedService<ProjectTaskNotifications>();

我本来是想从资源文件中获取域名,但是我也可以将其硬编码到任务方法中。

是否可以通过某种方式将这些信息动态传递给后台任务?

更多信息

这是整个后台任务:

internal class ProjectTaskNotifications : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;
    private readonly IServiceScopeFactory scopeFactory;
    private readonly IMapper auto;

    public ProjectTaskNotifications(
        ILogger<ProjectTaskNotifications> logger, 
        IServiceScopeFactory scopeFactory, 
        IMapper mapper)
    {
        _logger = logger;
        this.scopeFactory = scopeFactory;
        auto = mapper;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero,
            TimeSpan.FromSeconds(30));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Timed Background Service is working.");

        // Connect to the database and cycle through all unsent
        // notifications, checking if some of them are due to be sent:
        using (var scope = scopeFactory.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<MyDbContext>();

            List<ProjectTaskNotification> notifications = db.ProjectTaskNotifications
                .Include(t => t.Task)
                    .ThenInclude(o => o.TaskOwner)
                .Include(t => t.Task)
                    .ThenInclude(p => p.Project)
                        .ThenInclude(o => o.ProjectOwner)
                .Where(s => !s.IsSent).ToList();

            foreach (var notification in notifications)
            {
                if (DateTime.UtcNow > notification.Task.DueDate
                   .AddMinutes(-notification.TimeBefore.TotalMinutes))
                {
                    SendEmail(notification);
                    notification.Sent = DateTime.UtcNow;
                    notification.IsSent = true;
                }
            }
            db.UpdateRange(notifications);
            db.SaveChanges();
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

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

    public void SendEmail(ProjectTaskNotification notification)
    {   // Trimmed down for brevity

        // Key parts
        string toAddr = notification.Task.TaskOwner.Email1;
        BodyBuilder bodyBuilder = new BodyBuilder
        {
            HtmlBody = TaskInfo(auto.Map<ProjectTaskViewModel>(notification.Task))
        };

        return;
    }

    public string TaskInfo(ProjectTaskViewModel task)
    {   // Trimmed down for brevity
        return $@"<p>{BuildUrl("ProjectTasks", "Edit", task.Id)}</p>";
    }

    public string BuildUrl(string controller, string action, int id)
    {   
        // This is where I need the domain name sent in from somewhere:
        return "domain:port" + $@"/{controller}/{action}/{id}";
    }
}

1 个答案:

答案 0 :(得分:0)

您可以通过构造函数将任何对象传递给IHostedService提供者。

public ProjectTaskNotifications(IUrlPrefixProvider provider)
{
    _urlPrefixProvider = urlPrefixProvider
}

private string BuildUrl(<Your args>)
{
    var prefix = _urlPrefixProvider.GetPrefix(<args>);
    ....
}

在startup.cs中,您可以拥有

services.AddSingleton<IUrlPrefixProvider, MyUrlPrefixProvider>()
services.AddHostedService<ProjectTaskNotifications>();

并让依赖注入负责其余的工作。