Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds asp-append-version support #3581

Merged
merged 31 commits into from Jul 5, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d6af96f
MediaFileStoreVersionProvider and FileVersionHashProvider
deanmarcussen Apr 30, 2019
ca10230
WIP. Add IFileVersion to ResourceManager and Tag Helpers
deanmarcussen May 4, 2019
b1c17bc
Merge branch 'dev' into file-version-providers
deanmarcussen May 4, 2019
0541823
WIP Update ResourceManifest and admin layout to use asp-append-versio…
deanmarcussen May 4, 2019
b23d4a6
create IModuleStaticFileProvider and provide registration identifiers…
deanmarcussen May 4, 2019
6eac4c1
WIP. Media ImageHelper working but needs further testing
deanmarcussen May 4, 2019
303c3b3
add ImageVersionProcessor suggest by jtkech. Tested works well
deanmarcussen May 4, 2019
5b090ac
Fixes #3434 Setting the right resource key in debug mode - added #817…
deanmarcussen May 4, 2019
a78bd7c
add liquid tag helper for append_version
deanmarcussen May 4, 2019
55eb778
updated LiquidFilter to work via httpContextAccessor to support media…
deanmarcussen May 4, 2019
fd70d8f
implement cache / tidy up mediafilter
deanmarcussen May 4, 2019
a5e8b65
remove IFileVersionHashProvider, and Replace, rather than remove and …
deanmarcussen May 5, 2019
6890dc3
renamed MediaFileImageProvider to MediaResizingFileProvider
deanmarcussen May 5, 2019
7e886d2
add CdnBaseUrl support for prepending a base cdn url to assets
deanmarcussen May 5, 2019
aa05c9d
update documentation, and support append-version with AssertUrl Helper
deanmarcussen May 5, 2019
6e103c7
documentation tweaks
deanmarcussen May 5, 2019
bb8b9d2
more documentation tweaks
deanmarcussen May 5, 2019
b48595d
add support for tenant static file provider, and change tenant static…
deanmarcussen May 6, 2019
413b0b4
Add support for IVirtualPathBaseProvider as a better generic filter t…
deanmarcussen May 6, 2019
b71cff3
Code cleanup
deanmarcussen May 6, 2019
81a82dd
Refactoring
jtkech May 7, 2019
57a9123
Minor changes.
jtkech May 7, 2019
5f5be76
Refactoring ShellFileVersionProvider
jtkech May 8, 2019
2e96a57
Refactoring, rename ImageTagHelper Attribute asp-append-version
deanmarcussen May 8, 2019
45847ba
Also use a shared cache for module static files.
jtkech May 8, 2019
59eae16
Minor change.
jtkech May 9, 2019
4ed9ef9
Add support for AppendVersion to Link Tag Helper
deanmarcussen May 9, 2019
40e32f8
Merge branch 'dev' into file-version-providers
deanmarcussen May 30, 2019
83ae789
merge dev, resolve conflicts
deanmarcussen Jun 23, 2019
3382ab5
Merge remote-tracking branch 'oc-origin/dev' into file-version-providers
jtkech Jul 4, 2019
4563054
Little formatting after merging dev.
jtkech Jul 5, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Liquid/README.md
Expand Up @@ -231,6 +231,8 @@ Gives access to the current site settings, e.g `Site.SiteName`.
| `SuperUser` | `admin` | The user name of the site's super user. |
| `TimeZoneId` | `America/Los_Angeles` | The site's time zone id as per the tz database, c.f., https://en.wikipedia.org/wiki/List_of_tz_database_time_zones |
| `UseCdn` | `false` | Enable/disable the use of a CDN. |
| `ResourceDebugMode` | `Disabled` | Provides options for whether src or debug-src is used for loading scripts and stylesheets |
| `CdnBaseUrl` | `https://localhost:44300` | If provided a CDN Base url is prepended to local scripts and stylesheets |

### Request

Expand Down
@@ -1,7 +1,8 @@
using System;
using System.Threading.Tasks;
using Fluid;
using Fluid.Values;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using OrchardCore.Liquid;

