Skip to content

Commit 918b3b8

Browse files
Replace IUmbracoMediaFileProvider with IFileProviderFactory implementation
1 parent b414ad5 commit 918b3b8

12 files changed

+204
-148
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Microsoft.Extensions.FileProviders;
2+
3+
namespace Umbraco.Cms.Core.IO
4+
{
5+
/// <summary>
6+
/// Factory for creating <see cref="IFileProvider" /> instances.
7+
/// </summary>
8+
public interface IFileProviderFactory
9+
{
10+
/// <summary>
11+
/// Creates a new <see cref="IFileProvider" /> instance.
12+
/// </summary>
13+
/// <returns>
14+
/// The newly created <see cref="IFileProvider" /> instance.
15+
/// </returns>
16+
IFileProvider Create();
17+
}
18+
}

src/Umbraco.Core/IO/MediaFileManager.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
using System.Linq;
55
using System.Threading.Tasks;
66
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.FileProviders;
78
using Microsoft.Extensions.Logging;
89
using Microsoft.Extensions.Options;
910
using Umbraco.Cms.Core.Configuration.Models;
1011
using Umbraco.Cms.Core.Models;
11-
using Umbraco.Cms.Core.Models.PublishedContent;
1212
using Umbraco.Cms.Core.PropertyEditors;
1313
using Umbraco.Cms.Core.Strings;
1414
using Umbraco.Extensions;
@@ -22,29 +22,49 @@ public sealed class MediaFileManager
2222
private readonly IShortStringHelper _shortStringHelper;
2323
private readonly IServiceProvider _serviceProvider;
2424
private MediaUrlGeneratorCollection _mediaUrlGenerators;
25-
private readonly ContentSettings _contentSettings;
26-
27-
/// <summary>
28-
/// Gets the media filesystem.
29-
/// </summary>
30-
public IFileSystem FileSystem { get; }
3125

3226
public MediaFileManager(
3327
IFileSystem fileSystem,
3428
IMediaPathScheme mediaPathScheme,
3529
ILogger<MediaFileManager> logger,
3630
IShortStringHelper shortStringHelper,
37-
IServiceProvider serviceProvider,
38-
IOptions<ContentSettings> contentSettings)
31+
IServiceProvider serviceProvider)
3932
{
4033
_mediaPathScheme = mediaPathScheme;
4134
_logger = logger;
4235
_shortStringHelper = shortStringHelper;
4336
_serviceProvider = serviceProvider;
44-
_contentSettings = contentSettings.Value;
4537
FileSystem = fileSystem;
4638
}
4739

40+
[Obsolete("Use the ctr that doesn't include unused parameters.")]
41+
public MediaFileManager(
42+
IFileSystem fileSystem,
43+
IMediaPathScheme mediaPathScheme,
44+
ILogger<MediaFileManager> logger,
45+
IShortStringHelper shortStringHelper,
46+
IServiceProvider serviceProvider,
47+
IOptions<ContentSettings> contentSettings)
48+
: this(fileSystem, mediaPathScheme, logger, shortStringHelper, serviceProvider)
49+
{ }
50+
51+
/// <summary>
52+
/// Gets the media filesystem.
53+
/// </summary>
54+
public IFileSystem FileSystem { get; }
55+
56+
/// <summary>
57+
/// Create an <see cref="IFileProvider" /> instance for the media file system.
58+
/// </summary>
59+
/// <returns>
60+
/// The <see cref="IFileProvider" /> for the media file system.
61+
/// </returns>
62+
public IFileProvider CreateFileProvider() => FileSystem switch
63+
{
64+
IFileProviderFactory fileProviderFactory => fileProviderFactory.Create(),
65+
var fileSystem => new FileSystemFileProvider(fileSystem)
66+
};
67+
4868
/// <summary>
4969
/// Delete media files.
5070
/// </summary>

src/Umbraco.Core/IO/PhysicalFileSystem.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
using System.IO;
44
using System.Linq;
55
using System.Threading;
6+
using Microsoft.Extensions.FileProviders;
67
using Microsoft.Extensions.Logging;
78
using Umbraco.Cms.Core.Hosting;
89
using Umbraco.Extensions;
910

1011
namespace Umbraco.Cms.Core.IO
1112
{
12-
public interface IPhysicalFileSystem : IFileSystem {}
13-
public class PhysicalFileSystem : IPhysicalFileSystem
13+
public interface IPhysicalFileSystem : IFileSystem
14+
{ }
15+
16+
public class PhysicalFileSystem : IPhysicalFileSystem, IFileProviderFactory
1417
{
1518
private readonly IIOHelper _ioHelper;
1619
private readonly ILogger<PhysicalFileSystem> _logger;
@@ -28,7 +31,7 @@ public class PhysicalFileSystem : IPhysicalFileSystem
2831
// eg "" or "/Views" or "/Media" or "/<vpath>/Media" in case of a virtual path
2932
private readonly string _rootUrl;
3033

31-
public PhysicalFileSystem(IIOHelper ioHelper,IHostingEnvironment hostingEnvironment, ILogger<PhysicalFileSystem> logger, string rootPath, string rootUrl)
34+
public PhysicalFileSystem(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger<PhysicalFileSystem> logger, string rootPath, string rootUrl)
3235
{
3336
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
3437
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -450,6 +453,9 @@ protected void WithRetry(Action action)
450453
}
451454
}
452455

456+
/// <inheritdoc />
457+
public IFileProvider Create() => new PhysicalFileProvider(_rootPath);
458+
453459
#endregion
454460
}
455461
}

src/Umbraco.Core/IO/ShadowWrapper.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using Microsoft.Extensions.FileProviders;
56
using Microsoft.Extensions.Logging;
67
using Umbraco.Cms.Core.Hosting;
78
using Umbraco.Extensions;
89

910
namespace Umbraco.Cms.Core.IO
1011
{
11-
internal class ShadowWrapper : IFileSystem
12+
internal class ShadowWrapper : IFileSystem, IFileProviderFactory
1213
{
1314
private static readonly string ShadowFsPath = Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs";
1415

@@ -220,5 +221,12 @@ public void AddFile(string path, string physicalPath, bool overrideIfExists = tr
220221
{
221222
FileSystem.AddFile(path, physicalPath, overrideIfExists, copy);
222223
}
224+
225+
/// <inheritdoc />
226+
public IFileProvider Create() => _innerFileSystem switch
227+
{
228+
IFileProviderFactory fileProviderFactory => fileProviderFactory.Create(),
229+
var fileSystem => new FileSystemFileProvider(fileSystem)
230+
};
223231
}
224232
}

src/Umbraco.Core/Umbraco.Core.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
@@ -17,6 +17,7 @@
1717
<ItemGroup>
1818
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
1919
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="5.0.11" />
20+
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="5.0.0" />
2021
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
2122
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
2223
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />

src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
using SixLabors.ImageSharp.Web.DependencyInjection;
77
using Umbraco.Cms.Core.Configuration.Models;
88
using Umbraco.Cms.Core.Hosting;
9+
using Umbraco.Cms.Core.IO;
910
using Umbraco.Cms.Core.Services;
10-
using Umbraco.Cms.Web.Common.ImageProcessors;
1111
using Umbraco.Extensions;
1212

1313
namespace Umbraco.Cms.Web.Common.ApplicationBuilder
@@ -31,7 +31,9 @@ public UmbracoApplicationBuilder(IApplicationBuilder appBuilder)
3131
}
3232

3333
public IServiceProvider ApplicationServices { get; }
34+
3435
public IRuntimeState RuntimeState { get; }
36+
3537
public IApplicationBuilder AppBuilder { get; }
3638

3739
/// <inheritdoc />
@@ -82,9 +84,8 @@ public void WithEndpoints(Action<IUmbracoEndpointBuilderContext> configureUmbrac
8284
}
8385

