Make _PageImports work
Add support for generating the Model property
This commit is contained in:
parent
78046c0706
commit
624909763b
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
namespace MvcSandbox
|
||||
{
|
||||
public class TestModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
@page Test
|
||||
@model TestModel
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
@using MvcSandbox
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue