c# - 在 ASP.NET Core 中异步保存文件导致 DbContext 异常

标签 c# asp.net asynchronous asp.net-core entity-framework-6

我有一个为客户保存文档信息的应用程序。我正在尝试添加功能以允许用户上传 PDF 并将它们保存到磁盘。我正在使用找到的推荐代码 herehere .

当代码运行时,一切看起来都很好——文档实体被保存到数据库中,上传的文件被保存到磁盘中。但是,我偶尔会抛出异常——比如 System.ObjectDisposedException(“无法访问已处置的对象”),有时 DbUpdate 异常表示引用为空,等等......我可以重现问题,但不是每次都是 100%,也不是每次都出现相同的异常。

我怀疑这是由于在保存文件时使用 CopyToAsync 造成的。我对异步代码不是很有经验,我可能会做一些明显错误的事情。如果我更改方法以改为使用同步 CopyTo,似乎可以解决问题。我试图理解为什么会这样。

我正在使用 AutoFac 注入(inject)我的存储库和 DbContext。这是 Controller 调用的服务方法的代码:

public async Task<int> SaveDocument(DocumentDetailDto dto, string user, string webRoot)
{
     documentToSave = new Document();

     // Code not shown that maps dto to new document and adds it to context

     if (dto.FileUpload != null && dto.FileUpload.Length > 0)
     {
          var fileName = $"{dto.CustomerId}-{dto.DocumentTypeId}-{DateTime.Now.Ticks}.pdf";

          var filePath = Path.Combine(webRoot, "uploads");

          using (var fileStream = new FileStream(Path.Combine(filePath, fileName), FileMode.Create))
          {
               await dto.FileUpload.CopyToAsync(fileStream);
          }
     }

     _repo.Save(user);

     return documentToSave.Id;
}

你看到这个设置有什么明显的错误吗?在对上下文调用 save 之前将 async 与 FileStream 一起使用时,我需要做些什么特别的事情吗?我仍在尝试调试错误,但问题似乎是打开的 FileStream 和尝试写入数据库的 DbContext 之间存在某种冲突。欢迎尝试任何想法!

编辑添加一些额外的代码:

以下是我在 Startup.cs 中注册 DbContext 的方式:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
     services.AddMvc();

     // Add DbContext
     var connection = Configuration.GetConnectionString("DefaultConnection");

     services.AddDbContext<DocContext>(
                options => options.UseSqlServer(connection, b => b.MigrationsAssembly("InfrastructureLayer")));

      // Add repository
      services.AddScoped<IRepository, EntityFrameworkRepository<DocContext>>();

      services.AddTransient<IResolveUserService, ResolveUserService>();

      // Autofac setup
      var containerBuilder = new ContainerBuilder();
      containerBuilder.RegisterModule<ServiceLayer.AutofacModule>();
      containerBuilder.Populate(services);
      var container = containerBuilder.Build();
      return new AutofacServiceProvider(container);
 }

这里是 repo 中的 Save 方法:

public virtual void Save(string user = "")
{
     var modifiedEntries = Context.ChangeTracker.Entries<IEntity>()
          .Where(x => x.State == EntityState.Modified)
          .Select(x => x.Entity)
          .ToList();

     foreach (var entity in modifiedEntries)
     {
          entity.ModifiedDate = DateTime.UtcNow;
          entity.ModifiedBy = user;
     }

     var newEntries = Context.ChangeTracker.Entries<IEntity>()
          .Where(x => x.State == EntityState.Added)
          .Select(x => x.Entity)
          .ToList();

     foreach (var entity in newEntries)
     {
          entity.CreatedDate = DateTime.UtcNow;
          entity.CreatedBy = user;
     }

     Context.SaveChanges();
}

下面是如何从 Controller 调用 SaveDocument 方法:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Save(DocumentDetailDto dto, [FromServices]IResolveUserService userService, [FromServices]IHostingEnvironment environment)
{
     _service.SaveDocument(dto, userService.GetUser(), environment.WebRootPath);

     return RedirectToAction("Detail", "Customers", new { id = dto.CustomerId });
}

谢谢!

最佳答案

您应该等待 _service.SaveDocument 完成。目前您启动它并且不等待它的结果。相反,您向用户发送成功的响应,处理请求,可以随时处理使用的资源。

将您的 Controller 操作更改为:

public async Task<IActionResult> Save(...
{
     await _service.SaveDocument(...

     return RedirectToAction(...
}

关于c# - 在 ASP.NET Core 中异步保存文件导致 DbContext 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44875630/

相关文章:

c# - 有没有办法知道是否正在等待任务?

c# - 在父 View 中显示子项的验证 asp.net mvc 3

c# - Oracle数据访问版本问题

c# - 有没有办法将事件处理程序附加到 C# 中正在运行的进程列表?

c# - 在 C# 中使用 json 对象

ASP.net:有谁知道如何实现类似youtube 搜索框的效果?

c# - 如何在不完全阻塞线程的情况下将线程池中的线程暂停执行一定时间?

c# - 并行运行两个异步任务并在 .NET 4.5 中收集结果

c# - 替换 C# 字符串中的数字

c# - 如何配置 AutoMapper 以全局忽略所有具有不可访问 Setter 的属性(私有(private)或 protected )?