namespace OrchardCore.Media.Filters
Expand Down Expand Up @@ -76,4 +77,27 @@ public ValueTask<FluidValue> ProcessAsync(FluidValue input, FilterArguments argu
return new ValueTask<FluidValue>(new StringValue(url));
}
}

public class AppendVersionFilter : ILiquidFilter
deanmarcussen marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly IFileVersionProvider _fileVersionProvider;
private readonly IHttpContextAccessor _httpContextAccessor;

public AppendVersionFilter(
IFileVersionProvider fileVersionProvider,
IHttpContextAccessor httpContextAccessor)
{
_fileVersionProvider = fileVersionProvider;
_httpContextAccessor = httpContextAccessor;
}

public ValueTask<FluidValue> ProcessAsync(FluidValue input, FilterArguments arguments, TemplateContext ctx)
{
var url = input.ToStringValue();

var imageUrl = _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext.Request.PathBase, url);

return new ValueTask<FluidValue>(new StringValue(imageUrl ?? url));
}
}
}
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp.Web;
using SixLabors.ImageSharp.Web.Processors;

namespace OrchardCore.Media.Processing
{
public class ImageVersionProcessor : IImageWebProcessor
{
private static readonly IEnumerable<string> VersionCommands = new[] { "v" };

public IEnumerable<string> Commands => VersionCommands;

public FormattedImage Process(FormattedImage image, ILogger logger, IDictionary<string, string> commands)
=> image;
}
}
Expand Up @@ -17,15 +17,15 @@

