Skip to content

MapStaticAssets() should be a viable alternative to UseStaticFiles() #63210

@Atulin

Description

@Atulin

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

  1. I'm trying to serve non-standard files, like .avif and .epub

    With .UseStaticFiles() it's very easy to do:

    var extensionsProvider = new FileExtensionContentTypeProvider();
    extensionsProvider.Mappings.Add(".bar", "foo/bar");
    app.UseStaticFiles(new StaticFileOptions
    {
    	ContentTypeProvider = extensionsProvider,
    });

    With .MapStaticAssets() it's not possible, as far as I can tell.

  2. I'm trying to add ZStandard compression.

    With .UseStaticFiles() it's fairly easy to do, for example using code yoinked from here:

    services.AddResponseCompression(options => {
    		options.Providers.Add<ZstdCompressionProvider>();
    		options.Providers.Add<BrotliCompressionProvider>();
    		options.Providers.Add<GzipCompressionProvider>();
    	})
    	.Configure<ZstdCompressionProvider.Options>(o => o.CompressionLevel = CompressionLevel.Optimal);

    With .MapStaticAssets() it's not possible, as far as I can tell.

  3. I'm trying to serve service workers, which might require a Service-Worker-Allowed response header.

    With .UseStaticFiles() it's pretty trivial as well:

    app.UseStaticFiles(new StaticFileOptions
    {
    	OnPrepareResponse = ctx => {
    	 	if (ctx.File.Name.Contains("worker")
     	 	{
     	 	 	ctx.Context.Response.Headers.Append("Service-Worker-Allowed", "/");
     	 	}
    	},
    });

    With .MapStaticAssets() it's not possible, as far as I can tell.

Describe the solution you'd like

Since .MapStaticAssets() works on build-time, adding customization options is tricky. I see two ways to go about it:

  1. Some basic customization can probably be achieved via some settings file or .csproj properties. For example, appsettings.jsoncould get a section like

    {
        "ConfigureStaticFiles": {
            "ContentTypes": {
                ".foo": "foo/bar",
                ".avif": "image/avif"
            },
            "ExtraHeaders": {
                "**/*.worker.js": {
                    "Service-Worker-Allowed": "/"
                }
            }
        }
    }

    which could then be read on build-time, and the settings could be used in the generated manifest as they are.

    Any more advanced settings like custom compression algorithms (forementioned ZStandard) would not be easy to achieve this way. We'd have to encroach on a weird DSL territory, specifying the compression class as a JSON string or something. That said, for completness' sake, let's say it could look like this:

    {
        "ConfigureStaticFiles": {
            "FileCompression": [
                "MyProject.Infrastructure.ZStandardCompressor",
                "brotli",
                "gzip"
            ]   
        }
    }

    With the compressor being defined by some IFileCompressor interface, like

    interface IFileCompressor
    {
        byte[] Compress(byte[] file);
    }
  2. Precompression should be done on startup or first access, not build time.

    Compressing all files on startup could increase startup times a fair bit, but compressing them on first access should be fine. First time the browser requests a script.js file with gz encoding, the middleware (.UseStaticFiles() perhaps?) could cache the compressed response in a script.js.gz file and just serve that next time it is requested.

    That way, any more advanced config could be defined not unlike it is being defined now. The only difference would be that it doesn't run on every request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ✔️ Resolution: AnsweredResolved because the question asked by the original author has been answered.Status: Resolvedarea-middlewareIncludes: URL rewrite, redirect, response cache/compression, session, and other general middlewaresfeature-static-filesquestion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions