c# - 进行异步工作以返回快速响应的最佳方法

标签 c# asp.net .net asp.net-web-api async-await

我正在 ASP.NET 上开发 REST API。我想知道哪个是独立于将响应发送给客户端进行后台工作的最佳方式。基本上,我有一个 PUT 方法,我必须发送几封电子邮件。假设它们是 10 封电子邮件。我将恢复所有方法以使一切更清楚:

我尝试了以下方法,两种方式都在发送电子邮件后发送了回复,并且它们花费了相同的时间:

方式一:

    [EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
    public async Task<HttpResponseMessage> Put(string id, [FromBody]InformeModel informe)
    {
        if (CookieManager.ValidarCookie(Request.Headers.GetCookies("mb-session").FirstOrDefault()) == EstadoCookie.VALIDA)
        {
            await SendMails()

            return Request.CreateResponse(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.Unauthorized);
        }
    }


    private async Task SendMails()
    {
        await Task.Run(() => {
            foreach (string m in mails)
            {
                Mail mail = new Mail("test@test.com", 25, "test@test.com.ar", "myPass");
                mail.SendMailHTML(m, "Email Title", "This is the Email");
            }
        });
    }

方式二:

    // PUT: api/Informes/5
    [EnableCors(origins: "*", headers: "*", methods: "*", SupportsCredentials = true)]
    public HttpResponseMessage Put(string id, [FromBody]InformeModel informe)
    {
        if (CookieManager.ValidarCookie(Request.Headers.GetCookies("mb-session").FirstOrDefault()) == EstadoCookie.VALIDA)
        {
            SendMails()

            return Request.CreateResponse(HttpStatusCode.OK);
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.Unauthorized);
        }
    }


    private async void SendMails()
    {
        await Task.Run(() => {
            foreach (string m in mails)
            {
                Mail mail = new Mail("test@test.com", 25, "test@test.com.ar", "myPass");
                mail.SendMailHTML(m, "Email Title", "This is the Email");
            }
        });
    }

为了向客户端发送响应而不必等待所有电子邮件都已发送,哪种方法最好?。我必须使用 ThreadPool 吗?

最佳答案

我会在解耦方面更进一步,并使用类似于域事件的通用事件。

如果 Controller 可以完成其工作并返回响应,无论电子邮件是否已发送,这强烈表明发送电子邮件超出了 Controller 的责任范围。 (特别是对于电子邮件, Controller 永远无法确定电子邮件是否已发送。)

在那种情况下,我会使用某种事件总线。一些示例使用静态实例,或者它可以是您注入(inject)到 Controller 中的东西。

然后, Controller 不发送电子邮件,而是引发一个事件,例如

_eventBus.Raise(new SomethingHappenedEvent(argsThatIncludeRelevantInfo args));

然后你有一个事件处理程序(你甚至可以有多个),一个事件处理程序发送电子邮件,包括使其异步并处理任何异常。

这使得单元测试更加容易。您不需要测试您的 Controller 是否已发送电子邮件。您可以模拟事件总线并测试是否引发了事件。然后可以单独测试事件处理程序。

Here is an article on domain events有一段时间被引用了很多。我确信那里有更多最新信息。

有关这些事件的很多信息都在域驱动开发的上下文中,但无论您是否在进行 DDD,这些原则和机制都适用。您的类与其方法产生的其他事物脱钩,但它本身不应该知道或关心这些事物 - 例如返回响应的 Controller ,以及发送电子邮件的副作用。

Here's an event bus implementation我前一段时间做过。我不认为我包括了异步处理,但是当你想要即发即弃时,这可能有意义。这是我应该重新审视的事情。

如评论中所述,即发即弃并不意味着事件的结果微不足道。为了确保事情发生,事件处理程序将请求放入队列而不是自己完成工作可能是有意义的。这使它更持久,因此您可以确保放入队列的任何内容都得到处理。

关于c# - 进行异步工作以返回快速响应的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48585379/

相关文章:

c# - 数据表填充对象

c# - 命令行自动化——期待等效

c# - C# HTTP PUT 请求代码的问题

.net - 使用客户端凭据通过 SSL 的 HttpWebRequest

.net - SSL channel 连接的 MQ 上出现 2538 错误

c# - MVVM View 模型异步数据初始化

c# - WPF根据条件隐藏数据网格中的行

asp.net - 基于 ASP.NET Identity 的两个 ASP.NET 应用程序之间的通用身份验证

asp.net - 当客户端cookie滑动时刷新IdentityServer cookie

c# - 仅捕获特定的 HttpException