Make _PageImports work

Add support for generating the Model property
This commit is contained in:
Pranav K 2017-02-07 11:00:10 -08:00
parent 78046c0706
commit 624909763b
10 changed files with 159 additions and 19 deletions

View File

@ -0,0 +1 @@


View File

@ -0,0 +1,9 @@

namespace MvcSandbox
{
public class TestModel
{
public string Name { get; set; }
}
}

View File

@ -1,4 +1,5 @@
@page Test
@model TestModel
<div class="row">
<div class="col-md-3">

View File

@ -0,0 +1 @@
@using MvcSandbox

View File

@ -0,0 +1,61 @@
// 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.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Host
{
public class PagesPropertyInjectionPass : IRazorIRPass
{
public RazorEngine Engine { get; set; }
public int Order => RazorIRPass.LoweringOrder;
public DocumentIRNode Execute(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
if (irDocument.DocumentKind != RazorPageDocumentClassifier.DocumentKind)
{
return irDocument;
}
var modelType = ModelDirective.GetModelType(irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
var @class = visitor.Class;
var viewDataType = $"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<{modelType}>";
var vddProperty = new CSharpStatementIRNode
{
Content = $"public {viewDataType} ViewData => ({viewDataType})PageContext?.ViewData;",
Parent = @class,
};
var modelProperty = new CSharpStatementIRNode
{
Content = $"public {modelType} Model => ViewData.Model;",
Parent = @class,
};
@class.Children.Add(vddProperty);
@class.Children.Add(modelProperty);
return irDocument;
}
private class Visitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Class { get; private set; }
public override void VisitClass(ClassDeclarationIRNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClass(node);
}
}
}
}

View File

@ -186,6 +186,7 @@ namespace Microsoft.Extensions.DependencyInjection
PageDirective.Register(b);
b.Features.Add(new ModelExpressionPass());
b.Features.Add(new PagesPropertyInjectionPass());
b.Features.Add(new ViewComponentTagHelperPass());
b.Features.Add(new RazorPageDocumentClassifier());
b.Features.Add(new MvcViewDocumentClassifierPass());

View File

