Exporting .Resources to Sql Server (byte [] or string)
One of my current tasks is writing a utility to import the contents of an arbitrary random .resources file (compiles .Resx file) into SqlServer. The problem is that there some of the resources returned as objects are INTERNAL classes, namely:
- System.IO.PinnedBufferMemoryStream
- System.IO.UnmanagedMemoryStreamWrapper (1 page of Google results only… the unknown .Net Class)
Two solutions to this":
- Add your own equivalent classes using the source at:
- Read through the code and realize the the following code will deal with these obstructive classes.
byte[] bytes=null;
// The following two classes are not exposed :-(
// So we must use name instead of IS
switch (value.GetType().Name)
{
case "System.IO.PinnedBufferMemoryStream":
using (Stream stream = (Stream)value)
{
bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
}
break;
case "System.IO.UnmanagedMemoryStreamWrapper":
using (Stream stream = (Stream)value)
{
bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
}
break;
}
It turned out that there is a simpler routine (thanks to Bradley Grainge)
else if (value is Stream) { using (var stream=value as Stream) { bytes = new byte[stream.Length]; stream.Read(bytes, 0, (int)stream.Length); return bytes; } }
The rest of the code is pretty simple, all of the other object types are easy to convert. There was one minor twist that I did because the resources were to used on a website – handling WMF and related non-web images, I converted every thing but GIF to PNG. GIF was not converted because they could be animated.
The entire routine to convert a resource object to byte[] is shown below. The is FileInfo was added to allow the handling of file references in a .Resx file.
/// <summary> /// Converts a resource object into a byte array /// </summary> /// <param name="value">The resource object</param> /// <returns>a byte[] suitable for returning to a Response</returns> public static byte[] ObjectToArray(object value) { byte[] bytes = null; if (value is String) { throw new DataMisalignedException("A string was found, an object was expected"); } else if (value is Byte[]) { return (Byte[])value; } else if (value is FileInfo) { return ((FileInfo)value).GetFile(); } else if (value is Icon) { Icon ico = (Icon)value; using (MemoryStream mem = new MemoryStream()) { ico.Save(mem); return mem.ToArray(); } } else if (value is Bitmap) { Bitmap bitmap = (Bitmap)value; using (MemoryStream mem = new MemoryStream()) { if (bitmap.RawFormat.Guid == System.Drawing.Imaging.ImageFormat.Gif.Guid) { bitmap.Save(mem, System.Drawing.Imaging.ImageFormat.Gif); return mem.ToArray(); } else { bitmap.Save(mem, System.Drawing.Imaging.ImageFormat.Png); return mem.ToArray(); } } } else if (value == null) { return null; } else if (value is Stream) { using (var stream = value as Stream) { bytes = new byte[stream.Length]; stream.Read(bytes, 0, (int)stream.Length); return bytes; } } else return null; }
It seems brittle to rely on the exact names of types that are internal to the BCL. Is there a drawback to writing the first code snippet as:
ReplyDeleteStream stream = value as Stream;
if (stream != null)
{
using (stream)
{ /* read all bytes */ }
}
Thanks Bradley, I had focused on getting A solution. Your proposal is a better solution and has been included in the above revision.
ReplyDelete