我有一个.netcore webAPI控制器,他的功能之一是上传文件。
因此,当用户上传文件时,会有一个任务来调用 AI 网络服务。
根据 Web 服务的结果,将对实体应用一些更改。
[HttpPost("upload/{id}")]
public async Task<string> UploadFile(int id)
{
//upload file
Task.Run(() => callForAI(id,names,pathExported));
return "ok";
}
public async Task callForAI(int id,List<string>names,string path)
{
User user= await _context.User.FindAsync(id);//here comes the exception
//some changes to make
_context.Entry(user).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
通过这样做,异常会出现:
引发的异常:"System.ObjectDisposedException" Microsoft.EntityFrameworkCore.dll
你在这里使用async/await
是错误的。无需在新线程上调用callForAI
。在单独的线程上运行它意味着UpLoadFile
很有可能在线程完成之前返回,此时上下文正在被销毁。
尝试像这样重写它:
[HttpPost("upload/{id}")]
public async Task<string> UploadFile(int id)
{
//upload file
await callForAI(id, names, pathExported);
return "ok";
}
public async Task callForAI(int id, List<string>names, string path)
{
User user= await _context.User.FindAsync(id);
//some changes to make
_context.Entry(user).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
此外,您已将UploadFile
标记为async
方法,但您没有await
任何内容,因此您应该看到编译器警告告诉您这一点。当你收到这些警告时,这是一个明显的迹象,表明你做错async/await
。
"即发即弃"几乎从来都不是正确的解决方案。"即发即弃"是指:
- 您不在乎附加代码是否有异常。
- 您不在乎其他代码是否完成。
- 您不在乎其他代码是否运行。
"即发即弃"的用例非常小。从本质上讲,它只对"更新此分布式缓存条目"之类的事情有用,在这些事情中,操作是否完成并没有太大区别。在您的额外工作中使用数据库是一个强有力的指标,表明"即发即弃"是针对您的问题的不正确解决方案。
如果不希望用户必须等待操作完成,更合适的设计是让操作将工作保存到持久队列,然后让单独的后台辅助角色从该队列中读取并执行实际工作。
但是,如果您坚持使用有问题的"即发即弃"模式,那么您只需要记住"即发即弃"工作是在请求上下文之外执行的。因此,不能使用具有作用域生存期注入控制器的任何内容。您的代码需要创建自己的数据库上下文。