Save HTML with Resources in C#

To save HTML with resources in C#, load an HTMLDocument, configure HTMLSaveOptions.ResourceHandlingOptions when needed, and call Save() with a path or a ResourceHandler. Use FileSystemResourceHandler, a custom ZIP handler, or a memory handler when linked CSS, images, scripts, or output streams must be controlled.

HTML documents often depend on linked resources such as CSS files, images, scripts, fonts, or pages referenced from the document. Saving only the main .html file can be enough for generated markup, but it is not enough when the saved document must remain usable outside its original location.

Aspose.HTML for .NET provides SaveOptions, ResourceHandlingOptions, and ResourceHandler APIs to control how linked resources are processed and where output streams are stored.

Use this article when you need to save an HTML document together with resources, save output to a custom folder, create a ZIP archive, or keep saved resources in memory.

ResourceHandlingOptions for HTML Saving

The SaveOptions class is a base class that allows you to specify additional options for saving operations. Its ResourceHandlingOptions property configures how linked resources are handled during saving.

OptionUse it to control
UrlRestrictionApplies restrictions to the hosts or folders where resources are located.
MaxHandlingDepthControls the depth of linked HTML pages that should be handled when the save workflow follows document links.
JavaScriptSpecifies how JavaScript files are handled. Supported values include saving separately, embedding into HTML, ignoring, or discarding scripts. The default value is Save.
DefaultSpecifies behavior for resources other than JavaScript. Supported values include Save, Ignore, and Embed. The default value is Save.

The following C# example creates save-with-linked-file.html, adds a link to linked.html, and uses HTMLSaveOptions with ResourceHandlingOptions to control whether the linked HTML file is saved.

To save an HTML document with linked HTML files in C#:

  1. Load or create an HTMLDocument that contains linked resources.
  2. Create an HTMLSaveOptions instance.
  3. Set options.ResourceHandlingOptions.MaxHandlingDepth = 1 so the linked HTML file can be handled during saving.
  4. Call document.Save(path, options) to save the document with the configured resource handling.
 1// Save HTML with a linked resources using C#
 2
 3// Prepare an output path for an HTML document 
 4string documentPath = Path.Combine(OutputDir, "save-with-linked-file.html");
 5
 6// Prepare a simple HTML file with a linked document
 7File.WriteAllText(documentPath, "<p>Hello, World!</p>" +
 8                                "<a href='linked.html'>linked file</a>");
 9
10// Prepare a simple linked HTML file
11File.WriteAllText(Path.Combine(OutputDir, "linked.html"), "<p>Hello, linked file!</p>");
12
13// Load the "save-with-linked-file.html" into memory
14using (HTMLDocument document = new HTMLDocument(documentPath))
15{
16    // Create a save options instance
17    HTMLSaveOptions options = new HTMLSaveOptions();
18
19    // The following line with value '0' cuts off all other linked HTML-files while saving this instance
20    // If you remove this line or change value to the '1', the 'linked.html' file will be saved as well to the output folder
21    options.ResourceHandlingOptions.MaxHandlingDepth = 1;
22
23    // Save the document with the save options
24    document.Save(Path.Combine(OutputDir, "save-with-linked-file_out.html"), options);
25}

Save HTML to Local File System Storage

The HTML document can contain different resources such as CSS, external images, and other linked files. Aspose.HTML for .NET provides a way to save HTML with all linked files by using a ResourceHandler. This class is responsible for handling resources and provides methods that allow you to control what is done with each resource.

Let’s consider an example of saving HTML with resources to user-specified local file storage. The source with-resources.html document and its linked image file are in the same directory. The FileSystemResourceHandler(customOutDir) constructor takes a path where the document with resources will be saved and creates a FileSystemResourceHandler object. The Save(resourceHandler) method takes this object and saves HTML to the output storage.

To save HTML with resources to a local folder in C#:

  1. Load an HTML document that references external resources.
  2. Create a FileSystemResourceHandler with the target output directory.
  3. Call document.Save(resourceHandler).
  4. Check the output directory for the saved HTML file and related resources.
 1// Save HTML with resources to local storage using C#
 2
 3// Prepare a path to a source HTML file
 4string inputPath = Path.Combine(DataDir, "with-resources.html");
 5
 6// Prepare a full path to an output directory 
 7string customOutDir = Path.Combine(Directory.GetCurrentDirectory(), "./../../../../tests-out/saving/");
 8
 9// Load the HTML document from a file
10using (HTMLDocument doc = new HTMLDocument(inputPath))
11{
12    // Save HTML with resources
13    doc.Save(new FileSystemResourceHandler(customOutDir));
14}

Save HTML with Resources to a ZIP Archive

You can implement the ResourceHandler class by creating a ZipResourceHandler. This makes it possible to create a structured and compressed archive containing the HTML document and associated resources, which is useful for archiving, transfer, or storage optimization.

The HandleResource() method in the ZipResourceHandler class customizes how individual resources are processed and stored in the ZIP archive.

In the following example, the ZipResourceHandler class is used to save the with-resources.html document along with its linked resources to a ZIP archive.

To save HTML with resources to ZIP in C#:

  1. Load the HTML document with linked resources.
  2. Create a custom ZipResourceHandler for the target archive path.
  3. Pass the handler to document.Save(resourceHandler).
  4. Implement HandleResource() so each document resource is written to the archive.
 1// Save an HTML document with all linked resources into a ZIP archive using C#
 2
 3// Prepare a path to a source HTML file 
 4string inputPath = Path.Combine(DataDir, "with-resources.html");
 5
 6string dir = Directory.GetCurrentDirectory();
 7
 8// Prepare a full path to an output zip storage
 9string customArchivePath = Path.Combine(dir, "./../../../../tests-out/saving/archive.zip");
10
11// Load the HTML document 
12using (HTMLDocument doc = new HTMLDocument(inputPath))
13{
14    // Initialize an instance of the ZipResourceHandler class
15    using (ZipResourceHandler resourceHandler = new ZipResourceHandler(customArchivePath))
16    {
17        // Save HTML with resources to a Zip archive
18        doc.Save(resourceHandler);
19    }
20}

The ResourceHandler class is intended for custom implementation. The ZipResourceHandler class extends the ResourceHandler base class and provides a convenient way to manage the entire process of handling and storing resources linked with an HTML document into a ZIP archive.

 1// Custom resource handler to save HTML with resources into a ZIP archive
 2
 3internal class ZipResourceHandler : ResourceHandler, IDisposable
 4{
 5    private FileStream zipStream;
 6    private ZipArchive archive;
 7    private int streamsCounter;
 8    private bool initialized;
 9
10    public ZipResourceHandler(string name)
11    {
12        DisposeArchive();
13        zipStream = new FileStream(name, FileMode.Create);
14        archive = new ZipArchive(zipStream, ZipArchiveMode.Update);
15        initialized = false;
16    }
17
18    public override void HandleResource(Resource resource, ResourceHandlingContext context)
19    {
20        string zipUri = (streamsCounter++ == 0
21            ? Path.GetFileName(resource.OriginalUrl.Href)
22            : Path.Combine(Path.GetFileName(Path.GetDirectoryName(resource.OriginalUrl.Href)),
23                Path.GetFileName(resource.OriginalUrl.Href)));
24        string samplePrefix = String.Empty;
25        if (initialized)
26            samplePrefix = "my_";
27        else
28            initialized = true;
29
30        using (Stream newStream = archive.CreateEntry(samplePrefix + zipUri).Open())
31        {
32            resource.WithOutputUrl(new Url("file:///" + samplePrefix + zipUri)).Save(newStream, context);
33        }
34    }
35
36    private void DisposeArchive()
37    {
38        if (archive != null)
39        {
40            archive.Dispose();
41            archive = null;
42        }
43
44        if (zipStream != null)
45        {
46            zipStream.Dispose();
47            zipStream = null;
48        }
49
50        streamsCounter = 0;
51    }
52
53    public void Dispose()
54    {
55        DisposeArchive();
56    }
57}

Save HTML with Resources to Memory Streams

A custom ResourceHandler implementation can also save HTML and linked resources to memory streams. This is useful in server-side workflows where output must be passed to another service, stored in a database, returned from an API, or processed without writing intermediate files to disk.

The following code shows how to use the MemoryResourceHandler class to store an HTML document in memory, collect handled resources, and print information about them.

