Shane32.CompressedStaticFiles
1.0.1
dotnet add package Shane32.CompressedStaticFiles --version 1.0.1
NuGet\Install-Package Shane32.CompressedStaticFiles -Version 1.0.1
<PackageReference Include="Shane32.CompressedStaticFiles" Version="1.0.1" />
<PackageVersion Include="Shane32.CompressedStaticFiles" Version="1.0.1" />
<PackageReference Include="Shane32.CompressedStaticFiles" />
paket add Shane32.CompressedStaticFiles --version 1.0.1
#r "nuget: Shane32.CompressedStaticFiles, 1.0.1"
#:package Shane32.CompressedStaticFiles@1.0.1
#addin nuget:?package=Shane32.CompressedStaticFiles&version=1.0.1
#tool nuget:?package=Shane32.CompressedStaticFiles&version=1.0.1
Shane32.CompressedStaticFiles
ASP.NET Core middleware that automatically serves pre-compressed static files (Brotli and Gzip) when available, falling back to uncompressed files.
🚀 Quick Start
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Add compressed static files middleware
app.UseCompressedStaticFiles();
app.Run();
📦 Compression of Static Assets
.NET 10+ automatically compresses static assets during publish. For earlier versions or when copying a project separately after build (such as a Vite React project), you'll need to compress files manually.
Vite Plugin Example
For Vite projects, use the vite-plugin-compression2 plugin:
npm install vite-plugin-compression2 --save-dev
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import compression from 'vite-plugin-compression2'
export default defineConfig({
plugins: [
react(),
// Generate both .gz and .br files
compression({
algorithms: ["gzip", "brotliCompress"],
}),
]
})
⚙️ Configuration Options
The CompressedStaticFileOptions class provides the following configuration options:
| Property | Type | Description |
|---|---|---|
RequestPath |
PathString |
See SharedOptionsBase.RequestPath |
ContentTypeProvider |
IContentTypeProvider |
See StaticFileOptions.ContentTypeProvider |
DefaultContentType |
string? |
See StaticFileOptions.DefaultContentType |
ServeUnknownFileTypes |
bool |
See StaticFileOptions.ServeUnknownFileTypes |
OnPrepareResponse |
Action<StaticFileResponseContext>? |
See StaticFileOptions.OnPrepareResponse |
OnPrepareResponseAsync |
Func<StaticFileResponseContext, Task>? |
See StaticFileOptions.OnPrepareResponseAsync |
FileSystemPath |
string? |
The physical file system path to serve files from. If not specified, the web root path will be used. |
Encodings |
Dictionary<string, EncodingOptions> |
Dictionary mapping Content-Encoding values to their configuration (file extension and priority). Default includes Brotli ("br" with extension .br and priority 0) and Gzip ("gzip" with extension .gz and priority 1). |
EncodingOptions
The EncodingOptions class configures each supported encoding:
| Property | Type | Description |
|---|---|---|
Extension |
string |
The file extension for this encoding (e.g., ".br", ".gz"). |
Priority |
int |
Priority for this encoding when client quality values are equal. Lower values have higher priority. Default is 0. |
🔧 Advanced Examples
Custom Directory with Cache Headers
This example demonstrates serving compressed static files from a custom directory with a specific request path and cache headers:
app.UseCompressedStaticFiles(new CompressedStaticFileOptions
{
RequestPath = "/static",
FileSystemPath = Path.Combine(builder.Environment.WebRootPath, "static"),
OnPrepareResponse = ctx =>
{
// Add cache headers for long-term caching
ctx.Context.Response.Headers.CacheControl = "public,max-age=31536000,immutable";
},
});
Custom Encodings
This example shows how to add support for additional compression formats or customize priorities:
app.UseCompressedStaticFiles(new CompressedStaticFileOptions
{
Encodings = new Dictionary<string, EncodingOptions>(StringComparer.OrdinalIgnoreCase)
{
// Brotli with highest priority
{ "br", new EncodingOptions { Extension = ".br", Priority = 0 } },
// Gzip with medium priority
{ "gzip", new EncodingOptions { Extension = ".gz", Priority = 1 } },
// Deflate with lowest priority (if you have .zz files)
{ "deflate", new EncodingOptions { Extension = ".zz", Priority = 2 } }
}
});
🔍 How It Works
This middleware is built on top of ASP.NET Core's UseStaticFiles middleware. As such, all security protections provided by ASP.NET Core are inherited, including:
- Protection against path traversal attacks (e.g.,
../sequences) - Invalid filename character validation
- Query string handling (e.g.,
/sample.txt?ab=cd) - Other built-in security features of the static files middleware
The middleware intelligently serves compressed files based on the client's Accept-Encoding header:
- Quality-based selection: The middleware parses quality values (q-values) from the
Accept-Encodingheader and prioritizes encodings with higher quality values - Priority tie-breaking: When multiple encodings have the same quality value, the middleware uses the
Priorityproperty to determine which encoding to serve first - Fallback behavior: If no compressed version exists or the client doesn't support any configured encodings, it serves the uncompressed file
- Wildcard handling: The wildcard
*inAccept-Encodingis ignored for safety, resulting in uncompressed file delivery
The middleware automatically sets the Content-Encoding header when serving compressed files.
Note: When using ASP.NET Core's
UseResponseCompressionmiddleware, it will automatically ignore any files served by this middleware that are already compressed. This prevents double compression and ensures optimal performance.
Example Scenarios
Accept-Encoding: br, gzip→ Serves Brotli (both have quality 1.0, Brotli has priority 0)Accept-Encoding: gzip;q=0.9, br;q=0.8→ Serves Gzip (higher quality value)Accept-Encoding: br;q=0→ Serves uncompressed (q=0 means not acceptable)Accept-Encoding: *→ Serves uncompressed (wildcard is ignored)
Content Type Provider
When no ContentTypeProvider is specified, the middleware creates a default FileExtensionContentTypeProvider with all configured compressed extensions removed from the mappings. This ensures that:
- Compressed files (e.g.,
script.js.br,style.css.gz) are not directly served as separate content types - The content type is determined from the original file name (e.g.,
script.js.bris served with the content type for.jsfiles) - Direct requests to compressed files (e.g.,
/script.js.br) will return 404 Not Found, preventing clients from bypassing the compression negotiation
If you provide a custom ContentTypeProvider, you should ensure it does not include mappings for your compressed file extensions.
📄 License
This project is licensed under the MIT License. See the LICENSE file for details.
🙏 Credits
Glory to Jehovah, Lord of Lords and King of Kings, creator of Heaven and Earth, who through his Son Jesus Christ, has reedemed me to become a child of God. -Shane32
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.