【问题标题】:Calling multiple methods asynchronously in single method in ASP.NET MVC Controller在 ASP.NET MVC 控制器的单个方法中异步调用多个方法
【发布时间】:2019-09-30 10:42:12
【问题描述】:

ASP.NET MVC 应用程序中,我的Service.cs 中有两个方法,如下所示(为简洁起见,方法已简化),我想使用async 异步调用这些方法。但是在从Controller 调用第一个方法(Save)之后,我也想返回此操作的结果,而无需等待第二种方法(SendEmail)。但在这种情况下,我必须返回结果并且不知道如何使用ASP.NET MVC async 来管理它。你能给这个场景一些建议吗?我想我必须在所有链方法中使用async,但不确定如何构建这个链。任何帮助,将不胜感激。

控制器:

public JsonResult AddRecord() {
var result = service.Save();
//I need to return the result after record is added (without waiting the email sent)

service.SendEmail();    
}

服务:

public MyEntity Save() {
    //
}


public void SendEmail() {
    //
}

【问题讨论】:

  • 等待Task.Run(() => { service.SendEmail(); });?
  • 您能否使用上面的代码发布您的答案?在此先感谢...
  • @nalnpir 已经这样做了。

标签: c# asp.net-mvc asynchronous asp.net-mvc-5 async-await


【解决方案1】:

听起来您想从不同的线程调用 SendMail()。 尝试查看有助于后台作业的 Hangfire

【讨论】:

  • 谢谢,但对于这种情况,我不想使用已经用于特定其他情况的 Hangfire...
【解决方案2】:

我能想到的场景。使用匿名任务

public JsonResult AddRecord() {
var result = service.Save();
//I need to return the result after record is added (without waiting the email sent)

Task.Run(() => service.SendEmail()); 
return result;
}

第二种情况是使您的 SendEmail 方法异步,这样它几乎与任务相同,通常它说使用异步方法不是一个好主意,但我认为这种特殊情况符合标准

【讨论】:

  • 您在 Task.Run 之前忘记了 await 关键字
  • 不,我没有,他不想等待任务的结果,而且你不能在非异步方法或任务中等待
  • 是的,我错了,当然。这个方法应该返回一个结果,当然你是对的。
  • 感谢您的回复。我是否也应该像亚历山大的回答那样在服务中使方法异步?哪一种更适合我的情况?这个还是亚历山大的帖子?提前致谢。
  • 老实说,我没有看到使保存方法异步的好处,因为您声明您希望在返回之前完成,而且您的方法中没有任何其他操作,您通常希望使用异步当您有一些需要很长时间才能运行的东西并且您不想在此过程中冻结您的 ui 时的模式,因此在这种情况下您不想等待电子邮件,但您确实需要等待保存结束后再去进一步。通常我的经验法则是不要解决你没有的问题,并且保存方法非常好
【解决方案3】:

一种方法是更改​​SendEmail 的行为及其名称,使其实际上不发送电子邮件。它添加了向队列发送电子邮件的请求。您的方法调用可能如下所示:

service.QueueEmail(someData);

这没有必要是异步的(也没有好处),因为您所做的只是向队列中添加一些内容。一个单独的进程从队列中读取并发送电子邮件。

这将使您的服务更加专注。知道如何发送电子邮件的更详细的代码将存在于其他地方。然后,该代码可以更有效地处理这种复杂性。例如,它可以合并重试逻辑。由于您的应用程序中有其他发送电子邮件的进程,因此它们可以重用该进程。

【讨论】:

  • 您能否像亚历山大一样在您的答案中包含我上面的代码?另一方面,对于这个扫描仪使用 Task.Run() 作为 Alexandr 的答案怎么样?非常感谢。
  • 我的解决方案不太适合。事实上,它甚至算不上一个“解决方案”。单独设计您的电子邮件解决方案更像是一个建议。如果service 发送电子邮件,则解决方案将是次优的。如果您使用Task.Run(),那么如果发送电子邮件引发异常会发生什么?就是发不出去。这就是为什么我会从允许您添加请求以将电子邮件发送到队列的东西开始。有了这个,这门课就完成了。然后分别解决如何发送队列中的电子邮件请求的问题。但我不会尝试同时解决这两个问题。
  • 感谢您的回复。这正是我非常困惑的地方,因为我需要在添加新记录之后返回响应。另一方面,当然认为发送电子邮件时出现问题怎么办。但是在这种情况下,如果没有关于添加记录的错误,用户已经关闭了表单,并且我只能通过将异常写入数据库来监控不同页面上的电子邮件状态,以防万一。那么,在这种情况下有更好的方法吗?在此先感谢...
  • 我通常有一个单独的流程来发送电子邮件,例如我向其发送请求的服务。发送该请求后,我的流程可以继续并假设电子邮件已发送。 (它不能做太多其他事情。)该过程通常不是 Web 应用程序的一部分。它只是不断监控自己的队列并发送电子邮件。这也最大限度地减少了存储 SMTP 配置的位置的数量。无论您如何解决电子邮件问题,这都会将其移出无法有效处理发送电子邮件的类。
【解决方案4】:

您可以尝试这样做:

public class Service
{
    public Task<MyEntity> SaveAsync()
    {
        return Task.Run(() => Save());
    }

    public MyEntity Save()
    {
        Thread.Sleep(2000);
        var entity = new MyEntity();
        return entity;
    }

    public Task SendEmailAsync()
    {
        return Task.Run(() => SendEmail());
    }

    public void SendEmail()
    {
        Thread.Sleep(2000);
        Console.WriteLine("The message is sent");
    }
}

并创建控制器或其他服务,一些这样的:

public class SomeController
{
    private readonly Service _service;

    public SomeController()
    {
        _service = new Service();
    }

    public MyEntity AddRecord()
    {
        var resultTask = _service.SaveAsync();
        _service.SendEmailAsync();

        return resultTask.Result;
    }

    public async Task<MyEntity> AddRecord2()
    {
        var resultTask = _service.SaveAsync();

        _service.SendEmailAsync();

        //var result = await resultTask;
        //return result;

        return await resultTask;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    • 2015-10-22
    • 2011-11-04
    • 1970-01-01
    • 2017-05-19
    • 2016-12-26
    相关资源
    最近更新 更多