传递ImageSharp Image参数时触发ObjectDisposedException的解决咨询
问题原因
你遇到的ObjectDisposedException是因为GetTicketWithQRCode方法中使用了using var声明imageWithQRCode对象。using关键字会在方法执行完毕(返回结果后)自动调用对象的Dispose方法释放资源,导致后续Send方法尝试操作这个已被释放的Image对象时触发异常。
解决方案
有两种可行的处理方式,根据你的场景选择:
方案一:移除imageWithQRCode的using声明,由调用方管理生命周期
修改GetTicketWithQRCode方法,去掉imageWithQRCode的using修饰:
async public Task<Image> GetTicketWithQRCode(CancellationToken cancellationToken) { var qrCode = QrCode.EncodeText($@" {{ Id:""{this.TickedGuid}"", UserData:""{this.TickedUserData.Name} {this.TickedUserData.Surname}"" }} ", QrCode.Ecc.Quartile); using var imageBase = await Image.LoadAsync<Rgba32>($"/var/opt/clubapp/images/{this.Ticket.Image.ImageSrc}", cancellationToken); // 移除using,手动管理对象生命周期 var imageWithQRCode = new Image<Rgba32>(imageBase.Width, imageBase.Height); imageWithQRCode.CombineWithBaseImageAndQrCode(imageBase, qrCode, new Size() { Width = 390, Height = 495 }, 250); await imageWithQRCode.ResizeToHasMaximumFileSize(1.5, cancellationToken); var imageRatio = imageWithQRCode.Width / imageWithQRCode.Height; imageWithQRCode.Mutate(x => x.Resize(new ResizeOptions() { Mode = ResizeMode.Max, Size = new Size() { Height = 100, Width = 100 * imageRatio } })); return imageWithQRCode; }
然后在Handle方法中使用完Image对象后手动释放:
public async Task<Unit> Handle(CancellationToken cancellationToken) { ... var ticketImage = await ticket.GetTicketWithQRCode(cancellationToken); try { _emailService.Send(ticketImage); } finally { // 使用完毕后手动释放资源 ticketImage.Dispose(); } return new Unit(); }
方案二:返回处理好的MemoryStream而非Image对象
这种方式更安全,因为可以在GetTicketWithQRCode方法内完成Image对象的释放,避免后续生命周期管理问题:
修改GetTicketWithQRCode返回MemoryStream:
async public Task<MemoryStream> GetTicketWithQRCode(CancellationToken cancellationToken) { var qrCode = QrCode.EncodeText($@" {{ Id:""{this.TickedGuid}"", UserData:""{this.TickedUserData.Name} {this.TickedUserData.Surname}"" }} ", QrCode.Ecc.Quartile); using var imageBase = await Image.LoadAsync<Rgba32>($"/var/opt/clubapp/images/{this.Ticket.Image.ImageSrc}", cancellationToken); using var imageWithQRCode = new Image<Rgba32>(imageBase.Width, imageBase.Height); imageWithQRCode.CombineWithBaseImageAndQrCode(imageBase, qrCode, new Size() { Width = 390, Height = 495 }, 250); await imageWithQRCode.ResizeToHasMaximumFileSize(1.5, cancellationToken); var imageRatio = imageWithQRCode.Width / imageWithQRCode.Height; imageWithQRCode.Mutate(x => x.Resize(new ResizeOptions() { Mode = ResizeMode.Max, Size = new Size() { Height = 100, Width = 100 * imageRatio } })); var memoryStream = new MemoryStream(); // 将Image保存到流中 await imageWithQRCode.SaveAsPngAsync(memoryStream, cancellationToken); // 重置流的位置到开头,确保后续能正确读取 memoryStream.Position = 0; return memoryStream; }
修改Send方法接收MemoryStream:
public string Send(MemoryStream imageStream) { var message = new MimeMessage(); [...] var body = new TextPart("Html") { Text = @"test" }; var attachment = new MimePart("image", "png") { Content = new MimeContent(imageStream), ContentDisposition = new ContentDisposition(ContentDisposition.Attachment), ContentTransferEncoding = ContentEncoding.Base64, }; ... }
最后在Handle方法中管理流的生命周期:
public async Task<Unit> Handle(CancellationToken cancellationToken) { ... var ticketImageStream = await ticket.GetTicketWithQRCode(cancellationToken); try { _emailService.Send(ticketImageStream); } finally { ticketImageStream.Dispose(); } return new Unit(); }
总结
推荐使用方案二,因为它将Image对象的生命周期完全限制在GetTicketWithQRCode方法内,避免了跨方法的资源管理风险,代码更健壮。
内容的提问来源于stack exchange,提问作者Gersalom
相关产品推荐
相关产品推荐