To save HTML with resources to memory streams in C#:

  1. Initialize an HTMLDocument using the specified HTML file path.
  2. Create an instance of the MemoryResourceHandler class.
  3. Call document.Save(resourceHandler) and pass the memory handler instance.
  4. Use the PrintInfo() method of the MemoryResourceHandler to print information about handled resources.
 1// Save HTML with resources to memory streams using C#
 2
 3// Prepare a path to a source HTML file 
 4string inputPath = Path.Combine(DataDir, "with-resources.html");
 5
 6// Load the HTML document 
 7using (HTMLDocument doc = new HTMLDocument(inputPath))
 8{
 9    // Create an instance of the MemoryResourceHandler class and save HTML to memory
10    MemoryResourceHandler resourceHandler = new MemoryResourceHandler();
11    doc.Save(resourceHandler);
12    resourceHandler.PrintInfo();
13}

After the example runs, the message about memory storage is printed:

uri:memory:///with-resources.html, length:256
uri:memory:///photo1.png, length:57438

The ResourceHandler class is a base class that supports the creation and management of output streams. The MemoryResourceHandler class allows you to capture and store resources in memory streams, providing a flexible way to handle resources without physically saving them to the file system.

 1// In-memory resource handler that captures and stores HTML resources as streams
 2
 3internal class MemoryResourceHandler : ResourceHandler
 4{
 5    public List<Tuple<Stream, Resource>> Streams;
 6
 7    public MemoryResourceHandler()
 8    {
 9        Streams = new List<Tuple<Stream, Resource>>();
10    }
11
12    public override void HandleResource(Resource resource, ResourceHandlingContext context)
13    {
14        MemoryStream outputStream = new MemoryStream();
15        Streams.Add(Tuple.Create<Stream, Resource>(outputStream, resource));
16        resource
17            .WithOutputUrl(new Url(Path.GetFileName(resource.OriginalUrl.Pathname), "memory:///"))
18            .Save(outputStream, context);
19    }
20
21    public void PrintInfo()
22    {
23        foreach (Tuple<Stream, Resource> stream in Streams)
24            Console.WriteLine($"uri:{stream.Item2.OutputUrl}, length:{stream.Item1.Length}");
25    }
26}

Choosing a Resource Saving Workflow

GoalRecommended workflow
Save the main HTML document and linked resources as filesUse HTMLSaveOptions and ResourceHandlingOptions, or FileSystemResourceHandler when you need a custom output directory.
Store HTML and resources in a custom folderUse FileSystemResourceHandler(customOutDir) and pass it to document.Save(resourceHandler).
Package HTML and resources for archive or transferImplement ZipResourceHandler and write resources to a ZIP archive from HandleResource().
Keep output in memoryImplement MemoryResourceHandler and keep resource streams in memory for further processing.
Control JavaScript handlingConfigure ResourceHandlingOptions.JavaScript; the default value is Save.

Common Resource Saving Issues

ProblemCauseSolution
CSS or images are missing from outputLinked resources were not saved or resource URL restrictions prevented handling.Review ResourceHandlingOptions and use a ResourceHandler workflow when output storage must be controlled.
Resources are saved in an unexpected locationThe default save path or handler output path does not match the expected storage layout.Use FileSystemResourceHandler(customOutDir) when the output directory must be explicit.
ZIP archive misses some filesHandleResource() does not write every handled resource to the archive.Check the custom ZipResourceHandler implementation and process each resource passed to HandleResource().
Memory usage grows during savingLarge resources are held in memory streams.Use file-system or streaming output for large resources, or release streams as soon as the next workflow step accepts them.
JavaScript files are not embeddedJavaScript handling uses the default Save behavior.Set ResourceHandlingOptions.JavaScript to an embed behavior when embedded scripts are required.

FAQ

How do I save HTML with CSS and images in C#?

Load the HTML document, configure HTMLSaveOptions or use a ResourceHandler, and call Save() so linked resources are handled together with the document.

When should I use FileSystemResourceHandler?

Use FileSystemResourceHandler when you need to save the HTML document and related resources to a specific local output directory.

Can I save HTML and resources to a ZIP archive?

Yes. Implement a custom ZipResourceHandler and write each handled resource to the archive inside HandleResource().

Can I save resources without writing files to disk?

Yes. Implement a memory-based ResourceHandler and keep handled resources in memory streams for further processing.

Related Articles

The complete C# examples and data files are available in the Aspose.HTML for .NET GitHub repository.