在执行任务时放置数据库对象

时间:2017-11-07 15:29:16

标签: asynchronous callback asp.net-web-api2 asp.net-core-2.0

这是我正在努力的流程,

  • 拨打网络电话api
  • Web api将立即返回确定
  • Web api将在后台完成一些工作

这是我迄今取得的成就,

 [Route("api/[controller]")]
    public class PremController : Controller
    {
        private readonly myDbContext _context;

        public PremController(myDbContext context)
        {
            _context = context;
        }

        [HttpGet]
        public HttpResponseMessage Get()
        {
            Task.Factory.StartNew(() => DoWork());
            return new HttpResponseMessage(HttpStatusCode.Accepted);
        }

        private void DoWork()
        {
            Delay(2000).ContinueWith(_ => GetProducts());

        }

        private void GetProducts()
        {
            var productUrls = _context.Products.Select(p => p.Url).ToArrayAsync();
        }

        static Task Delay(int milliseconds)
        {
            var tcs = new TaskCompletionSource<object>();
            new Timer(_ => tcs.SetResult(null)).Change(milliseconds, -1);
            return tcs.Task;
        }
    }

但是我收到的错误是myDbContext在新创建的任务完成之前被处理掉了。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

这是因为您创建了即发即弃任务,没有同步上下文。如果您直接等待DoWork(),则会保留同步上下文,从而确保不会处理上下文。更具体地说,您创建的任务在上下文的生命周期之外运行,由DI容器定义(很可能是请求范围的)。请求一旦完成,就会释放上下文,从而终止您的任务在请求之外尝试完成的工作。

长短不一,这是一个糟糕的设计,原因有很多。如果你需要做&#34;背景&#34;工作,应该卸载到一个完全不同的过程,而不仅仅是一个新的线程。在那里运行的代码应该负责维护自己的上下文,而不受Web应用程序中发生的事情的影响。 Task.Run / Task.Factory.StartNew对于Web应用程序来说非常糟糕,因为它有一个有限的线程池,并且从该池启动新线程会降低服务器的总负载容量。

如果您发现自己想要在Web应用程序中启动新主题,请不要这样做。这几乎是普遍错误的。相反,请使用后台处理解决方案(如Hangfire或类似方法)安排工作。