namespace OrchardCore.Media.Processing
{
public class MediaFileProvider : IImageProvider
public class MediaResizingFileProvider : IImageProvider
{
public static int[] DefaultSizes = new[] { 16, 32, 50, 100, 160, 240, 480, 600, 1024, 2048 };

private readonly IMediaFileStore _mediaStore;
private readonly FormatUtilities _formatUtilities;
private readonly int[] _supportedSizes;

public MediaFileProvider(
public MediaResizingFileProvider(
IMediaFileStore mediaStore,
IOptions<ImageSharpMiddlewareOptions> options,
IShellConfiguration shellConfiguration)
Expand Down
37 changes: 36 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Media/README.md
Expand Up @@ -107,6 +107,18 @@ Resizes the image using the same functionality as `max` then removes any image a

`<img src="~/media/animals/kittens.jpg?width=100&height=240&rmode=crop" />`

### `append_version`

Appends a version hash for an asset. Can be piped together with the other media filters.

#### Input

`{{ 'animals/kittens.jpg' | asset_url | append_version | img_tag }}`

#### Output

`<img src="~/media/animals/kittens.jpg?v=Ailxbj_jQtYc9LRXKa21DygRzmQqc3OfN1XxSaQ3UWE" />`

## Razor Helpers

To obtain the correct URL for an asset, use the `AssetUrl` helper extension method on the view's base `Orchard` property, e.g.:
Expand All @@ -117,16 +129,39 @@ To obtain the correct URL for a resized asset use `AssetUrl` with the optional w

`@Orchard.AssetUrl(Model.Paths[0], width: 100 , height: 240, resizeMode: ResizeMode.Crop)`

To append a version hash for an asset use `AssetUrl` with the append version parameter, e.g.:

`@Orchard.AssetUrl(Model.Paths[0], appendVersion: true)`

or with resizing options as well, noting that the version hash is based on the source image

`@Orchard.AssetUrl(Model.Paths[0], width: 100 , height: 240, resizeMode: ResizeMode.Crop, appendVersion: true)`

### Razor image resizing tag helpers

To use the image tag helpers add `@addTagHelper *, OrchardCore.Media` to `_ViewImports.cshtml`. `asset-src` is used to obtain the correct URL for the asset and set the `src` attribute. Width, height and resize mode can be set using `img-width`, `img-height` and `img-resize-mode` respectively. e.g.:
To use the image tag helpers add `@addTagHelper *, OrchardCore.Media` to `_ViewImports.cshtml`.

`asset-src` is used to obtain the correct URL for the asset and set the `src` attribute. Width, height and resize mode can be set using `img-width`, `img-height` and `img-resize-mode` respectively. e.g.:

`<img asset-src="Model.Paths[0]" alt="..." img-width="100" img-height="240" img-resize-mode="Crop" />`

Alternatively the Asset Url can be resolved independently and the `src` attribute used:

`<img src="@Orchard.AssetUrl(Model.Paths[0])" alt="..." img-width="100" img-height="240" img-resize-mode="Crop" />`

### Razor append version
`asp-append-version` support is available on the OrchardCore tag helpers and MVC tag helpers.

`<img asset-src="Model.Paths[0]" alt="..." asp-append-version="true" />`

Alternatively the Asset Url can be resolved independently and the `src` attribute used:

`<img src="@Orchard.AssetUrl(Model.Paths[0])" alt="..." asp-append-version="true" />`

Or when using the MVC tag helpers and the image is resolved from static assets, i.e. wwwroot

`<img src="/favicon.ico" asp-append-version="true"/>`

> The Razor Helper is accessible on the `Orchard` property if the view is using Orchard Core's Razor base class, or by injecting `OrchardCore.IOrchardHelper` in all other cases.

## Deployment Step Editor
Expand Down
@@ -1,3 +1,4 @@
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore;
using OrchardCore.Media;
Expand All @@ -8,7 +9,7 @@ public static class OrchardRazorHelperExtensions
/// <summary>
/// Returns the relative URL of the specifier asset path with optional resizing parameters.
/// </summary>
public static string AssetUrl(this IOrchardHelper orchardHelper, string assetPath, int? width = null, int? height = null, ResizeMode resizeMode = ResizeMode.Undefined)
public static string AssetUrl(this IOrchardHelper orchardHelper, string assetPath, int? width = null, int? height = null, ResizeMode resizeMode = ResizeMode.Undefined, bool appendVersion = false)
{
var mediaFileStore = orchardHelper.HttpContext.RequestServices.GetService<IMediaFileStore>();

Expand All @@ -19,7 +20,15 @@ public static string AssetUrl(this IOrchardHelper orchardHelper, string assetPat

var resolvedAssetPath = mediaFileStore.MapPathToPublicUrl(assetPath);

return orchardHelper.ImageResizeUrl(resolvedAssetPath, width, height, resizeMode);
var resizedUrl = orchardHelper.ImageResizeUrl(resolvedAssetPath, width, height, resizeMode);

if (appendVersion)
{
var fileVersionProvider = orchardHelper.HttpContext.RequestServices.GetService<IFileVersionProvider>();

resizedUrl = fileVersionProvider.AddFileVersionToPath(orchardHelper.HttpContext.Request.PathBase, resizedUrl);
}
return resizedUrl;
}

/// <summary>
Expand Down
@@ -0,0 +1,18 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Physical;

namespace OrchardCore.Media.Services
{
public class MediaFileProvider : PhysicalFileProvider, IMediaFileProvider
{
public string VirtualPathBase { get; set; }
public MediaFileProvider(string virtualPathBase, string root) : base(root)
{
VirtualPathBase = virtualPathBase;
}
public MediaFileProvider(string virtualPathBase, string root, ExclusionFilters filters) : base(root, filters)
{
VirtualPathBase = virtualPathBase;
}
}
}
35 changes: 24 additions & 11 deletions src/OrchardCore.Modules/OrchardCore.Media/Startup.cs
Expand Up @@ -76,6 +76,25 @@ public Startup(IShellConfiguration shellConfiguration)

public override void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IMediaFileProvider>(serviceProvider =>
{
var shellOptions = serviceProvider.GetRequiredService<IOptions<ShellOptions>>();
var shellSettings = serviceProvider.GetRequiredService<ShellSettings>();

var mediaPath = GetMediaPath(shellOptions.Value, shellSettings);

if (!Directory.Exists(mediaPath))
{
Directory.CreateDirectory(mediaPath);
}
return new MediaFileProvider(AssetsUrlPrefix, mediaPath);
});

services.AddSingleton<IFileProvider>(serviceProvider =>
{
return serviceProvider.GetRequiredService<IMediaFileProvider>();
});

services.AddSingleton<IMediaFileStore>(serviceProvider =>
{
var shellOptions = serviceProvider.GetRequiredService<IOptions<ShellOptions>>();
Expand Down Expand Up @@ -107,6 +126,7 @@ public override void ConfigureServices(IServiceCollection services)
services.AddLiquidFilter<MediaUrlFilter>("asset_url");
services.AddLiquidFilter<ResizeUrlFilter>("resize_url");
services.AddLiquidFilter<ImageTagFilter>("img_tag");
services.AddLiquidFilter<AppendVersionFilter>("append_version");
deanmarcussen marked this conversation as resolved.
Show resolved Hide resolved

// ImageSharp

Expand Down Expand Up @@ -145,9 +165,10 @@ public override void ConfigureServices(IServiceCollection services)
.SetMemoryAllocator<ArrayPoolMemoryAllocator>()
.SetCache<PhysicalFileSystemCache>()
.SetCacheHash<CacheHash>()
.AddProvider<MediaFileProvider>()
.AddProvider<MediaResizingFileProvider>()
.AddProcessor<ResizeWebProcessor>()
.AddProcessor<FormatWebProcessor>()
.AddProcessor<ImageVersionProcessor>()
.AddProcessor<BackgroundColorWebProcessor>();

// Media Field
Expand All @@ -169,15 +190,7 @@ public override void ConfigureServices(IServiceCollection services)

public override void Configure(IApplicationBuilder app, IRouteBuilder routes, IServiceProvider serviceProvider)
{
var shellOptions = serviceProvider.GetRequiredService<IOptions<ShellOptions>>();
var shellSettings = serviceProvider.GetRequiredService<ShellSettings>();

var mediaPath = GetMediaPath(shellOptions.Value, shellSettings);

if (!Directory.Exists(mediaPath))
{
Directory.CreateDirectory(mediaPath);
}
var mediaFileProvider = serviceProvider.GetRequiredService<IMediaFileProvider>();

// ImageSharp before the static file provider
app.UseImageSharp();
Expand All @@ -186,7 +199,7 @@ public override void Configure(IApplicationBuilder app, IRouteBuilder routes, IS
{
// The tenant's prefix is already implied by the infrastructure
RequestPath = AssetsUrlPrefix,
FileProvider = new PhysicalFileProvider(mediaPath),
FileProvider = mediaFileProvider,
ServeUnknownFileTypes = true,
});
}
Expand Down
@@ -1,3 +1,5 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace OrchardCore.Media.TagHelpers
Expand All @@ -7,16 +9,39 @@ public class ImageTagHelper : TagHelper
{
private const string AssetSrcAttributeName = "asset-src";

private const string AppendVersionAttributeName = "append-version";

private readonly IMediaFileStore _mediaFileStore;

private readonly IFileVersionProvider _fileVersionProvider;

private readonly IHttpContextAccessor _httpContextAccessor;

//private string _pathBase;

public override int Order => -10;

[HtmlAttributeName(AssetSrcAttributeName)]
public string AssetSrc { get; set; }

public ImageTagHelper(IMediaFileStore mediaFileStore)
/// <summary>
/// Value indicating if file version should be appended to the src urls.
/// </summary>
/// <remarks>
/// If <c>true</c> then a query string "v" with the encoded content of the file is added.
/// </remarks>
[HtmlAttributeName(AppendVersionAttributeName)]
public bool AppendVersion { get; set; }

public ImageTagHelper(
IMediaFileStore mediaFileStore,
IHttpContextAccessor httpContextAccessor,
IFileVersionProvider fileVersionProvider
)
{
_mediaFileStore = mediaFileStore;
_httpContextAccessor = httpContextAccessor;
_fileVersionProvider = fileVersionProvider;
}

public override void Process(TagHelperContext context, TagHelperOutput output)
Expand All @@ -28,6 +53,11 @@ public override void Process(TagHelperContext context, TagHelperOutput output)

var resolvedSrc = _mediaFileStore != null ? _mediaFileStore.MapPathToPublicUrl(AssetSrc) : AssetSrc;
output.Attributes.SetAttribute("src", resolvedSrc);

if (AppendVersion && _fileVersionProvider != null)
{
output.Attributes.SetAttribute("src", _fileVersionProvider.AddFileVersionToPath(_httpContextAccessor.HttpContext.Request.PathBase, resolvedSrc));
}
}
}
}