Output Streams and MemoryStream in C#

Aspose.HTML for .NET conversion APIs can write output to files, but production applications often need more control. Use ICreateStreamProvider when conversion results should be stored in memory, uploaded to remote storage, written to a ZIP archive, or handled page by page.

To redirect conversion output in C#, implement ICreateStreamProvider, return a new output stream from GetStream(), pass the provider to Converter.ConvertHTML(), and process the collected streams after conversion. This is especially useful for multi-page image output where each page may require a separate stream.

Output Streams in C#

In many conversion operations, the result is saved directly to a file. However, some workflows need to store the result in memory or send it to custom storage. You can do this by implementing the specialized ICreateStreamProvider interface and passing it to the converter. This interface acts as a callback that is used whenever a new output stream is required.

ICreateStreamProvider may be invoked several times when multiple output streams are required. A common example is rendering HTML to a set of image files, where each page can produce a separate output stream.

MemoryStreamProvider Class

A custom MemoryStreamProvider class can implement ICreateStreamProvider and return MemoryStream objects for conversion output. This approach avoids immediate disk writes and lets the application decide what to do with the generated data after conversion.

Using MemoryStream can reduce file system latency in service workflows and makes it possible to forward output to another storage layer. The tradeoff is memory usage: large documents or multi-page image output can create several streams that must be disposed after use.

  1. Create a MemoryStreamProvider class that implements ICreateStreamProvider.
  2. Store created MemoryStream objects in a collection such as Streams.
  3. Implement GetStream() so each requested output stream is created and returned.
  4. Implement ReleaseStream() for any per-stream cleanup, flushing, upload, or bookkeeping required by your application.
  5. Implement Dispose() to release all collected streams when processing is complete.

The following example shows a custom MemoryStreamProvider implementation:

 1// How to capture output in memory using a custom stream provider
 2
 3class MemoryStreamProvider : ICreateStreamProvider
 4{
 5    // List of MemoryStream objects created during the document rendering
 6    public List<MemoryStream> Streams { get; } = new List<MemoryStream>();
 7
 8    public Stream GetStream(string name, string extension)
 9    {
10        // This method is called when only one output stream is required, for instance for XPS, PDF or TIFF formats
11        MemoryStream result = new MemoryStream();
12        Streams.Add(result);
13        return result;
14    }
15
16    public Stream GetStream(string name, string extension, int page)
17    {
18        // This method is called when the creation of multiple output streams are required. For instance, during the rendering HTML to list of image files (JPG, PNG, etc.)
19        MemoryStream result = new MemoryStream();
20        Streams.Add(result);
21        return result;
22    }
23
24    public void ReleaseStream(Stream stream)
25    {
26        // Here you can release the stream filled with data and, for instance, flush it to the hard-drive
27    }
28
29    public void Dispose()
30    {
31        // Releasing resources
32        foreach (MemoryStream stream in Streams)
33            stream.Dispose();
34    }
35}

After conversion, the provider keeps the generated data in memory until your application processes it. This makes the example useful for services that need to upload output, attach it to a response, write it into an archive, or apply custom naming before saving files. For large documents, process streams promptly and dispose the provider when the workflow is complete.

Save MemoryStream Output to Files

The following C# example uses MemoryStreamProvider with Aspose.HTML for .NET to convert a multi-page HTML document to JPG and save each generated image stream to a file.

  1. Create a MemoryStreamProvider instance for conversion output.
  2. Load the source document with HTMLDocument.
  3. Create ImageSaveOptions and set the output image format to JPEG.
  4. Call Converter.ConvertHTML(document, options, provider).
  5. Iterate over the collected MemoryStream objects. Each stream represents one generated output item, such as a page image.
  6. Call Seek(0, SeekOrigin.Begin) before copying each memory stream to a file.
  7. Create an output file stream and copy the memory stream content with CopyTo().
  8. Dispose all streams when output processing is finished.
 1// Convert HTML to JPEG in C# using output memory streams for writing data
 2
 3// Create an instance of MemoryStreamProvider
 4using (MemoryStreamProvider streamProvider = new MemoryStreamProvider())
 5{
 6    // Prepare HTML code
 7    string code = @"<style>
 8                div { page-break-after: always; }
 9                </style>
10                <div style='border: 1px solid red; width: 300px'>First Page</div>
11                <div style='border: 1px solid red; width: 300px'>Second Page</div>
12                <div style='border: 1px solid red; width: 300px'>Third Page</div>
13             ";
14    // Initialize an HTML document from the HTML code
15    using HTMLDocument document = new HTMLDocument(code, ".");
16    {
17        // Convert HTML to Image by using the MemoryStreamProvider
18        Converter.ConvertHTML(document, new ImageSaveOptions(ImageFormat.Jpeg), streamProvider);
19
20        // Get access to the memory stream that contains the result data
21        int page = 1;
22        foreach (MemoryStream memory in streamProvider.Streams)
23        {
24            memory.Seek(0, SeekOrigin.Begin);
25
26            // Flush the result data to the output file
27            using (FileStream fs = File.Create(Path.Combine(OutputDir, "page_" + page + ".jpg")))
28            {
29                memory.CopyTo(fs);
30            }
31            page++;
32        }
33    }
34}

Common Output Stream Issues

IssueCauseFix
The saved file is emptyThe memory stream position is at the end before copying.Call Seek(0, SeekOrigin.Begin) before copying a MemoryStream to another stream.
Only one page is savedThe conversion produced multiple streams, but the code processed only the first one.Iterate through all streams collected by the provider and name output files page by page.
Memory usage is highLarge documents or image output can create several in-memory streams.Process and release streams promptly, or implement a provider that writes to file, ZIP, or remote storage.
Output is not flushed or uploadedReleaseStream() is empty in a custom provider.Add the required flushing, upload, or persistence logic to ReleaseStream() or process streams after conversion.

Related Articles