【问题标题】:Sending emails using Hangfire on asp.net core 2.1在 asp.net core 2.1 上使用 Hangfire 发送电子邮件
【发布时间】:2018-10-24 01:46:28
【问题描述】:

我已正确设置 Hangfire。我可以从邮递员运行以下代码:

 [HttpPost("appointments/new")]
 public async Task<IActionResult> SendMailMinutely()
 {
     RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!") Cron.Minutely);
     await Task.CompletedTask;
     return Ok();
 }

当我达到这个 API 点时,它工作正常。 我想做的是使用上面相同的代码运行我的电子邮件控制器。我修改的SchedulersController代码是:

[Route("/api/[controller]")]
public class SchedulersController : Controller
{
    private readonly MailsController mail;
    public SchedulersController(MailsController mail)
    {
        this.mail = mail;
    }

    [HttpPost("appointments/new")]
    public async Task<IActionResult> SendMailMinutely()
    {
        RecurringJob.AddOrUpdate(() => mail.SendMail(), Cron.Minutely);
        await Task.CompletedTask;
        return Ok();
    }
}

我的MailsController 是:

[HttpPost("appointments/new")]
public async Task<IActionResult> SendMail()
 {
    var message = new MimeMessage ();
    message.From.Add (new MailboxAddress ("Test", "test@test.com"));
    message.To.Add (new MailboxAddress ("Testing", "test@test123.com"));
    message.Subject = "How you doin'?";

    message.Body = new TextPart ("plain") {
        Text = @"Hey Chandler,
                I just wanted to let you know that Monica and I were going to go play some paintball, you in?
                -- Joey"
    };

     using (var client = new SmtpClient ()) {
     client.ServerCertificateValidationCallback = (s,c,h,e) => true;

    client.Connect ("smtp.test.edu", 25, false);

    await client.SendAsync (message);
            client.Disconnect (true);
        }


        return Ok();
    }

我收到的错误信息是:

执行请求时发生未处理的异常。 System.InvalidOperationException:尝试激活“Restore.API.Controllers.SchedulersController”时无法解析“Restore.API.Controllers.MailsController”类型的服务

如何使用我的MailsController 来安排电子邮件以使用 Hangfire 发送? 任何帮助将不胜感激。

【问题讨论】:

  • 如果您只是要等待完成的任务,为什么要将您的方法标记为异步?为什么不直接返回 IActionResult 而不是 Task&lt;IActionResult&gt;
  • 因为它必须是async,因为我有多个请求。有些请求需要一些时间。此邮件请求不应等待其他请求完成。
  • 为什么不把你的邮件发送逻辑封装到一个单独的服务中呢?为什么将其直接放在控制器的操作方法中?它不属于那里。
  • 我看到你在 SchedulersController 中调用的唯一异步代码是 await Task.CompletedTask;
  • 我建议将 SendMail 中的逻辑移动到一个单独的类中,一个将被注入到两个控制器中的 EmailService。将一个控制器注入另一个控制器是一种反模式。同时,请参阅以下答案以了解如何解决您的问题。 stackoverflow.com/a/49372654/10296119

标签: c# .net-core hangfire


【解决方案1】:

这样做的正确方法是将您的邮件发送逻辑移动到一个单独的服务中。

// We need an interface so we can test your code from unit tests without actually emailing people
public interface IEmailService
{
    async Task SendMail();
}

public EmailService : IEmailService
{
    public async Task SendMail()
    {
        // Perform the email sending here
    }
}

[Route("/api/[controller]")]
public class SchedulersController : Controller
{
    [HttpPost("appointments/new")]
    public IActionResult SendMailMinutely()
    {
        RecurringJob.AddOrUpdate<IEmailService>(service => service.SendMail(), Cron.Minutely);
        return Ok();
    }
}

您需要确保已为 IoC as described in their documentation 配置了 Hangfire,以便它可以解析 IEmailService。

【讨论】:

  • 你是对的。我上面描述的方式完全违背了模式。它现在按预期工作。感谢您的帮助!
  • 我在这里有一个问题,一般来说可以给出一个答案:假设他不会创建 Hangfire 作业,而只是使用 SenMail 方法而不等待它......不是吗比创造工作还快?
  • @Eru 当然会更快。但是,如果发送该电子邮件失败怎么办?如果邮件服务器暂时关闭,或者您的应用程序和邮件服务器之间存在导致 SendMail 失败的其他网络故障怎么办。如果您不等待任务,那么您将如何收到异常通知?你不会的。在后台作业中处理它是有意义的,因为您需要它是持久的(如果它失败,重试 Hangfire 作业很简单)并且您也不一定要等待整个 SMTP 握手完成,因为它可能不必要减慢请求处理速度。
  • @Eru 在不等待的情况下调用异步方法几乎不是一个好主意,因为您将没有机会捕获任何抛出的异常。例外只是迷路了。虽然有人可能会认为在简单的情况下,Hangfire 对于发送电子邮件来说太过分了,但如果你想争辩说不等待异步方法调用是正确的做法,那么你真的没有立足之地。跨度>
  • @Eru 请参阅 this Fiddle 演示如何在不等待异步方法调用时丢失异常。
【解决方案2】:

这与核心框架中的依赖注入有关。您需要确保在您的 startup.cs 中的 ConfigureService 方法下注册您的依赖项。

但不确定这是否是好的做法。

对于控制器,您可以使用: services.AddMvc().AddControllersAsServices();

【讨论】:

  • MailsController 是一个控制器,而不是接口,所以我可以在启动类中注册。它使用他们已经注册的服务。
猜你喜欢
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 2012-01-10
  • 1970-01-01
相关资源
最近更新 更多