Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Invalidate PageActionInvokerProvider cache when compilation cache expires #6438

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public ActionDescriptorCollectionProvider(

private IChangeToken GetCompositeChangeToken()
{
if (_actionDescriptorChangeProviders.Length == 1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just seemed sensible not to have nested CompositeChangeTokens in the most common case.

{
return _actionDescriptorChangeProviders[0].GetChangeToken();
}

var changeTokens = new IChangeToken[_actionDescriptorChangeProviders.Length];
for (var i = 0; i < _actionDescriptorChangeProviders.Length; i++)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
Expand All @@ -14,11 +17,18 @@ public class PageActionDescriptorChangeProvider : IActionDescriptorChangeProvide
{
private readonly IFileProvider _fileProvider;
private readonly string _searchPattern;
private readonly string[] _additionalFilesToTrack;

public PageActionDescriptorChangeProvider(
RazorTemplateEngine templateEngine,
IRazorViewEngineFileProviderAccessor fileProviderAccessor,
IOptions<RazorPagesOptions> razorPagesOptions)
{
if (templateEngine == null)
{
throw new ArgumentNullException(nameof(templateEngine));
}

if (fileProviderAccessor == null)
{
throw new ArgumentNullException(nameof(fileProviderAccessor));
Expand All @@ -30,9 +40,33 @@ public PageActionDescriptorChangeProvider(
}

_fileProvider = fileProviderAccessor.FileProvider;
_searchPattern = razorPagesOptions.Value.RootDirectory.TrimEnd('/') + "/**/*.cshtml";
var rootDirectory = razorPagesOptions.Value.RootDirectory;
Debug.Assert(!string.IsNullOrEmpty(rootDirectory));
rootDirectory = rootDirectory.TrimEnd('/');
var importFileAtPagesRoot = rootDirectory + "/" + templateEngine.Options.ImportsFileName;
_additionalFilesToTrack = templateEngine.GetImportItems(importFileAtPagesRoot)
.Select(item => item.Path)
.ToArray();

_searchPattern = rootDirectory + "/**/*.cshtml";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this breathe a bit?

}

public IChangeToken GetChangeToken() => _fileProvider.Watch(_searchPattern);
public IChangeToken GetChangeToken()
{
var wildcardChangeToken = _fileProvider.Watch(_searchPattern);
if (_additionalFilesToTrack.Length == 0)
{
return wildcardChangeToken;
}

var changeTokens = new IChangeToken[_additionalFilesToTrack.Length + 1];
for (var i = 0; i < _additionalFilesToTrack.Length; i++)
{
changeTokens[i] = _fileProvider.Watch(_additionalFilesToTrack[i]);
}

changeTokens[changeTokens.Length - 1] = wildcardChangeToken;
return new CompositeChangeToken(changeTokens);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using Moq;
using Xunit;

Expand All @@ -14,13 +17,16 @@ public class PageActionDescriptorChangeProviderTest
public void GetChangeToken_WatchesAllCshtmlFilesUnderFileSystemRoot()
{
// Arrange
var options = new TestOptionsManager<RazorPagesOptions>();
var fileProvider = new Mock<IFileProvider>();
var templateEngine = new RazorTemplateEngine(
RazorEngine.Create(),
new FileProviderRazorProject(fileProvider.Object));
var options = new TestOptionsManager<RazorPagesOptions>();
var fileProviderAccessor = new Mock<IRazorViewEngineFileProviderAccessor>();
fileProviderAccessor
.Setup(f => f.FileProvider)
.Returns(fileProvider.Object);
var changeProvider = new PageActionDescriptorChangeProvider(fileProviderAccessor.Object, options);
var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, fileProviderAccessor.Object, options);

// Act
var changeToken = changeProvider.GetChangeToken();
Expand All @@ -35,20 +41,48 @@ public void GetChangeToken_WatchesAllCshtmlFilesUnderFileSystemRoot()
public void GetChangeToken_WatchesAllCshtmlFilesUnderSpecifiedRootDirectory(string rootDirectory)
{
// Arrange
var fileProvider = new Mock<IFileProvider>();
var templateEngine = new RazorTemplateEngine(
RazorEngine.Create(),
new FileProviderRazorProject(fileProvider.Object));
var options = new TestOptionsManager<RazorPagesOptions>();
options.Value.RootDirectory = rootDirectory;
var fileProvider = new Mock<IFileProvider>();
var fileProviderAccessor = new Mock<IRazorViewEngineFileProviderAccessor>();
fileProviderAccessor
.Setup(f => f.FileProvider)
.Returns(fileProvider.Object);
var changeProvider = new PageActionDescriptorChangeProvider(fileProviderAccessor.Object, options);
var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, fileProviderAccessor.Object, options);

// Act
var changeToken = changeProvider.GetChangeToken();

// Assert
fileProvider.Verify(f => f.Watch("/pages-base-dir/**/*.cshtml"));
}

[Fact]
public void GetChangeToken_WatchesViewImportsOutsidePagesRoot()
{
// Arrange
var fileProvider = new TestFileProvider();
var templateEngine = new RazorTemplateEngine(
RazorEngine.Create(),
new FileProviderRazorProject(fileProvider));
templateEngine.Options.ImportsFileName = "_ViewImports.cshtml";
var options = new TestOptionsManager<RazorPagesOptions>();
options.Value.RootDirectory = "/dir1/dir2";
var fileProviderAccessor = new Mock<IRazorViewEngineFileProviderAccessor>();
fileProviderAccessor
.Setup(f => f.FileProvider)
.Returns(fileProvider);
var changeProvider = new PageActionDescriptorChangeProvider(templateEngine, fileProviderAccessor.Object, options);

// Act & Assert
var compositeChangeToken = Assert.IsType<CompositeChangeToken>(changeProvider.GetChangeToken());
Assert.Collection(compositeChangeToken.ChangeTokens,
changeToken => Assert.Same(fileProvider.GetChangeToken("/dir1/_ViewImports.cshtml"), changeToken),
changeToken => Assert.Same(fileProvider.GetChangeToken("/_ViewImports.cshtml"), changeToken),
changeToken => Assert.Same(fileProvider.GetChangeToken("/dir1/dir2/**/*.cshtml"), changeToken));
}
}
}