执行任务时释放数据库对象

Database object is disposed while executing a task

这是我正在努力的流程,

这是我到目前为止所取得的成就,

 [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 已被处理掉。我该如何解决这个问题?

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

总而言之,由于多种原因,这是一个糟糕的设计。如果您需要做 "background" 工作,那应该卸载到一个完全不同的进程,而不仅仅是一个新线程。在那里运行的代码应该负责维护自己的上下文,不受网络应用程序中发生的事情的影响。 Task.Run/Task.Factory.StartNew 对于 Web 应用程序来说非常糟糕,因为线程池是有限的,并且从该池启动新线程会降低服务器的总负载能力。

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