Skip to content

Commit

Permalink
Use of IPostConfigureOptions<StaticFileOptions> to configure StaticFi…
Browse files Browse the repository at this point in the history
…leOptions

Fixes OrchardCMS#6505 OrchardCMS#2966
  • Loading branch information
ns8482e committed Aug 15, 2021
1 parent bb87856 commit e0dbe3f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Modules;

namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Configures Module Static File Providers and Set Cache
/// </summary>
internal class ConfigureModuleStaticFileOptions : IPostConfigureOptions<StaticFileOptions>
{
private readonly IModuleStaticFileProvider _fileProvider;
private readonly IShellConfiguration _shellConfiguration;
private readonly IWebHostEnvironment _environment;
public ConfigureModuleStaticFileOptions(IModuleStaticFileProvider fileProvider,
IShellConfiguration shellConfiguration,
IWebHostEnvironment environment)
{
_fileProvider = fileProvider;
_shellConfiguration = shellConfiguration;
_environment = environment;
}
public void PostConfigure(string name, StaticFileOptions options)
{
name = name ?? throw new ArgumentNullException(nameof(name));
options = options ?? throw new ArgumentNullException(nameof(options));

if (name != Microsoft.Extensions.Options.Options.DefaultName)
{
return;
}

var serveWebRoot = _shellConfiguration.GetValue("StaticFileOptions:ServeHostWebRoot", false);
if (serveWebRoot)
{
// Serve Tenant Static files from module and from HostWebRoot
options.FileProvider = new CompositeFileProvider(_fileProvider, _environment.WebRootFileProvider);
}
else
{
// Serve Tenant Static files only from module
options.FileProvider = _fileProvider;
}

var cacheControl = _shellConfiguration.GetValue("StaticFileOptions:CacheControl", $"public, max-age={TimeSpan.FromDays(30).TotalSeconds}, s-max-age={TimeSpan.FromDays(365.25).TotalSeconds}");
var beforePrepare = options.OnPrepareResponse;

options.OnPrepareResponse = ctx => OnPrepareResponseCacheControl(ctx, cacheControl, beforePrepare);
}

private static void OnPrepareResponseCacheControl(StaticFileResponseContext ctx, string cacheControl, Action<StaticFileResponseContext> beforePrepare)
{
if (beforePrepare != null)
{
beforePrepare(ctx);
}

// Cache static files for a year as they are coming from embedded resources and should not vary
ctx.Context.Response.Headers[HeaderNames.CacheControl] = cacheControl;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using OrchardCore;
using OrchardCore.Environment.Extensions;
using OrchardCore.Environment.Shell;
using OrchardCore.Environment.Shell.Builders;
using OrchardCore.Environment.Shell.Configuration;
using OrchardCore.Environment.Shell.Descriptor.Models;
using OrchardCore.Environment.Shell.Models;
using OrchardCore.Localization;
Expand Down Expand Up @@ -173,6 +171,7 @@ private static void AddExtensionServices(OrchardCoreBuilder builder)
/// </summary>
private static void AddStaticFiles(OrchardCoreBuilder builder)
{
var services = builder.ApplicationServices;
builder.ConfigureServices(services =>
{
services.AddSingleton<IModuleStaticFileProvider>(serviceProvider =>
Expand Down Expand Up @@ -201,28 +200,14 @@ private static void AddStaticFiles(OrchardCoreBuilder builder)
{
return serviceProvider.GetRequiredService<IModuleStaticFileProvider>();
});
// Configures StaticFileOptions for Modules
services.ConfigureOptions<ConfigureModuleStaticFileOptions>();
});

builder.Configure((app, routes, serviceProvider) =>
{
var fileProvider = serviceProvider.GetRequiredService<IModuleStaticFileProvider>();
var options = serviceProvider.GetRequiredService<IOptions<StaticFileOptions>>().Value;
options.RequestPath = "";
options.FileProvider = fileProvider;
var shellConfiguration = serviceProvider.GetRequiredService<IShellConfiguration>();
var cacheControl = shellConfiguration.GetValue("StaticFileOptions:CacheControl", $"public, max-age={TimeSpan.FromDays(30).TotalSeconds}, s-max-age={TimeSpan.FromDays(365.25).TotalSeconds}");
// Cache static files for a year as they are coming from embedded resources and should not vary
options.OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers[HeaderNames.CacheControl] = cacheControl;
};
app.UseStaticFiles(options);
app.UseStaticFiles();
});
}

Expand Down
5 changes: 4 additions & 1 deletion src/docs/reference/core/Modules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ You can find a sample application here: [`OrchardCore.Mvc.Web`](../../../../Orch

The following configuration values are used by default and can be customized:

By default each tenant doesn't serve static files from Host `wwwroot`. To serve Host `wwwroot` for each tenant, set `ServeHostWebRoot` to `true` in tenant config.

```json
"StaticFileOptions": {
// The CacheControl header sent with any static file served by modules
"CacheControl": "public, max-age=2592000, s-max-age=31557600"
"CacheControl": "public, max-age=2592000, s-max-age=31557600",
"ServeHostWebRoot" : false
}
```

0 comments on commit e0dbe3f

Please sign in to comment.