从实体框架加载列表而不让控制器等待
本文关键字:控制器 等待 列表 实体 框架 加载 | 更新日期: 2023-09-27 18:18:32
我想在我的Web应用程序的开始加载一组列表,以便以后使用它们。这些列表是静态的,使用实体框架作为ORM从数据库中读取。我们的想法是在开始时加载列表(在登录后的主页上),并在整个de App中使用它们。但我不希望主页等待列表完成加载。我已经尝试了几个替代方案,但没有一个工作(或同步或有错误)。
1。第一次尝试:调用ToListAsync()并等待ToListAsync(Throw Exception from EF)
列表有两个版本,一个是异步的,另一个是同步的:
private static Task<List<EMPRESA>> ListaEmpresasAsync;
public static List<EMPRESA> ListaEmpresas
我已经定义了一个函数,从EF
上的存储库生成列表。public async static Task<List<T>> GenerateAsyncListFromRepository(IGenericRepositoryBlockable<T> repository)
{
IQueryable<T> queryAsync = repository.GetAllActive();
return await queryAsync.ToListAsync();
}
和其他函数检查异步调用的结果:
public static List<T> ForceToLoadAsyncList(Task<List<T>> task)
{
task.Wait();
return task.Result;
}
异步加载列表:
ListaEmpresasAsync = TaskManager<EMPRESA>.GenerateAsynListFromRepository((IEmpresaRepositorio)DIResolver.GetService(typeof(IEmpresaRepositorio)));
当需要List时,我强制加载:
public static List<EMPRESA> ListaEmpresas
{
get
{
return TaskManager<EMPRESA>.ForceToLoadAsyncList(ListaEmpresasAsync);
}
}
这个初始方法抛出以下错误:
在前一个异步操作完成之前,在此上下文中开始了第二个操作
2。第二:使用ToList()并等待任务结束。run()(空枚举的问题)
然后我测试使用ToList()代替ToListAsync:return await Task.Run(() => { return queryAsync.ToList(); });
我也不工作。
3。第三:使用ToList()并等待GenerationList, Force只返回List(行为类似于同步方法)。控制器正在等待所有列表加载)
按照这种方法,我将函数的签名更改为返回list:
return queryAsync.ToList();
并等待加载进程
ListaEmpresasAsync = await TaskManager<EMPRESA>.GenerateAsynListFromRepository((IEmpresaRepositorio)DIResolver.GetService(typeof(IEmpresaRepositorio)));
但是这与同步过程的工作原理相似,这意味着在主页上加载时间非常长。
我知道在EF上,每个上下文只允许一个异步调用。我只是想把所有这些加载进程放在后台,即使他们运行同步,当列表需要检查任务的结果。
任何想法?
只是为了澄清,Yuval Itzchakov提出的解决方案应该在DbContext不被所有加载列表调用共享时工作,但在我的场景中,它抛出了与实体框架上多个异步调用相关的错误。
您的代码有几处错误。首先,您需要知道,即使使用async-await
进行异步调用,在等待的操作返回之前,请求也不会完成。这一点很重要,因为如果你需要的是Fire and Forget样式的操作,这是行不通的。
如果您想要异步执行(而不是触发并忘记),请执行以下操作:
public static List<EMPRESA> ListaEmpresas
public static Task<List<T>> GenerateAsyncListFromRepository(IGenericRepositoryBlockable<T> repository)
{
return repository.GetAllActive().ToListAsync();
}
然后像这样调用它:
ListaEmpresas = await TaskManager<EMPRESA>.GenerateAsyncListFromRepository((IEmpresaRepositorio)DIResolver.GetService(typeof(IEmpresaRepositorio)));
创建两个列表并使用Task.Wait
是无用的,你没有强迫任何其他的线程等待async方法返回,这意味着它是同步运行的。
如果您想要的是,请注意以下内容:
在ASP中使用Task.Run
. NET是危险的,因为它不向asp.net注册排队的工作。. NET线程池,并且暴露于IIS回收,这可能导致您的后台工作意外终止。相反,如果你使用的是。net 4.5.2,你可以使用HostingEnvironment.QueueBackgroundWorkItem
来为你注册队列任务。如果没有,看看Stephan Clearys的BackgroundTaskManager
您可以使用EF执行此并行任务,但是在并行线程中使用1 DBContext的意图将以失败告终。DBContext的实例成员不是线程安全的!DBContext信息
你可以使用一个简单的模式来跨越线程
- 线程n + 1
- 线程N + 2
- …
等待结果。
每个线程必须使用自己的上下文。对于给定的搜索字符串,我使用此模式一次搜索许多对象类型。但是要有一个等待的整体结果是设计的一部分。我不确定这是否符合你的要求。
并行任务演示
如果您有非易失性数据集,您可以让IIS缓存结果。我在非易失性内容的控制器方法上使用这种方法。参见OutputCache注释。
[OutputCache(Duration = int.MaxValue, VaryByParam = "id", Location = OutputCacheLocation.ServerAndClient)]