Watch _ViewImports outside the pages root for changes

Fixes #6428
This commit is contained in:
Pranav K 2017-06-26 09:21:33 -07:00
parent d278d6eedf
commit 9acfc8d221
3 changed files with 81 additions and 6 deletions

View File

@ -43,6 +43,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private IChangeToken GetCompositeChangeToken()
{
if (_actionDescriptorChangeProviders.Length == 1)
{
return _actionDescriptorChangeProviders[0].GetChangeToken();
}
var changeTokens = new IChangeToken[_actionDescriptorChangeProviders.Length];
for (var i = 0; i < _actionDescriptorChangeProviders.Length; i++)
{

View File

@ -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;
@ -14,11 +17,18 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
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));
@ -30,9 +40,35 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
}
_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";
}
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);
}
}
}

View File

@ -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;
@ -14,13 +17,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
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();
@ -35,14 +41,17 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
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();
@ -50,5 +59,30 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// 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));
}
}
}