在MVC 5的服务层使用异步方法?

时间:2014-05-16 12:50:42

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

我正在开发一个ASP.NET MVC 5应用程序。我一直在阅读一些问题here,这些问题建议不要使用我想要的行为类型。

我想达到的高水平 -

MVC Controller - 在服务层调用方法,然后继续执行控制器中的下一行代码,因为不需要返回任何内容。

服务层中的方法 - 我想调用一些具有Async方法的外部Web服务,所以我希望这些方法能够运行,然后在返回时将数据写入数据库。

这样的事情是否可以实现或不是最佳方法?

将此虚拟出来并测试我在控制器上有以下原理:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult TestAsync()
    {
        _myService.TestAsync();

        return RedirectToAction("Summary");
    }

在_myService,该方法如下所示:

    public async Task TestAsync()
    {
        await Task.Delay(10000);

        var test = "Testing";

       _testRepository.Add(test);
    }

我希望这个TestAsync方法等待10秒然后我可以检查数据库,并且会添加测试值。但是这不起作用 - 在按下按钮后,在UI上,页面转到摘要视图,并且命中了等待Task.Delay断点,但下一行永远不会执行。这种方法有什么不对吗? TestAsync方法应该类似于:

    public void TestAsync()
    {
       //Call another private async method here in the class that does the task delay
       //which would be similar to calling the actual Async External Web Service methods
        var test = "Testing";

       _testRepository.Add(test);
    }

1 个答案:

答案 0 :(得分:3)

  

我一直在阅读一些问题,建议不要使用我想要的行为类型。

那是因为它很危险。 ASP.NET确定在没有活动请求时卸载AppDomain是安全的,因此如果您在仍有工作要做的时候从控制器操作返回,ASP.NET将不会意识到这项工作。

最佳解决方案是使用单独的后端(例如Azure WebJob)设置可靠的队列(例如Azure队列),以便以可靠的方式处理该队列。这是正确的解决方案,但很多人只是因为它很复杂而不会这样做。

如果解决方案中有SQL Server或Redis数据库,请考虑Hangfire。 Hangfire将数据库用作可靠队列,并在ASP.NET应用程序旁边执行其后端。

如果您想要危险地生活,至少应该使用HostingEnvironment.QueueBackgroundWorkItem,这将告知ASP.NET您的应用程序在请求之外所做的工作。

  

这种方法有什么不对吗?

是; _myService.TestAsync正在尝试在请求上下文中恢复已完成的请求。