@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
internal static class MvcRazorLoggerExtensions
public static class MvcRazorLoggerExtensions
{
private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency;

View File

@ -9,8 +9,6 @@ using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.CodeGenerators;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
@ -27,7 +25,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
private readonly RazorProject _project;
private readonly IFileProvider _fileProvider;
private readonly ILogger _logger;
private readonly RazorSourceDocument _globalImports;
/// <summary>
/// Instantiates a new instance of the <see cref="RazorCompilationService"/> class.
@ -68,10 +65,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
writer.Flush();
stream.Seek(0L, SeekOrigin.Begin);
_globalImports = RazorSourceDocument.ReadFrom(stream, filename: null, encoding: Encoding.UTF8);
GlobalImports = RazorSourceDocument.ReadFrom(stream, filename: null, encoding: Encoding.UTF8);
}
public RazorSourceDocument GlobalImports { get; }
/// <inheritdoc />
public CompilationResult Compile(RelativeFileInfo file)
@ -97,7 +94,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
if (cSharpDocument.Diagnostics.Count > 0)
{
return GetCompilationFailedResult(file, cSharpDocument.Diagnostics);
return GetCompilationFailedResult(file.RelativePath, cSharpDocument.Diagnostics);
}
return _compilationService.Compile(codeDocument, cSharpDocument);
@ -111,7 +108,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
var imports = new List<RazorSourceDocument>()
{
_globalImports,
GlobalImports,
};
var paths = ViewHierarchyUtility.GetViewImportsLocations(relativePath);
@ -138,15 +135,15 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
}
// Internal for unit testing
internal CompilationResult GetCompilationFailedResult(
RelativeFileInfo file,
public CompilationResult GetCompilationFailedResult(
string relativePath,
IEnumerable<Microsoft.AspNetCore.Razor.Evolution.Legacy.RazorError> errors)
{
// If a SourceLocation does not specify a file path, assume it is produced
// from parsing the current file.
var messageGroups = errors
.GroupBy(razorError =>
razorError.Location.FilePath ?? file.RelativePath,
razorError.Location.FilePath ?? relativePath,
StringComparer.Ordinal);
var failures = new List<CompilationFailure>();

View File

@ -2,24 +2,35 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
public class DefaultPageLoader : IPageLoader
{
private readonly IRazorCompilationService _razorCompilationService;
private readonly RazorCompilationService _razorCompilationService;
private readonly ICompilationService _compilationService;
private readonly RazorProject _project;
private readonly ILogger _logger;
public DefaultPageLoader(
IRazorCompilationService razorCompilationService,
RazorProject razorProject)
ICompilationService compilationService,
RazorProject razorProject,
ILogger<DefaultPageLoader> logger)
{
_razorCompilationService = razorCompilationService;
_razorCompilationService = (RazorCompilationService)razorCompilationService;
_compilationService = compilationService;
_project = razorProject;
_logger = logger;
}
public Type Load(PageActionDescriptor actionDescriptor)
@ -30,11 +41,70 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
throw new InvalidOperationException($"File {actionDescriptor.RelativePath} was not found.");
}
var projectItem = (DefaultRazorProjectItem)item;
var compilationResult = _razorCompilationService.Compile(new RelativeFileInfo(projectItem.FileInfo, item.Path));
compilationResult.EnsureSuccessful();
RazorCodeDocument codeDocument;
RazorCSharpDocument cSharpDocument;
_logger.RazorFileToCodeCompilationStart(item.Path);
var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0;
codeDocument = CreateCodeDocument(item);
cSharpDocument = _razorCompilationService.ProcessCodeDocument(codeDocument);
_logger.RazorFileToCodeCompilationEnd(item.Path, startTimestamp);
CompilationResult compilationResult;
if (cSharpDocument.Diagnostics.Count > 0)
{
compilationResult = _razorCompilationService.GetCompilationFailedResult(item.Path, cSharpDocument.Diagnostics);
}
else
{
compilationResult = _compilationService.Compile(codeDocument, cSharpDocument);
}
compilationResult.EnsureSuccessful();
return compilationResult.CompiledType;
}
private RazorCodeDocument CreateCodeDocument(RazorProjectItem item)
{
var absolutePath = GetItemPath(item);
RazorSourceDocument source;
using (var inputStream = item.Read())
{
source = RazorSourceDocument.ReadFrom(inputStream, absolutePath);
}
var imports = new List<RazorSourceDocument>()
{
_razorCompilationService.GlobalImports,
};
var pageImports = _project.FindHierarchicalItems(item.Path, "_PageImports.cshtml");
foreach (var pageImport in pageImports.Reverse())
{
if (pageImport.Exists)
{
using (var stream = pageImport.Read())
{
imports.Add(RazorSourceDocument.ReadFrom(stream, GetItemPath(item)));
}
}
}
return RazorCodeDocument.Create(source, imports);
}
private static string GetItemPath(RazorProjectItem item)
{
var absolutePath = item.Path;
if (item.Exists && string.IsNullOrEmpty(item.PhysicalPath))
{
absolutePath = item.PhysicalPath;
}
return absolutePath;
}
}
}

View File

@ -157,7 +157,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
var fileProvider = new TestFileProvider();
var file = fileProvider.AddFile(viewPath, "View Content");
fileProvider.AddFile(viewImportsPath, "Global Import Content");
var relativeFileInfo = new RelativeFileInfo(file, viewPath);
var razorService = new RazorCompilationService(
Mock.Of<ICompilationService>(),
Mock.Of<RazorEngine>(),
@ -173,7 +172,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
};
// Act
var result = razorService.GetCompilationFailedResult(relativeFileInfo, errors);
var result = razorService.GetCompilationFailedResult(viewPath, errors);
// Assert
Assert.NotNull(result.CompilationFailures);