Accessing Compressed Blobs from outside NAV (NAV2013)
21.01.14 – This Solution was not completly working, here is the new solutions, tested on NAV2013 R2 : https://devch.wordpress.com/2014/01/21/accessing-compressed-blobs-from-outside-nav-nav2013-revisited/
Just a short hint for anyone interested in accessing BLOB Fields in NAV. In the new Version, the BLOB compression is now longer a proprietary format, NAV now uses the .net deflate Class to compress the binary objects. (In a previous blogpost (https://devch.wordpress.com/2012/01/12/read-content-of-nav-notesblobs-from-sql/) I stated the need for disabling the compression on BLOB fields to access them from outside NAV)
Therefore you can no easily use the DeflateStream Class to decompress the content and access it.
So to decompress the content, the method would look something like this:
public static long Decompress(Stream inp, Stream outp) { byte[] buf = new byte[BUF_SIZE]; long nBytes = 0; // Decompress the contents of the input file using (inp = new DeflateStream(inp, CompressionMode.Decompress)) { int len; while ((len = inp.Read(buf, 0, buf.Length)) > 0) { // Write the data block to the decompressed output stream outp.Write(buf, 0, len); nBytes += len; } } // Done return nBytes; }
hm, not working for me. I dont think its always DEFLATE compressed.
Hi Lukas, i think at the time i checked this, NAV2013 was still in beta, maybe they changed something. Unfortunately for know i don’t have time to check it.
When trying this on the [Object Metadata] table [Metadata] field, I get the error “Unknown block type. Stream might be corrupted” while trying to Decompress the binary field data using DeflateStream. I’m on NAV 2013 but maybe the NAV Object Metadata uses a different compression algorithm or some other custom binary format for these fields?
Yes, I think it’s another format then. Maybe you could find out what’s going on by reflecting the binaries of the service tier.
Edit: I just had a look at the binaries myself, and there is no other behaviour then for normal BLOB fields. Could it be that there is no compression for the object metadata at all?
You can investigate the method by yourself by using ILSpy (or a similar application):
// Microsoft.Dynamics.Nav.Runtime.NavSqlCommand
internal int GetBlobDataFromreader(NCLMetaField field, int resultIndex, NavBLOB navBlob)
{
int num = this.Reader.IsDBNull(resultIndex) ? 0 : ((int)this.Reader.GetBytes(resultIndex, 0L, null, 0, 0));
if (num > 0)
{
using (Stream stream = new BlobReaderStream(this.Reader, resultIndex, num))
{
using (Stream newStream = navBlob.GetNewStream())
{
if (field.FieldIsCompressed)
{
byte[] array = new byte[4];
long num2 = (long)stream.Read(array, 0, 4);
if (num2 < 4L || !NavBLOB.BlobMagicOk(array))
{
this.CloseReader(false, true);
return 22926086;
}
using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
{
deflateStream.CopyTo(newStream);
goto IL_A0;
}
}
stream.CopyTo(newStream);
IL_A0:;
}
}
return 0;
}
return 0;
}
Here is the new (working) solution: https://devch.wordpress.com/2014/01/21/accessing-compressed-blobs-from-outside-nav-nav2013-revisited/
Please let me know if it’s working for you.
Devch, can you do it with Nav2009 R2 using NAVRuntime?
Well when you are in NAV Runtime then you already have access to any blob fields content by using standard nav code. What exactly do you want to do and what does not work for you?
Actually I want to read object table out of navision and export them as text by using .net code. I am dealing with 20 nav databases with same code in all of them.
The Problem is you cannot design the object table, therefore you cannot set the compressed property to false, which is needed in databases before 2013, because the compression used before that is no standard compression and I don’t know of any way to read the content in this situation.
can we do the same with object table? i tried your code, it works with object metadata table in nav 2015 but i get garbage / empty strings when i tried to blob reference field from object table.