简体   繁体   English

序列化/反序列化大数据集

[英]Serialize/Deserialize Large DataSet

I have a reporting tool that sends query requests to a server. 我有一个报告工具,可将查询请求发送到服务器。 After the query is done by the server the result is sent back to the requesting reporting tool. 服务器完成查询后,结果将发送回请求报告工具。 The communication is done using WCF. 使用WCF完成通信。

The queried data, stored in a DataSet object, is very large and is usually round about 100mb big. 存储在DataSet对象中的查询数据非常大,通常约为100mb。

To fasten the transmission I serialize (BinaryFormatter) and compress the DataSet.The transmitted object between the server and reporting tool is a byte array. 为了加快传输速度,我进行了序列化(BinaryFormatter)并压缩了DataSet。服务器和报表工具之间传输的对象是字节数组。

However after a few requests the reporting tool throws an OutOfMemoryException when it tries to deserialize the DataSet. 但是,在几次请求之后,报表工具尝试对数据集进行反序列化时会引发OutOfMemoryException。 The exception is thrown when I call: 当我打电话时抛出异常:

dataSet = (DataSet) formatter.Deserialize(dstream);

dstream is the DeflateStream used to decompress the transmitted compressed byte array. dstream是DeflateStream,用于解压缩传输的压缩字节数组。

The exception occurs in a sub call of formatter.Deserialize when the byte array is created out of the stream. 异常发生在formatter的子调用中。从流中创建字节数组时,请反序列化。

Is there any other way of binary serialization that has a better mechanism to prevent this exception? 还有其他任何更好的机制来防止此异常的二进制序列化方式吗?

Implementation: 执行:

The method to serialize and compress the DataSet (used by the server) 序列化和压缩数据集的方法(由服务器使用)

public static byte[] Compress(DataSet dataSet)
{
    using (var input = new MemoryStream())
    {
        var binaryFormatter = new BinaryFormatter();
        binaryFormatter.Serialize(input, dataSet);

        using (var output = new MemoryStream())
        {
            using (var compressor = new DeflateStream(output, CompressionLevel.Optimal))
            {
                input.Position = 0;

                var buffer = new byte[1024];

                int read;

                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                    compressor.Write(buffer, 0, read);

                compressor.Close();

                return output.ToArray();
            }
        }
    }
}

The method to decompress and deserialize the DataSet (used by the reporting tool) 解压缩和反序列化DataSet的方法(由报表工具使用)

public static DataSet Decompress(byte[] data)
{
    DataSet dataSet;

    using (var input = new MemoryStream(data))
    {
        using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
        {
            var formatter = new BinaryFormatter();
            dataSet = (DataSet) formatter.Deserialize(dstream);
        }
    }

    return dataSet;
}

Stacktrace: 堆栈跟踪:

at System.Array.InternalCreate(Void* elementType, Int32 rank, Int32* pLengths, Int32* pLowerBounds)
at System.Array.CreateInstance(Type elementType, Int32 length)
at System.Array.UnsafeCreateInstance(Type elementType, Int32 length)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseArray(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObject(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at DRX.PTClientMonitoring.Infrastructure.Helper.DataSetCompressor.Decompress(Byte[] data) in c:\_develop\PTClientMonitoringTool\PTClientMonitoringTool\Source\DRX.PTClientMonitoring.Infrastructure\Helper\DataSetCompressor.cs:line 51
at DRX.PTClientMonitoring.Reporting.ViewModels.ShellViewModel.<>c__DisplayClassf.<ExecudeDefinedQuery>b__4() in c:\_develop\PTClientMonitoringTool\PTClientMonitoringTool\Source\DRX.PTClientMonitoring.Reporting\ViewModels\ShellViewModel.cs:line 347

Before serializing, set: 序列化之前,请设置:

yourDataSet.RemotingFormat = SerializationFormat.Binary;

That should help a lot. 那应该有很大帮助。 The default even when using BinaryFormatter is xml. 即使使用BinaryFormatter ,默认值也是xml。

Note, however, that DataSet and DataTable are inherently not great candidates for optimization. 但是请注意, DataSetDataTable 本质上不是优化的最佳选择。 There are a lot of great serialization tools that will do a much better job of packing your data, but they invariable require strong type models, ie List<SomeSpecificType> where SomeSpecificType is a POCO/DTO class. 有很多伟大的序列化工具,将做包装你的数据的一个更好的工作,但他们不变的需要强大的款型,即List<SomeSpecificType>其中SomeSpecificType是POCO / DTO类。 Even WCF only barely tolerates DataTable / DataSet . 甚至WCF也几乎不能容忍DataTable / DataSet So if you can get rid of your dependency on DataTable / DataSet : I strongly advise doing so. 因此,如果您可以摆脱对DataTable / DataSet依赖,我强烈建议您这样做。

Another option is to send the data as a Stream . 另一种选择是将数据作为Stream发送 I'm pretty sure WCF supports this natively, but this would in theory allow you to have a different Stream ( not MemoryStream ) that is actually much larger. 我很确定WCF本身就支持此功能,但是从理论上讲,这将使您拥有一个实际上更大得多的不同Stream不是 MemoryStream )。 As a cheap option you could use a temporary file as a scratch area, but if that works you could investigate a custom in-memory stream that stitches multiple buffers together. 作为一种便宜的选择,您可以将临时文件用作暂存区域,但是如果可行,您可以研究将多个缓冲区缝合在一起的自定义内存流。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM