Our goal is to generate reports in streaming mode.
At some point we need to deal with data streams (e.g. xml streams for xslt transformations). Often a nature of report demands several passes through the data. To increase performance we have defined a class named StreamResource. This class encapsulates input data, reads it once and caches it into a temp file; thus data can be traversed many times. StreamResource can read data lazily or in a eager way thus releasing resources early. This class can be used as a variation of PipeStream, which never blocks, as if a size of a buffer is not limited, and which can be read many times.
StreamResource
PipeStream
The API looks like this:
public class StreamResource: IDisposable { /// <summary> /// Creates a StreamSource instance. /// </summary> /// <param name="source"> /// A function that returns source as an input stream. /// </param> /// <param name="settings">Optional settings.</param> public StreamResource(Func<Stream> source, Settings settings = null); /// <summary> /// Creates a StreamSource instance. /// </summary> /// <param name="source"> /// A function that writes source data into an output stream. /// </param> /// <param name="settings">Optional settings.</param> public StreamResource(Action<Stream> source, Settings settings = null); /// <summary> /// Gets an input stream. /// </summary> /// <param name="shared"> /// Indicates that this StreamResouce should be disposed when returned /// stream is closed and there are no more currently opened cache streams. /// </param> /// <returns>A input stream.</returns> public Stream GetStream(bool shared = false); }
The use pattern is following:
// Acquire resource. using(var resource = new StreamResource(() => CallService(params...))) { // Read stream. using(var stream = resource.GetStream()) { ... } ... // Read stream again. using(var stream = resource.GetStream()) { ... } }
StreamResource is efficient even if you need to process content only once, as it monitors timings of reading of source data and compares it with timings of data consumption. If the difference exceeds some threshold then StreamResource caches source greedily, otherwise source is pooled lazily. Thus, input resources can be released promptly. This is important, for example, when the source depends on a database connection.
// Acquire resource and get shared stream. using(var stream = new StreamResource(() => CallService(params...)).GetStream(true)) { ... }
Finally, StreamResource allows to process data in a pipe stream mode. This is when you have a generator function Action<Stream> that can write to a stream, and you want to read that data. The advantage of StreamResource over real pipe stream is that it can work without blocking of generator, thus releasing resources early.
Action<Stream>
The use pattern is similar to the previous one:
using(var stream = new StreamResource(output => Generate(output, params...)).GetStream(true)) { ... }
The source of the class can be found at Streaming.zip.
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u