Unplanned
Last Updated: 26 Jan 2024 12:32 by ADMIN
Francesco
Created on: 09 Jan 2024 09:55
Category: SpreadStreamProcessing
Type: Feature Request
1
SpreadStreamProcessing: NotSupportedException is thrown when a stream which doesn't support seeking is used in the SpreadExporter.CreateWorkbookExporter method

Exception Message: "Stream does not support seeking."

I was trying to stream an XLSX document directly to a write-only stream when I noticed the XlsxWorkbookExporter implementation (or more precisely the custom ZipArchive implementation) requires the stream to be seekable.

2 comments
ADMIN
Dess | Tech Support Engineer, Principal
Posted on: 26 Jan 2024 12:32

Hello,

Thank you for sharing your feedback with us. 

The provided sample code snippet is greatly appreciated. It is a suitable temporary solution. We performed similar tests on our side and we believe that the SpreadExportMode.Create operation works as expected if the stream is not seek-able. Make sure that you follow this item in order to get notified once any status changes occur.

You can add your vote for the item to increase its priority. The more votes an item gathers, the higher its priority becomes.

Regards,
Dess | Tech Support Engineer, Principal
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

PRMconnect
Posted on: 22 Jan 2024 23:04

Not using the Zip implementation, but I had a similar problem trying to use CreateWorkbookExporter to export directly to the Response.OutputStream.  To make this work I created a seek-ignoring stream class that fakes the necessary methods:

        public class SeekIgnoringStream : Stream
        {
            private readonly Stream _outputStream;
            private bool _seekPerformed = false;

            public override bool CanRead => _outputStream.CanRead;

            public override bool CanSeek => true;

            public override bool CanWrite => true;

            public override long Length => _outputStream.Length;

            public override long Position { get => pos; set { } }

            public SeekIgnoringStream(Stream outputStream)
            {
                _outputStream = outputStream;
            }
            long pos = 0;
            public override void Write(byte[] buffer, int offset, int count)
            {
                _outputStream.Write(buffer, offset, count);
                pos += count;
                _outputStream.Flush();
            }

            public override void Flush()
            {
                _outputStream.Flush();
            }

            public override long Seek(long offset, SeekOrigin origin)
            {
                // Ignore the initial seek
                if (!_seekPerformed)
                {
                    _seekPerformed = true;
                    return 0;
                }

                // Otherwise, delegate to the output stream
                return _outputStream.Seek(offset, origin);
            }

            public override void SetLength(long value)
            {
                //_outputStream.SetLength(value);
            }

            public override int Read(byte[] buffer, int offset, int count)
            {
                return _outputStream.Read(buffer, offset, count);
            }
        }

 

And then to use it you wrap the non-seekable stream in a SeekIgnoringStream like so:

 

            using (var ms = new SeekIgnoringStream(Response.OutputStream))
            {
                using (IWorkbookExporter workbook = SpreadExporter.CreateWorkbookExporter(SpreadDocumentFormat.Xlsx, ms))

                { ...

 

At least for a basic implementation writing a single worksheet to Response.OutputStream this does work as basically an unbuffered write operation to the browser.  Note that you do need to set Response.BufferOutput = false before this or else it will still buffer in memory.  I haven't looked at the Telerik internals for this, so I'm not sure under what conditions this might break.