.NET 7无PackageStore类,如何获取内存中Bitmap的URI?
.NET 7 中生成内存Bitmap的URI替代方案
在.NET 7中,PackageStore类被移除后,我们可以通过自定义内存包缓存+注册URI请求处理程序的方式,实现不创建临时文件的内存Bitmap URI生成逻辑。
核心思路
- 用静态类替代
PackageStore,维护内存中的Package实例缓存 - 注册自定义的
WebRequest处理程序,让系统能解析pack://格式的URI并读取内存中的流
实现步骤
1. 安装依赖
首先确保已安装System.IO.Packaging NuGet包:
Install-Package System.IO.Packaging
2. 实现内存包缓存类
用于存储和管理内存中的Package实例,替代原PackageStore的功能:
using System.Collections.Generic; using System.IO.Packaging; using System; using System.Threading; public static class MemoryPackageCache { private static readonly Dictionary<Uri, Package> _packageCache = new Dictionary<Uri, Package>(); private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); public static void AddPackage(Uri packUri, Package package) { _lock.EnterWriteLock(); try { if (_packageCache.ContainsKey(packUri)) throw new InvalidOperationException("该URI对应的包已存在"); _packageCache.Add(packUri, package); } finally { _lock.ExitWriteLock(); } } public static bool TryGetPackage(Uri packUri, out Package? package) { _lock.EnterReadLock(); try { return _packageCache.TryGetValue(packUri, out package); } finally { _lock.ExitReadLock(); } } public static void RemovePackage(Uri packUri) { _lock.EnterWriteLock(); try { if (_packageCache.TryGetValue(packUri, out var package)) { package.Dispose(); _packageCache.Remove(packUri); } } finally { _lock.ExitWriteLock(); } } }
3. 实现自定义WebRequest处理程序
让系统能够解析pack:// URI并返回内存中的流:
using System.IO.Packaging; using System.Net; using System; public class MemoryPackWebRequest : WebRequest { private readonly PackagePart? _targetPart; private MemoryPackWebRequest(Uri uri) { // 解析pack URI,拆分出包URI和部件URI var packUri = PackUriHelper.GetPackageUri(uri); if (MemoryPackageCache.TryGetPackage(packUri, out var package)) { var partUri = PackUriHelper.GetPartUri(uri); _targetPart = package.GetPart(partUri); } } public override Stream GetResponseStream() { return _targetPart?.GetStream() ?? throw new WebException("未找到内存中的包部件"); } public override WebResponse GetResponse() { return new MemoryPackWebResponse(this); } // 自定义WebResponse实现 public class MemoryPackWebResponse : WebResponse { private readonly MemoryPackWebRequest _request; public MemoryPackWebResponse(MemoryPackWebRequest request) { _request = request; } public override Stream GetResponseStream() { return _request.GetResponseStream(); } } // WebRequest创建器 public class MemoryPackWebRequestCreator : IWebRequestCreate { public WebRequest Create(Uri uri) { return new MemoryPackWebRequest(uri); } } }
4. 注册处理程序并生成URI
在应用启动时注册pack://前缀的处理程序,然后修改原方法生成内存Bitmap的URI:
注册处理程序(例如在App.xaml.cs的OnStartup方法中)
WebRequest.RegisterPrefix("pack://", new MemoryPackWebRequest.MemoryPackWebRequestCreator());
生成内存Bitmap URI的方法
using System.IO.Packaging; using System; using System.IO; Uri GetMemoryBitmapUri() { // 创建内存包 MemoryStream packStream = new MemoryStream(); Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite); // 定义包的基础URI并添加到缓存 Uri packBaseUri = new Uri("pack://memory_bitmap/"); MemoryPackageCache.AddPackage(packBaseUri, pack); // 创建包中的图片部件 Uri partUri = new Uri("/bitmap.jpg", UriKind.Relative); PackagePart imagePart = pack.CreatePart(partUri, System.Net.Mime.MediaTypeNames.Image.Jpeg); // 写入Bitmap字节数据 byte[] bitmapBytes = GetInMemoryBitmapData(); // 替换为你的Bitmap字节获取逻辑 using (Stream partStream = imagePart.GetStream()) { partStream.Write(bitmapBytes, 0, bitmapBytes.Length); } // 生成最终的pack URI return PackUriHelper.Create(packBaseUri, partUri); } // 示例:模拟获取Bitmap字节数据的方法 byte[] GetInMemoryBitmapData() { // 这里替换为实际的Bitmap转字节逻辑 using (var ms = new MemoryStream()) { // 假设你有一个Bitmap对象:bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); return ms.ToArray(); } }
注意事项
- 内存管理:当不再需要该URI时,务必调用
MemoryPackageCache.RemovePackage(packBaseUri)释放资源,避免内存泄漏。 - URI唯一性:确保每个内存包的基础URI(如
pack://memory_bitmap/)是唯一的,避免缓存冲突。 - 兼容性:该方案适用于大多数接受URI并通过
WebRequest读取流的类,若目标类有特殊的URI解析逻辑,可能需要调整自定义处理程序的实现。
内容的提问来源于stack exchange,提问作者undermind
相关产品推荐
相关产品推荐