8486
/// <summary>
85-
/// Registers the default required middleware to run Umbraco
87+
/// Registers the default required middleware to run Umbraco.
8688
/// </summary>
87-
/// <param name="umbracoApplicationBuilderContext"></param>
8889
public void RegisterDefaultRequiredMiddleware()
8990
{
9091
UseUmbracoCoreMiddleware();
@@ -94,14 +95,19 @@ public void RegisterDefaultRequiredMiddleware()
9495
// Important we handle image manipulations before the static files, otherwise the querystring is just ignored.
9596
AppBuilder.UseImageSharp();
9697

98+
// Get media file provider and request path/URL
99+
IFileProvider mediaFileProvider = AppBuilder.ApplicationServices.GetRequiredService<MediaFileManager>().CreateFileProvider();
100+
97101
GlobalSettings globalSettings = AppBuilder.ApplicationServices.GetRequiredService<IOptions<GlobalSettings>>().Value;
98-
IUmbracoMediaFileProvider umbracoMediaFileProvider = AppBuilder.ApplicationServices.GetRequiredService<IUmbracoMediaFileProvider>();
102+
IHostingEnvironment hostingEnvironment = AppBuilder.ApplicationServices.GetService<IHostingEnvironment>();
103+
string mediaRequestPath = hostingEnvironment.ToAbsolute(globalSettings.UmbracoMediaUrl);
99104

100105
AppBuilder.UseStaticFiles(new StaticFileOptions()
101106
{
102-
FileProvider = umbracoMediaFileProvider,
103-
RequestPath = globalSettings.UmbracoMediaUrl.TrimStart("~")
107+
FileProvider = mediaFileProvider,
108+
RequestPath = mediaRequestPath
104109
});
110+
105111
AppBuilder.UseStaticFiles();
106112

107113
AppBuilder.UseUmbracoPluginsStaticFiles();

src/Umbraco.Web.Common/DependencyInjection/ImageSharpConfigurationOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Umbraco.Cms.Web.Common.DependencyInjection
77
/// <summary>
88
/// Configures the ImageSharp middleware options to use the registered configuration.
99
/// </summary>
10-
/// <seealso cref="Microsoft.Extensions.Options.IConfigureOptions&lt;SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddlewareOptions&gt;" />
10+
/// <seealso cref="IConfigureOptions{ImageSharpMiddlewareOptions}" />
1111
public sealed class ImageSharpConfigurationOptions : IConfigureOptions<ImageSharpMiddlewareOptions>
1212
{
1313
/// <summary>
@@ -22,7 +22,7 @@ public sealed class ImageSharpConfigurationOptions : IConfigureOptions<ImageShar
2222
public ImageSharpConfigurationOptions(Configuration configuration) => _configuration = configuration;
2323

2424
/// <summary>
25-
/// Invoked to configure a <typeparamref name="TOptions" /> instance.
25+
/// Invoked to configure an <see cref="ImageSharpMiddlewareOptions" /> instance.
2626
/// </summary>
2727
/// <param name="options">The options instance to configure.</param>
2828
public void Configure(ImageSharpMiddlewareOptions options) => options.Configuration = _configuration;

src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.ImageSharp.cs

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
using Microsoft.AspNetCore.Http;
44
using Microsoft.Extensions.Configuration;
55
using Microsoft.Extensions.DependencyInjection;
6-
using Microsoft.Extensions.DependencyInjection.Extensions;
7-
using Microsoft.Extensions.FileProviders;
86
using Microsoft.Extensions.Options;
97
using Microsoft.Net.Http.Headers;
10-
using SixLabors.ImageSharp.Web;
118
using SixLabors.ImageSharp.Web.Caching;
129
using SixLabors.ImageSharp.Web.Commands;
1310
using SixLabors.ImageSharp.Web.DependencyInjection;
@@ -32,62 +29,58 @@ public static IServiceCollection AddUmbracoImageSharp(this IUmbracoBuilder build
3229
.Get<ImagingSettings>() ?? new ImagingSettings();
3330

3431
builder.Services.AddImageSharp(options =>
35-
{
36-
// options.Configuration is set using ImageSharpConfigurationOptions below
37-
options.BrowserMaxAge = imagingSettings.Cache.BrowserMaxAge;
38-
options.CacheMaxAge = imagingSettings.Cache.CacheMaxAge;
39-
options.CachedNameLength = imagingSettings.Cache.CachedNameLength;
32+
{
33+
// options.Configuration is set using ImageSharpConfigurationOptions below
34+
options.BrowserMaxAge = imagingSettings.Cache.BrowserMaxAge;
35+
options.CacheMaxAge = imagingSettings.Cache.CacheMaxAge;
36+
options.CachedNameLength = imagingSettings.Cache.CachedNameLength;
4037

41-
// Use configurable maximum width and height (overwrite ImageSharps default)
42-
options.OnParseCommandsAsync = context =>
38+
// Use configurable maximum width and height (overwrite ImageSharps default)
39+
options.OnParseCommandsAsync = context =>
40+
{
41+
if (context.Commands.Count == 0)
4342
{
44-
if (context.Commands.Count == 0)
45-
{
46-
return Task.CompletedTask;
47-
}
43+
return Task.CompletedTask;
44+
}
4845

49-
uint width =
50-
context.Parser.ParseValue<uint>(
51-
context.Commands.GetValueOrDefault(ResizeWebProcessor.Width), context.Culture);
52-
uint height = context.Parser.ParseValue<uint>(
53-
context.Commands.GetValueOrDefault(ResizeWebProcessor.Height), context.Culture);
54-
if (width > imagingSettings.Resize.MaxWidth || height > imagingSettings.Resize.MaxHeight)
55-
{
56-
context.Commands.Remove(ResizeWebProcessor.Width);
57-
context.Commands.Remove(ResizeWebProcessor.Height);
58-
}
46+
uint width = context.Parser.ParseValue<uint>(context.Commands.GetValueOrDefault(ResizeWebProcessor.Width), context.Culture);
47+
uint height = context.Parser.ParseValue<uint>(context.Commands.GetValueOrDefault(ResizeWebProcessor.Height), context.Culture);
48+
if (width > imagingSettings.Resize.MaxWidth || height > imagingSettings.Resize.MaxHeight)
49+
{
50+
context.Commands.Remove(ResizeWebProcessor.Width);
51+
context.Commands.Remove(ResizeWebProcessor.Height);
52+
}
5953

60-
return Task.CompletedTask;
61-
};
62-
options.OnBeforeSaveAsync = _ => Task.CompletedTask;
63-
options.OnProcessedAsync = _ => Task.CompletedTask;
64-
options.OnPrepareResponseAsync = context =>
54+
return Task.CompletedTask;
55+
};
56+
options.OnBeforeSaveAsync = _ => Task.CompletedTask;
57+
options.OnProcessedAsync = _ => Task.CompletedTask;
58+
options.OnPrepareResponseAsync = context =>
59+
{
60+
// Change Cache-Control header when cache buster value is present
61+
if (context.Request.Query.ContainsKey("rnd"))
6562
{
66-
// Change Cache-Control header when cache buster value is present
67-
if (context.Request.Query.ContainsKey("rnd"))
68-
{
69-
var headers = context.Response.GetTypedHeaders();
63+
var headers = context.Response.GetTypedHeaders();
7064

71-
var cacheControl = headers.CacheControl;
72-
cacheControl.MustRevalidate = false;
73-
cacheControl.Extensions.Add(new NameValueHeaderValue("immutable"));
65+
var cacheControl = headers.CacheControl;
66+
cacheControl.MustRevalidate = false;
67+
cacheControl.Extensions.Add(new NameValueHeaderValue("immutable"));
7468

75-
headers.CacheControl = cacheControl;
76-
}
69+
headers.CacheControl = cacheControl;
70+
}
7771

78-
return Task.CompletedTask;
79-
};
80-
})
81-
.Configure<PhysicalFileSystemCacheOptions>(options =>
82-
options.CacheFolder =
83-
builder.BuilderHostingEnvironment.MapPathContentRoot(imagingSettings.Cache.CacheFolder))
84-
.AddProcessor<CropWebProcessor>()
85-
.ClearProviders()
86-
.AddProvider<UmbracoImageProvider>();
72+
return Task.CompletedTask;
73+
};
74+
})
75+
.Configure<PhysicalFileSystemCacheOptions>(options => options.CacheFolder = builder.BuilderHostingEnvironment.MapPathContentRoot(imagingSettings.Cache.CacheFolder))
76+
.AddProcessor<CropWebProcessor>();
8777

78+
// Configure middleware to use the registered/shared ImageSharp configuration
8879
builder.Services.AddTransient<IConfigureOptions<ImageSharpMiddlewareOptions>, ImageSharpConfigurationOptions>();
8980

90-
builder.Services.AddUnique<IUmbracoMediaFileProvider, UmbracoMediaFileProvider>();
81+
// Add FileSystemImageProvider before default provider
82+
builder.Services.Insert(0, ServiceDescriptor.Singleton<IImageProvider, FileSystemImageProvider>());
83+
9184
return builder.Services;
9285
}
9386
}

0 commit comments

Comments
 (0)