Addressing breaking IFileSystem changes

@pranavkm
This commit is contained in:
Praburaj 2014-11-26 19:38:36 -08:00 committed by Pranav K
parent f75140765c
commit cfd5630cf2
16 changed files with 172 additions and 81 deletions

View File

@ -105,8 +105,8 @@ namespace Microsoft.AspNet.Mvc
return path; return path;
} }
IFileInfo fileInfo = null; var fileInfo = fileSystem.GetFileInfo(path);
if (fileSystem.TryGetFileInfo(path, out fileInfo)) if (fileInfo.Exists)
{ {
// The path is relative and IFileSystem found the file, so return the full // The path is relative and IFileSystem found the file, so return the full
// path. // path.

View File

@ -49,20 +49,27 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
var inheritedChunks = new List<Chunk>(); var inheritedChunks = new List<Chunk>();
var templateEngine = new RazorTemplateEngine(_razorHost); var templateEngine = new RazorTemplateEngine(_razorHost);
foreach (var viewStart in ViewStartUtility.GetViewStartLocations(_fileSystem, pagePath)) foreach (var viewStartPath in ViewStartUtility.GetViewStartLocations(pagePath))
{ {
CodeTree codeTree; CodeTree codeTree;
IFileInfo fileInfo;
if (_parsedCodeTrees.TryGetValue(viewStart, out codeTree)) if (_parsedCodeTrees.TryGetValue(viewStartPath, out codeTree))
{ {
inheritedChunks.AddRange(codeTree.Chunks); inheritedChunks.AddRange(codeTree.Chunks);
} }
else if (_fileSystem.TryGetFileInfo(viewStart, out fileInfo)) else
{ {
codeTree = ParseViewFile(templateEngine, fileInfo); var fileInfo = _fileSystem.GetFileInfo(viewStartPath);
_parsedCodeTrees.Add(viewStart, codeTree); if (fileInfo.Exists)
inheritedChunks.AddRange(codeTree.Chunks); {
// viewStartPath contains the app-relative path of the ViewStart.
// Since the parsing of a _ViewStart would cause parent _ViewStarts to be parsed
// we need to ensure the paths are app-relative to allow the GetViewStartLocations
// for the current _ViewStart to succeed.
codeTree = ParseViewFile(templateEngine, fileInfo, viewStartPath);
_parsedCodeTrees.Add(viewStartPath, codeTree);
inheritedChunks.AddRange(codeTree.Chunks);
}
} }
} }
@ -118,18 +125,19 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
} }
private static CodeTree ParseViewFile(RazorTemplateEngine engine, private static CodeTree ParseViewFile(RazorTemplateEngine engine,
IFileInfo fileInfo) IFileInfo fileInfo,
string viewStartPath)
{ {
using (var stream = fileInfo.CreateReadStream()) using (var stream = fileInfo.CreateReadStream())
{ {
using (var streamReader = new StreamReader(stream)) using (var streamReader = new StreamReader(stream))
{ {
var parseResults = engine.ParseTemplate(streamReader, fileInfo.PhysicalPath); var parseResults = engine.ParseTemplate(streamReader, viewStartPath);
var className = ParserHelpers.SanitizeClassName(fileInfo.Name); var className = ParserHelpers.SanitizeClassName(fileInfo.Name);
var language = engine.Host.CodeLanguage; var language = engine.Host.CodeLanguage;
var codeGenerator = language.CreateCodeGenerator(className, var codeGenerator = language.CreateCodeGenerator(className,
engine.Host.DefaultNamespace, engine.Host.DefaultNamespace,
fileInfo.PhysicalPath, viewStartPath,
engine.Host); engine.Host);
codeGenerator.Visit(parseResults); codeGenerator.Visit(parseResults);

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.AspNet.FileSystems;
namespace Microsoft.AspNet.Mvc.Razor namespace Microsoft.AspNet.Mvc.Razor
{ {
@ -27,41 +26,54 @@ namespace Microsoft.AspNet.Mvc.Razor
/// <summary> /// <summary>
/// Gets the view start locations that are applicable to the specified path. /// Gets the view start locations that are applicable to the specified path.
/// </summary> /// </summary>
/// <param name="applicationBase">The base of the application.</param> /// <param name="applicationRelativePath">The application relative path of the file to locate
/// <param name="path">The path to locate view starts for.</param> /// <c>_ViewStart</c>s for.</param>
/// <returns>A sequence of paths that represent potential view start locations.</returns> /// <returns>A sequence of paths that represent potential view start locations.</returns>
/// <remarks> /// <remarks>
/// This method returns paths starting from the directory of <paramref name="path"/> and moves /// This method returns paths starting from the directory of <paramref name="applicationRelativePath"/> and
/// upwards until it hits the application root. /// moves upwards until it hits the application root.
/// e.g. /// e.g.
/// /Views/Home/View.cshtml -> [ /Views/Home/_ViewStart.cshtml, /Views/_ViewStart.cshtml, /_ViewStart.cshtml ] /// /Views/Home/View.cshtml -> [ /Views/Home/_ViewStart.cshtml, /Views/_ViewStart.cshtml, /_ViewStart.cshtml ]
/// </remarks> /// </remarks>
public static IEnumerable<string> GetViewStartLocations(IFileSystem fileSystem, string path) public static IEnumerable<string> GetViewStartLocations(string applicationRelativePath)
{ {
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(applicationRelativePath))
{ {
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
if (path.StartsWith("~/", StringComparison.Ordinal))
if (applicationRelativePath.StartsWith("~/", StringComparison.Ordinal))
{ {
path = path.Substring(1); applicationRelativePath = applicationRelativePath.Substring(2);
} }
if (string.Equals(ViewStartFileName, Path.GetFileName(path), StringComparison.OrdinalIgnoreCase)) if (applicationRelativePath.StartsWith("/", StringComparison.Ordinal))
{
applicationRelativePath = applicationRelativePath.Substring(1);
}
if (Path.IsPathRooted(applicationRelativePath))
{
// If the path looks like it's app relative, don't attempt to construct _ViewStart paths.
return Enumerable.Empty<string>();
}
if (IsViewStart(applicationRelativePath))
{ {
// If the specified path is a ViewStart file, then the first view start that applies to it is the // If the specified path is a ViewStart file, then the first view start that applies to it is the
// parent view start. // parent view start.
if (!fileSystem.TryGetParentPath(path, out path)) applicationRelativePath = Path.GetDirectoryName(applicationRelativePath);
if (string.IsNullOrEmpty(applicationRelativePath))
{ {
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
} }
var viewStartLocations = new List<string>(); var viewStartLocations = new List<string>();
while (!string.IsNullOrEmpty(applicationRelativePath))
while (fileSystem.TryGetParentPath(path, out path))
{ {
var viewStartPath = Path.Combine(path, ViewStartFileName); applicationRelativePath = Path.GetDirectoryName(applicationRelativePath);
var viewStartPath = Path.Combine(applicationRelativePath, ViewStartFileName);
viewStartLocations.Add(viewStartPath); viewStartLocations.Add(viewStartPath);
} }

View File

@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.Razor
} }
else else
{ {
_fileSystem.TryGetFileInfo(virtualPath, out fileInfo); fileInfo = _fileSystem.GetFileInfo(virtualPath);
expiringFileInfo = new ExpiringFileInfo() expiringFileInfo = new ExpiringFileInfo()
{ {

View File

@ -77,10 +77,10 @@ namespace Microsoft.AspNet.Mvc.Razor
private IEnumerable<RelativeFileInfo> GetFileInfosRecursive(string currentPath) private IEnumerable<RelativeFileInfo> GetFileInfosRecursive(string currentPath)
{ {
IEnumerable<IFileInfo> fileInfos;
string path = currentPath; string path = currentPath;
if (!_fileSystem.TryGetDirectoryContents(path, out fileInfos)) var fileInfos = _fileSystem.GetDirectoryContents(path);
if (!fileInfos.Exists)
{ {
yield break; yield break;
} }

View File

@ -4,28 +4,23 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNet.FileSystems;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc.Razor namespace Microsoft.AspNet.Mvc.Razor
{ {
/// <inheritdoc /> /// <inheritdoc />
public class ViewStartProvider : IViewStartProvider public class ViewStartProvider : IViewStartProvider
{ {
private readonly IFileSystem _fileSystem;
private readonly IRazorPageFactory _pageFactory; private readonly IRazorPageFactory _pageFactory;
public ViewStartProvider(IRazorPageFactory pageFactory, public ViewStartProvider(IRazorPageFactory pageFactory)
IOptions<RazorViewEngineOptions> optionsAccessor)
{ {
_fileSystem = optionsAccessor.Options.FileSystem;
_pageFactory = pageFactory; _pageFactory = pageFactory;
} }
/// <inheritdoc /> /// <inheritdoc />
public IEnumerable<IRazorPage> GetViewStartPages([NotNull] string path) public IEnumerable<IRazorPage> GetViewStartPages([NotNull] string path)
{ {
var viewStartLocations = ViewStartUtility.GetViewStartLocations(_fileSystem, path); var viewStartLocations = ViewStartUtility.GetViewStartLocations(path);
var viewStarts = viewStartLocations.Select(_pageFactory.CreateInstance) var viewStarts = viewStartLocations.Select(_pageFactory.CreateInstance)
.Where(p => p != null) .Where(p => p != null)
.ToArray(); .ToArray();

View File

@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var fileInfo = _fileInfoCache.GetFileInfo(relativePath); var fileInfo = _fileInfoCache.GetFileInfo(relativePath);
if (fileInfo != null) if (fileInfo.Exists)
{ {
var relativeFileInfo = new RelativeFileInfo() var relativeFileInfo = new RelativeFileInfo()
{ {

View File

@ -215,5 +215,26 @@ component-content";
// Assert // Assert
Assert.Equal(expected, body.Trim()); Assert.Equal(expected, body.Trim());
} }
// Inheritance of chunks in _ViewStart is affected by paths being app-relative and not absolute.
// This change ensures that _ViewStart files correctly inherits directives from parent _ViewStarts
// which guarantees that paths flow correctly through MvcRazorHost.
[Fact]
public async Task ViewStartsCanUseDirectivesInjectedFromParentViewStarts()
{
// Arrange
var expected =
@"<view-start>Hello Controller-Person</view-start>
<page>Hello Controller-Person</page>";
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
var target = "http://localhost/NestedViewStarts/NestedViewStartUsingParentDirectives";
// Act
var body = await client.GetStringAsync(target);
// Assert
Assert.Equal(expected, body.Trim());
}
} }
} }

View File

@ -13,10 +13,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
{ {
// Arrange // Arrange
var fileSystem = new TestFileSystem(); var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\views\accounts\_viewstart.cshtml", "@using AccountModels"); fileSystem.AddFile(@"views\accounts\_viewstart.cshtml", "@using AccountModels");
fileSystem.AddFile(@"x:\myapproot\views\Shared\_viewstart.cshtml", "@inject SharedHelper Shared"); fileSystem.AddFile(@"views\Shared\_viewstart.cshtml", "@inject SharedHelper Shared");
fileSystem.AddFile(@"x:\myapproot\views\home\_viewstart.cshtml", "@using MyNamespace"); fileSystem.AddFile(@"views\home\_viewstart.cshtml", "@using MyNamespace");
fileSystem.AddFile(@"x:\myapproot\views\_viewstart.cshtml", fileSystem.AddFile(@"views\_viewstart.cshtml",
@"@inject MyHelper<TModel> Helper @"@inject MyHelper<TModel> Helper
@inherits MyBaseType @inherits MyBaseType
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
var utility = new ChunkInheritanceUtility(host, fileSystem, new Chunk[0]); var utility = new ChunkInheritanceUtility(host, fileSystem, new Chunk[0]);
// Act // Act
var chunks = utility.GetInheritedChunks(@"x:\myapproot\views\home\Index.cshtml"); var chunks = utility.GetInheritedChunks(@"views\home\Index.cshtml");
// Assert // Assert
Assert.Equal(8, chunks.Count); Assert.Equal(8, chunks.Count);
@ -57,14 +57,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
{ {
// Arrange // Arrange
var fileSystem = new TestFileSystem(); var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\_viewstart.cs", string.Empty); fileSystem.AddFile(@"_viewstart.cs", string.Empty);
fileSystem.AddFile(@"x:\myapproot\views\_Layout.cshtml", string.Empty); fileSystem.AddFile(@"views\_Layout.cshtml", string.Empty);
fileSystem.AddFile(@"x:\myapproot\views\home\_not-viewstart.cshtml", string.Empty); fileSystem.AddFile(@"views\home\_not-viewstart.cshtml", string.Empty);
var host = new MvcRazorHost(fileSystem); var host = new MvcRazorHost(fileSystem);
var utility = new ChunkInheritanceUtility(host, fileSystem, new Chunk[0]); var utility = new ChunkInheritanceUtility(host, fileSystem, new Chunk[0]);
// Act // Act
var chunks = utility.GetInheritedChunks(@"x:\myapproot\views\home\Index.cshtml"); var chunks = utility.GetInheritedChunks(@"views\home\Index.cshtml");
// Assert // Assert
Assert.Empty(chunks); Assert.Empty(chunks);
@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
{ {
// Arrange // Arrange
var fileSystem = new TestFileSystem(); var fileSystem = new TestFileSystem();
fileSystem.AddFile(@"x:\myapproot\views\_viewstart.cshtml", fileSystem.AddFile(@"views\_viewstart.cshtml",
"@inject DifferentHelper<TModel> Html"); "@inject DifferentHelper<TModel> Html");
var host = new MvcRazorHost(fileSystem); var host = new MvcRazorHost(fileSystem);
var defaultChunks = new Chunk[] var defaultChunks = new Chunk[]
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
var utility = new ChunkInheritanceUtility(host, fileSystem, defaultChunks); var utility = new ChunkInheritanceUtility(host, fileSystem, defaultChunks);
// Act // Act
var chunks = utility.GetInheritedChunks(@"x:\myapproot\views\home\Index.cshtml"); var chunks = utility.GetInheritedChunks(@"views\Home\Index.cshtml");
// Assert // Assert
Assert.Equal(4, chunks.Count); Assert.Equal(4, chunks.Count);

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.Razor
private readonly Dictionary<string, IFileInfo> _lookup = private readonly Dictionary<string, IFileInfo> _lookup =
new Dictionary<string, IFileInfo>(StringComparer.Ordinal); new Dictionary<string, IFileInfo>(StringComparer.Ordinal);
public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents) public IDirectoryContents GetDirectoryContents(string subpath)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -29,6 +29,8 @@ namespace Microsoft.AspNet.Mvc.Razor
.Returns(path); .Returns(path);
fileInfo.SetupGet(f => f.Name) fileInfo.SetupGet(f => f.Name)
.Returns(Path.GetFileName(path)); .Returns(Path.GetFileName(path));
fileInfo.SetupGet(f => f.Exists)
.Returns(true);
AddFile(path, fileInfo.Object); AddFile(path, fileInfo.Object);
} }
@ -37,15 +39,16 @@ namespace Microsoft.AspNet.Mvc.Razor
_lookup.Add(path, contents); _lookup.Add(path, contents);
} }
public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo) public IFileInfo GetFileInfo(string subpath)
{ {
return _lookup.TryGetValue(subpath, out fileInfo); if (_lookup.ContainsKey(subpath))
} {
return _lookup[subpath];
public bool TryGetParentPath(string subpath, out string parentPath) }
{ else
parentPath = Path.GetDirectoryName(subpath); {
return !string.IsNullOrEmpty(parentPath); return new NotFoundFileInfo(subpath);
}
} }
} }
} }

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.Razor
public void GetViewStartLocations_ReturnsEmptySequenceIfViewPathIsEmpty(string viewPath) public void GetViewStartLocations_ReturnsEmptySequenceIfViewPathIsEmpty(string viewPath)
{ {
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(new TestFileSystem(), viewPath); var result = ViewStartUtility.GetViewStartLocations(viewPath);
// Assert // Assert
Assert.Empty(result); Assert.Empty(result);
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Razor
[InlineData("/views/Home/MyView.cshtml")] [InlineData("/views/Home/MyView.cshtml")]
[InlineData("~/views/Home/MyView.cshtml")] [InlineData("~/views/Home/MyView.cshtml")]
[InlineData("views/Home/MyView.cshtml")] [InlineData("views/Home/MyView.cshtml")]
public void GetViewStartLocations_ReturnsPotentialViewStartLocations(string inputPath) public void GetViewStartLocations_ReturnsPotentialViewStartLocations_PathStartswithSlash(string inputPath)
{ {
// Arrange // Arrange
var expected = new[] var expected = new[]
@ -36,10 +36,9 @@ namespace Microsoft.AspNet.Mvc.Razor
@"views\_viewstart.cshtml", @"views\_viewstart.cshtml",
@"_viewstart.cshtml" @"_viewstart.cshtml"
}; };
var fileSystem = new PhysicalFileSystem(GetTestFileSystemBase());
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, inputPath); var result = ViewStartUtility.GetViewStartLocations(inputPath);
// Assert // Assert
Assert.Equal(expected, result); Assert.Equal(expected, result);
@ -60,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var fileSystem = new PhysicalFileSystem(GetTestFileSystemBase()); var fileSystem = new PhysicalFileSystem(GetTestFileSystemBase());
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, inputPath); var result = ViewStartUtility.GetViewStartLocations(inputPath);
// Assert // Assert
Assert.Equal(expected, result); Assert.Equal(expected, result);
@ -69,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor
[Theory] [Theory]
[InlineData("Test.cshtml")] [InlineData("Test.cshtml")]
[InlineData("ViewStart.cshtml")] [InlineData("ViewStart.cshtml")]
public void GetViewStartLocations_ReturnsPotentialViewStartLocations_IfPathIsAbsolute(string fileName) public void GetViewStartLocations_ReturnsPotentialViewStartLocations(string fileName)
{ {
// Arrange // Arrange
var expected = new[] var expected = new[]
@ -81,12 +80,10 @@ namespace Microsoft.AspNet.Mvc.Razor
@"Areas\_viewstart.cshtml", @"Areas\_viewstart.cshtml",
@"_viewstart.cshtml", @"_viewstart.cshtml",
}; };
var appBase = GetTestFileSystemBase(); var viewPath = Path.Combine("Areas", "MyArea", "Sub", "Views", "Admin", fileName);
var viewPath = Path.Combine(appBase, "Areas", "MyArea", "Sub", "Views", "Admin", fileName);
var fileSystem = new PhysicalFileSystem(appBase);
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, viewPath); var result = ViewStartUtility.GetViewStartLocations(viewPath);
// Assert // Assert
Assert.Equal(expected, result); Assert.Equal(expected, result);
@ -95,7 +92,7 @@ namespace Microsoft.AspNet.Mvc.Razor
[Theory] [Theory]
[InlineData("_ViewStart.cshtml")] [InlineData("_ViewStart.cshtml")]
[InlineData("_viewstart.cshtml")] [InlineData("_viewstart.cshtml")]
public void GetViewStartLocations_SkipsCurrentPath_IfAbsolutePathIsAViewStartFile(string fileName) public void GetViewStartLocations_SkipsCurrentPath_IfPathIsAViewStartFile(string fileName)
{ {
// Arrange // Arrange
var expected = new[] var expected = new[]
@ -106,12 +103,10 @@ namespace Microsoft.AspNet.Mvc.Razor
@"Areas\_viewstart.cshtml", @"Areas\_viewstart.cshtml",
@"_viewstart.cshtml", @"_viewstart.cshtml",
}; };
var appBase = GetTestFileSystemBase(); var viewPath = Path.Combine("Areas", "MyArea", "Sub", "Views", "Admin", fileName);
var viewPath = Path.Combine(appBase, "Areas", "MyArea", "Sub", "Views", "Admin", fileName);
var fileSystem = new PhysicalFileSystem(appBase);
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, viewPath); var result = ViewStartUtility.GetViewStartLocations(viewPath);
// Assert // Assert
Assert.Equal(expected, result); Assert.Equal(expected, result);
@ -123,10 +118,23 @@ namespace Microsoft.AspNet.Mvc.Razor
// Arrange // Arrange
var appBase = GetTestFileSystemBase(); var appBase = GetTestFileSystemBase();
var viewPath = "_viewstart.cshtml"; var viewPath = "_viewstart.cshtml";
var fileSystem = new PhysicalFileSystem(appBase);
// Act // Act
var result = ViewStartUtility.GetViewStartLocations(fileSystem, viewPath); var result = ViewStartUtility.GetViewStartLocations(viewPath);
// Assert
Assert.Empty(result);
}
[Fact]
public void GetViewStartLocations_ReturnsEmptySequence_IfPathIsRooted()
{
// Arrange
var appBase = GetTestFileSystemBase();
var absolutePath = Path.Combine(Directory.GetCurrentDirectory(), "Index.cshtml");
// Act
var result = ViewStartUtility.GetViewStartLocations(absolutePath);
// Assert // Assert
Assert.Empty(result); Assert.Empty(result);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.AspNet.FileSystems; using Microsoft.AspNet.FileSystems;
using Microsoft.Framework.Expiration.Interfaces;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -354,28 +355,25 @@ namespace Microsoft.AspNet.Mvc.Razor
} }
} }
public bool TryGetDirectoryContents(string subpath, out IEnumerable<IFileInfo> contents) public IDirectoryContents GetDirectoryContents(string subpath)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public bool TryGetFileInfo(string subpath, out IFileInfo fileInfo) public IFileInfo GetFileInfo(string subpath)
{ {
IFileInfo knownInfo; IFileInfo knownInfo;
if (_fileInfos.TryGetValue(subpath, out knownInfo)) if (_fileInfos.TryGetValue(subpath, out knownInfo))
{ {
fileInfo = new DummyFileInfo() return new DummyFileInfo()
{ {
Name = knownInfo.Name, Name = knownInfo.Name,
LastModified = knownInfo.LastModified, LastModified = knownInfo.LastModified,
}; };
return true;
} }
else else
{ {
fileInfo = null; return new NotFoundFileInfo(subpath);
return false;
} }
} }
@ -393,7 +391,39 @@ namespace Microsoft.AspNet.Mvc.Razor
public long Length { get { throw new NotImplementedException(); } } public long Length { get { throw new NotImplementedException(); } }
public bool IsDirectory { get { throw new NotImplementedException(); } } public bool IsDirectory { get { throw new NotImplementedException(); } }
public string PhysicalPath { get { throw new NotImplementedException(); } } public string PhysicalPath { get { throw new NotImplementedException(); } }
public bool Exists
{
get
{
throw new NotImplementedException();
}
}
public bool IsReadOnly
{
get
{
throw new NotImplementedException();
}
}
public Stream CreateReadStream() { throw new NotImplementedException(); } public Stream CreateReadStream() { throw new NotImplementedException(); }
public void WriteContent(byte[] content)
{
throw new NotImplementedException();
}
public void Delete()
{
throw new NotImplementedException();
}
public IExpirationTrigger CreateFileChangeTrigger()
{
throw new NotImplementedException();
}
} }
} }
} }

View File

@ -11,5 +11,15 @@ namespace RazorWebSite.Controllers
{ {
return View("NestedViewStarts/Index"); return View("NestedViewStarts/Index");
} }
public ViewResult NestedViewStartUsingParentDirectives()
{
var model = new Person
{
Name = "Controller-Person"
};
return View("~/Views/NestedViewStartUsingParentDirectives/Nested/Index.cshtml", model);
}
} }
} }

View File

@ -0,0 +1 @@
<page>@MyInjectedHelper.Greet(Model)</page>

View File

@ -0,0 +1,2 @@
@model Person
<view-start>@MyInjectedHelper.Greet(Model)</view-start>

View File

@ -0,0 +1 @@
@inject InjectedHelper MyInjectedHelper