Skip to content

Commit 0d9625d

Browse files
Decouple PhysicalFileSystemProvider from WebRootFileProvider
1 parent b15c4d4 commit 0d9625d

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.IO;
56
using System.Threading.Tasks;
67
using Microsoft.AspNetCore.Hosting;
78
using Microsoft.AspNetCore.Http;
89
using Microsoft.AspNetCore.Http.Extensions;
910
using Microsoft.Extensions.FileProviders;
11+
using Microsoft.Extensions.Options;
1012
using SixLabors.ImageSharp.Web.Resolvers;
1113

1214
namespace SixLabors.ImageSharp.Web.Providers
@@ -29,9 +31,11 @@ public class PhysicalFileSystemProvider : IImageProvider
2931
/// <summary>
3032
/// Initializes a new instance of the <see cref="PhysicalFileSystemProvider"/> class.
3133
/// </summary>
34+
/// <param name="options">The provider configuration options.</param>
3235
/// <param name="environment">The environment used by this middleware.</param>
3336
/// <param name="formatUtilities">Contains various format helper methods based on the current configuration.</param>
3437
public PhysicalFileSystemProvider(
38+
IOptions<PhysicalFileSystemProviderOptions> options,
3539
#if NETCOREAPP2_1
3640
IHostingEnvironment environment,
3741
#else
@@ -40,9 +44,18 @@ public PhysicalFileSystemProvider(
4044
FormatUtilities formatUtilities)
4145
{
4246
Guard.NotNull(environment, nameof(environment));
43-
Guard.NotNull(environment.WebRootFileProvider, nameof(environment.WebRootFileProvider));
4447

45-
this.fileProvider = environment.WebRootFileProvider;
48+
// ContentRootPath is never null.
49+
// https://github.com/dotnet/aspnetcore/blob/b89eba6c3cda331ee98063e3c4a04267ec540315/src/Hosting/Hosting/src/WebHostBuilder.cs#L262
50+
Guard.NotNullOrWhiteSpace(environment.WebRootPath, nameof(environment.WebRootPath));
51+
52+
// Allow configuration of the provider without having to register everything
53+
PhysicalFileSystemProviderOptions providerOptions = options != null ? options.Value : new();
54+
string cacheRootPath = GetProviderRoot(providerOptions, environment.WebRootPath, environment.ContentRootPath);
55+
56+
// Ensure provider directory is created before initializing the file provider
57+
Directory.CreateDirectory(cacheRootPath);
58+
this.fileProvider = new PhysicalFileProvider(cacheRootPath);
4659
this.formatUtilities = formatUtilities;
4760
}
4861

@@ -71,5 +84,23 @@ public Task<IImageResolver> GetAsync(HttpContext context)
7184
var metadata = new ImageMetadata(fileInfo.LastModified.UtcDateTime, fileInfo.Length);
7285
return Task.FromResult<IImageResolver>(new PhysicalFileSystemResolver(fileInfo, metadata));
7386
}
87+
88+
/// <summary>
89+
/// Determine the provider root path
90+
/// </summary>
91+
/// <param name="providerOptions">The provider options.</param>
92+
/// <param name="webRootPath">The web root path.</param>
93+
/// <param name="contentRootPath">The content root path.</param>
94+
/// <returns><see cref="string"/> representing the fully qualified provider root path.</returns>
95+
internal static string GetProviderRoot(PhysicalFileSystemProviderOptions providerOptions, string webRootPath, string contentRootPath)
96+
{
97+
string providerRoot = string.IsNullOrWhiteSpace(providerOptions.ProviderRoot)
98+
? webRootPath
99+
: providerOptions.ProviderRoot;
100+
101+
return Path.IsPathFullyQualified(providerRoot)
102+
? providerRoot
103+
: Path.GetFullPath(providerRoot, contentRootPath);
104+
}
74105
}
75106
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
namespace SixLabors.ImageSharp.Web.Providers
5+
{
6+
/// <summary>
7+
/// Configuration options for the <see cref="PhysicalFileSystemProvider" />.
8+
/// </summary>
9+
public class PhysicalFileSystemProviderOptions
10+
{
11+
/// <summary>
12+
/// Gets or sets the optional provider root folder.
13+
/// <para>
14+
/// This value can be <see langword="null"/>, a fully qualified absolute path,
15+
/// or a path relative to the directory that contains the application
16+
/// content files.
17+
/// </para>
18+
/// <para>
19+
/// If not set, this will default to the directory that contains the web-servable
20+
/// application content files; commonly 'wwwroot'.
21+
/// </para>
22+
/// </summary>
23+
public string ProviderRoot { get; set; }
24+
}
25+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using SixLabors.ImageSharp.Web.Providers;
5+
using Xunit;
6+
7+
namespace SixLabors.ImageSharp.Web.Tests.Providers
8+
{
9+
public class PhysicalFileSystemProviderTests
10+
{
11+
[Theory]
12+
#if OS_LINUX
13+
[InlineData(null, "wwwroot", "Users/root/", "Users/root/wwwroot")]
14+
[InlineData(null, "Users/WebRoot", "Users/root/", "Users/WebRoot")]
15+
[InlineData("providerFolder", "../Temp", "Users/this/a/root", "Users/this/a/root/providerFolder")]
16+
[InlineData("../Temp", null, "Users/this/a/root", "Users/this/a/Temp")]
17+
[InlineData("Users/WebRoot", null, "Users/this/a/root", "Users/WebRoot")]
18+
#elif OS_OSX
19+
[InlineData(null, "wwwroot", "Users/root/", "Users/root/wwwroot")]
20+
[InlineData(null, "Users/WebRoot", "Users/root/", "Users/WebRoot")]
21+
[InlineData("providerFolder", "../Temp", "Users/this/a/root", "Users/this/a/root/providerFolder")]
22+
[InlineData("../Temp", null, "Users/this/a/root", "Users/this/a/Temp")]
23+
[InlineData("Users/WebRoot", null, "Users/this/a/root", "Users/WebRoot")]
24+
#elif OS_WINDOWS
25+
[InlineData(null, "wwwroot", "C:/root\\", "C:\\root\\wwwroot")]
26+
[InlineData(null, "C:/WebRoot", "C:/root\\", "C:/WebRoot")]
27+
[InlineData("providerFolder", "../Temp", "C:/this/a/root", "C:\\this\\a\\root\\providerFolder")]
28+
[InlineData("../Temp", null, "C:/this/a/root", "C:\\this\\a\\Temp")]
29+
[InlineData("C:/WebRoot", null, "C:/this/a/root", "C:/WebRoot")]
30+
#endif
31+
public void CacheRootFromOptions(string providerRoot, string webRootPath, string contentRootPath, string expected)
32+
{
33+
var providerOptions = new PhysicalFileSystemProviderOptions
34+
{
35+
ProviderRoot = providerRoot,
36+
};
37+
38+
string providerRootResult = PhysicalFileSystemProvider.GetProviderRoot(providerOptions, webRootPath, contentRootPath);
39+
40+
Assert.Equal(expected, providerRootResult);
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)