实现功能:
1,通过Magicodes.IE(不错的文件导入及导出组件,使用近5年了),导出10W+的数据;
2,前端VUE调用导出大数据接口,报Http499超时,考虑后端用HangFire后台作业来执行具体任务,执行完成,把执行的结果返回给前端;
实现动态导出功能的服务代码如下:
public class OutputService : ITransientDependency { private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IBlobContainer<BlobCommonFileContainer> _fileContainer; public OutputService( IUnitOfWorkManager unitOfWorkManager, IBlobContainer<BlobCommonFileContainer> fileContainer) { _fileContainer = fileContainer; _unitOfWorkManager = unitOfWorkManager; } public async Task Export<T>(Guid Id, string fileName, List<T> list) where T : class, new() { using (var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true)) { IExporter _exporter = new ExcelExporter();//导出Excel var result = await _exporter.ExportAsByteArray<T>(list); result.ShouldNotBeNull(); await _fileContainer.SaveAsync(fileName, result).ConfigureAwait(false); await uow.CompleteAsync(); } } }
调用方式一:
此处的坑:
1,异常吞没:如果 SaveAsync
方法内部有异常处理(例如 try-catch
块),并且异常被吞没(没有被记录或重新抛出),这可能导致方法在没有明显错误的情况下失败
2,后显示加上try-catch
块,报出了异常:
System.ObjectDisposedException HResult=0x80131622 Message=Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed. Source=Autofac StackTrace: 在 Autofac.Core.Lifetime.LifetimeScope.ThrowDisposedException() 在 Autofac.Core.Lifetime\LifetimeScope.cs 中: 第 314 行 在 Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(ResolveRequest request) 在 Autofac.Core.Lifetime\LifetimeScope.cs 中: 第 177 行 在 Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) 在 Autofac\ResolutionExtensions.cs 中: 第 414 行 在 Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) 在 Autofac\ResolutionExtensions.cs 中: 第 306 行 在 Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) 在 Volo.Abp.BlobStoring.BlobNormalizeNamingService.NormalizeNaming(BlobContainerConfiguration configuration, String containerName, String blobName) 在 Volo.Abp.BlobStoring.BlobContainer.<SaveAsync>d__22.MoveNext() 在 Volo.Abp.BlobStoring.BlobContainerExtensions.<SaveAsync>d__0.MoveNext()
大体意思:
System.ObjectDisposedException
错误表明尝试从已经被释放(disposed)的 LifetimeScope
解析服务时出现了问题。在这种情况下,错误消息指出 Autofac 容器的一个作用域(或其父作用域)已经被释放,因此无法从中解析服务或创建嵌套的作用域。
以下是可能导致此异常的原因和解决方法:
-
作用域释放:
- 确保你没有在完成请求处理之前释放了 Autofac 的作用域。在 ASP.NET Core 中,作用域通常与 HTTP 请求生命周期相关联。
-
依赖项注入问题:
- 如果在
BlobContainer
或相关服务中使用了依赖注入,确保这些服务在作用域释放之前被正确解析。
- 如果在
-
异步方法和作用域:
- 如果
SaveAsync
或其他异步方法在作用域被释放后仍在执行,它们可能会尝试解析服务,从而导致此异常。
- 如果
-
使用
IAsyncLifetime
或IDisposable
:- 如果你的服务实现了
IAsyncLifetime
接口,确保在DisposeAsync
方法中正确处理了作用域。如果实现了IDisposable
,确保在对象被释放前正确处理资源。
- 如果你的服务实现了
-
检查
BlobNormalizeNamingService
和BlobContainer
:- 检查
BlobNormalizeNamingService.NormalizeNaming
和BlobContainer.SaveAsync
方法的实现,确保它们不会在作用域释放后执行。
- 检查
解决问题,重新加上生命周期作用域,代码如下:
public async Task<string> ExportFile(Guid id, List<string> exportName, List<CustomCondition> p_list) { id = Guid.NewGuid(); using (var scope = _serviceProvider.CreateScope()) { var service = scope.ServiceProvider.GetRequiredService<OutputService>(); var _first = exportName.FirstOrDefault(); string sql = "SELECT id,ParentItemCode,ParentItemDesc,ChildItemCode,ChildItemDesc,Qty,ChildItemUom FROM [dbo].[hx_bom]"; var _list = await _dbDapperContext.QueryAsync<BomExportDto>(sql, null, databaseType: DatabaseType.Secondary); try { // 使用 service 执行工作 await service.Export<BomExportDto>(id, _first, _list.ToList()).ConfigureAwait(false); } catch (Exception ex) { Console.WriteLine(ex.Message.ToString()); } return id.ToString(); } }
测试:
执行hangfire任务
成功通过后台作业生成文件‘
标签:Autofac,作用域,导出,HangFire,LifetimeScope,ABP,list,Magicodes,var From: https://www.cnblogs.com/netcore-vue/p/18246868