CodeGen RouteTemplate as a RazorCompiledItemAttribute

This commit is contained in:
Pranav K 2018-03-14 21:47:04 -07:00
parent 767e5a12c3
commit 7ff56dadf4
17 changed files with 573 additions and 12 deletions

View File

@ -13,16 +13,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpy
internal static string ArgumentCannotBeNullOrEmpty
{
get => GetString("ArgumentCannotBeNullOrEmpy");
get => GetString("ArgumentCannotBeNullOrEmpty");
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpy()
=> GetString("ArgumentCannotBeNullOrEmpy");
internal static string FormatArgumentCannotBeNullOrEmpty()
=> GetString("ArgumentCannotBeNullOrEmpty");
/// <summary>
/// Inject a service from the application's service container into a property.

View File

@ -3,6 +3,7 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
@ -10,6 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public class RazorPageDocumentClassifierPass : DocumentClassifierPassBase
{
public static readonly string RazorPageDocumentKind = "mvc.1.0.razor-page";
public static readonly string RouteTemplateKey = "RouteTemplate";
protected override string DocumentKind => RazorPageDocumentKind;
@ -43,14 +45,38 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
method.Modifiers.Add("override");
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
EnsureValidPageDirective(codeDocument);
}
private void EnsureValidPageDirective(RazorCodeDocument codeDocument)
{
var document = codeDocument.GetDocumentIntermediateNode();
PageDirective.TryGetPageDirective(document, out var pageDirective);
EnsureValidPageDirective(pageDirective);
AddRouteTemplateMetadataAttribute(@namespace, @class, pageDirective);
}
private static void AddRouteTemplateMetadataAttribute(NamespaceDeclarationIntermediateNode @namespace, ClassDeclarationIntermediateNode @class, PageDirective pageDirective)
{
if (string.IsNullOrEmpty(pageDirective.RouteTemplate))
{
return;
}
var classIndex = @namespace.Children.IndexOf(@class);
if (classIndex == -1)
{
return;
}
var metadataAttributeNode = new RazorCompiledItemMetadataAttributeIntermediateNode
{
Key = RouteTemplateKey,
Value = pageDirective.RouteTemplate,
};
// Metadata attributes need to be inserted right before the class declaration.
@namespace.Children.Insert(classIndex, metadataAttributeNode);
}
private void EnsureValidPageDirective(PageDirective pageDirective)
{
Debug.Assert(pageDirective != null);
if (pageDirective.DirectiveNode.IsImported())

View File

@ -117,7 +117,7 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentCannotBeNullOrEmpy" xml:space="preserve">
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>Value cannot be null or empty.</value>
</data>
<data name="InjectDirective_Description" xml:space="preserve">

View File

@ -10,5 +10,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
void WriteRazorCompiledItemAttribute(CodeRenderingContext context, RazorCompiledItemAttributeIntermediateNode node);
void WriteRazorSourceChecksumAttribute(CodeRenderingContext context, RazorSourceChecksumAttributeIntermediateNode node);
void WriteRazorCompiledItemMetadataAttribute(CodeRenderingContext context, RazorCompiledItemMetadataAttributeIntermediateNode node);
}
}

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
protected override void OnInitialized()
{
_identifierFeature = Engine.Features.OfType<IMetadataIdentifierFeature>().FirstOrDefault();
_identifierFeature = Engine.Features.OfType<IMetadataIdentifierFeature>().FirstOrDefault();
}
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)

View File

@ -12,6 +12,9 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
public string SourceChecksumAttributeName { get; set; } = "global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute";
public string CompiledItemMetadataAttributeName { get; set; } = "global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute";
public void WriteRazorCompiledItemAttribute(CodeRenderingContext context, RazorCompiledItemAttributeIntermediateNode node)
{
if (context == null)
@ -36,6 +39,28 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
context.CodeWriter.WriteLine("\")]");
}
public void WriteRazorCompiledItemMetadataAttribute(CodeRenderingContext context, RazorCompiledItemMetadataAttributeIntermediateNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
// [assembly: global::...RazorCompiledItemAttribute(@"{node.Key}", @"{node.Value}")]
context.CodeWriter.Write("[");
context.CodeWriter.Write(CompiledItemMetadataAttributeName);
context.CodeWriter.Write("(");
context.CodeWriter.WriteStringLiteral(node.Key);
context.CodeWriter.Write(", ");
context.CodeWriter.WriteStringLiteral(node.Value);
context.CodeWriter.WriteLine(")]");
}
public void WriteRazorSourceChecksumAttribute(CodeRenderingContext context, RazorSourceChecksumAttributeIntermediateNode node)
{
if (context == null)

View File

@ -0,0 +1,59 @@
// 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 System;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
/// <summary>
/// An <see cref="ExtensionIntermediateNode"/> that generates code for <c>RazorCompiledItemMetadataAttribute</c>.
/// </summary>
public class RazorCompiledItemMetadataAttributeIntermediateNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children => IntermediateNodeCollection.ReadOnly;
/// <summary>
/// Gets or sets the attribute key.
/// </summary>
public string Key { get; set; }
/// <summary>
/// Gets or sets the attribute value.
/// </summary>
public string Value { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IMetadataAttributeTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IMetadataAttributeTargetExtension>(context);
return;
}
extension.WriteRazorCompiledItemMetadataAttribute(context, this);
}
}
}

View File

@ -0,0 +1,35 @@
// 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 System;
namespace Microsoft.AspNetCore.Razor.Hosting
{
/// <summary>
/// Defines a key/value metadata pair for the decorated Razor type.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class RazorCompiledItemMetadataAttribute : Attribute
{
/// <summary>
/// Creates a new <see cref="RazorCompiledItemMetadataAttribute"/>.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public RazorCompiledItemMetadataAttribute(string key, string value)
{
Key = key;
Value = value;
}
/// <summary>
/// Gets the key.
/// </summary>
public string Key { get; }
/// <summary>
/// Gets the value.
/// </summary>
public string Value { get; }
}
}

View File

@ -231,6 +231,14 @@ public class DivTagHelper : {typeof(TagHelper).FullName}
RunRuntimeTest(compilation);
}
[Fact]
public void RazorPagesWithRouteTemplate_Runtime()
{
var compilation = BaseCompilation;
RunRuntimeTest(compilation);
}
[Fact]
public void RazorPagesWithoutModel_Runtime()
{
@ -510,6 +518,14 @@ public class DivTagHelper : {typeof(TagHelper).FullName}
RunDesignTimeTest(compilation);
}
[Fact]
public void RazorPagesWithRouteTemplate_DesignTime()
{
var compilation = BaseCompilation;
RunDesignTimeTest(compilation);
}
[Fact]
public void RazorPagesWithoutModel_DesignTime()
{

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
// Arrange
var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page", "Test.cshtml"));
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
irDocument.DocumentKind = "some-value";
@ -239,6 +240,31 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
Assert.Equal(new[] { "public", "async", "override" }, visitor.Method.Modifiers);
}
[Fact]
public void RazorPageDocumentClassifierPass_AddsRouteTemplateMetadata()
{
// Arrange
var properties = new RazorSourceDocumentProperties(filePath: "ignored", relativePath: "Test.cshtml");
var codeDocument = RazorCodeDocument.Create(RazorSourceDocument.Create("@page \"some-route\"", properties));
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new RazorPageDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
var attributeNode = Assert.IsType<RazorCompiledItemMetadataAttributeIntermediateNode>(visitor.ExtensionNode);
Assert.Equal("RouteTemplate", attributeNode.Key);
Assert.Equal("some-route", attributeNode.Value);
}
private static RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
@ -271,6 +297,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
public MethodDeclarationIntermediateNode Method { get; private set; }
public ExtensionIntermediateNode ExtensionNode { get; private set; }
public override void VisitMethodDeclaration(MethodDeclarationIntermediateNode node)
{
Method = node;
@ -287,6 +315,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
Class = node;
base.VisitClassDeclaration(node);
}
public override void VisitExtension(ExtensionIntermediateNode node)
{
ExtensionNode = node;
}
}
}
}

View File

@ -0,0 +1,13 @@
@page "/About"
@model NewModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@functions {
public class NewModel : PageModel
{
public string Name { get; set; }
}
}
<h1>New Customer @Model.Name</h1>

View File

@ -0,0 +1,70 @@
// <auto-generated/>
#pragma warning disable 1591
namespace AspNetCore
{
#line hidden
using TModel = global::System.Object;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line 4 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
using Microsoft.AspNetCore.Mvc.RazorPages;
#line default
#line hidden
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("RouteTemplate", "/About")]
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object __typeHelper = "/About";
}
))();
((System.Action)(() => {
NewModel __typeHelper = default(NewModel);
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
#line 13 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
__o = Model.Name;
#line default
#line hidden
}
#pragma warning restore 1998
#line 6 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
public class NewModel : PageModel
{
public string Name { get; set; }
}
#line default
#line hidden
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<NewModel> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel>)PageContext?.ViewData;
public NewModel Model => ViewData.Model;
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,60 @@
Document -
NamespaceDeclaration - - AspNetCore
UsingDirective - - TModel = global::System.Object
UsingDirective - (1:0,1 [12] ) - System
UsingDirective - (16:1,1 [32] ) - System.Collections.Generic
UsingDirective - (51:2,1 [17] ) - System.Linq
UsingDirective - (71:3,1 [28] ) - System.Threading.Tasks
UsingDirective - (102:4,1 [30] ) - Microsoft.AspNetCore.Mvc
UsingDirective - (135:5,1 [40] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingDirective - (178:6,1 [43] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
UsingDirective - (36:3,1 [41] RazorPagesWithRouteTemplate.cshtml) - Microsoft.AspNetCore.Mvc.RazorPages
RazorCompiledItemMetadataAttribute -
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate - global::Microsoft.AspNetCore.Mvc.RazorPages.Page -
DesignTimeDirective -
DirectiveToken - (231:7,8 [62] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel>
DirectiveToken - (294:7,71 [4] ) - Html
DirectiveToken - (308:8,8 [54] ) - global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper
DirectiveToken - (363:8,63 [4] ) - Json
DirectiveToken - (377:9,8 [53] ) - global::Microsoft.AspNetCore.Mvc.IViewComponentHelper
DirectiveToken - (431:9,62 [9] ) - Component
DirectiveToken - (450:10,8 [43] ) - global::Microsoft.AspNetCore.Mvc.IUrlHelper
DirectiveToken - (494:10,52 [3] ) - Url
DirectiveToken - (507:11,8 [70] ) - global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider
DirectiveToken - (578:11,79 [23] ) - ModelExpressionProvider
DirectiveToken - (617:12,14 [96] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor
DirectiveToken - (729:13,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor
DirectiveToken - (832:14,14 [87] ) - Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor
DirectiveToken - (6:0,6 [8] RazorPagesWithRouteTemplate.cshtml) - "/About"
DirectiveToken - (25:2,7 [8] RazorPagesWithRouteTemplate.cshtml) - NewModel
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync
HtmlContent - (16:1,0 [2] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (16:1,0 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
HtmlContent - (77:3,42 [4] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (77:3,42 [4] RazorPagesWithRouteTemplate.cshtml) - Html - \n\n
HtmlContent - (191:10,1 [21] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (191:10,1 [4] RazorPagesWithRouteTemplate.cshtml) - Html - \n\n
IntermediateToken - (195:12,0 [4] RazorPagesWithRouteTemplate.cshtml) - Html - <h1>
IntermediateToken - (199:12,4 [13] RazorPagesWithRouteTemplate.cshtml) - Html - New Customer
CSharpExpression - (213:12,18 [10] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (213:12,18 [10] RazorPagesWithRouteTemplate.cshtml) - CSharp - Model.Name
HtmlContent - (223:12,28 [7] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (223:12,28 [5] RazorPagesWithRouteTemplate.cshtml) - Html - </h1>
IntermediateToken - (228:12,33 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
CSharpCode - (93:5,12 [97] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (93:5,12 [97] RazorPagesWithRouteTemplate.cshtml) - CSharp - \n public class NewModel : PageModel\n {\n public string Name { get; set; }\n }\n
Inject -
Inject -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel>)PageContext?.ViewData;
CSharpCode -
IntermediateToken - - CSharp - public NewModel Model => ViewData.Model;

View File

@ -0,0 +1,35 @@
Source Location: (36:3,1 [41] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml)
|using Microsoft.AspNetCore.Mvc.RazorPages|
Generated Location: (492:14,0 [41] )
|using Microsoft.AspNetCore.Mvc.RazorPages|
Source Location: (6:0,6 [8] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml)
|"/About"|
Generated Location: (1005:24,37 [8] )
|"/About"|
Source Location: (25:2,7 [8] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml)
|NewModel|
Generated Location: (1076:28,0 [8] )
|NewModel|
Source Location: (213:12,18 [10] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml)
|Model.Name|
Generated Location: (1573:40,18 [10] )
|Model.Name|
Source Location: (93:5,12 [97] TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml)
|
public class NewModel : PageModel
{
public string Name { get; set; }
}
|
Generated Location: (1781:47,12 [97] )
|
public class NewModel : PageModel
{
public string Name { get; set; }
}
|

View File

@ -0,0 +1,72 @@
#pragma checksum "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "d2a113c82e86efc28ea0a17c1f42bbb23a52fecf"
// <auto-generated/>
#pragma warning disable 1591
[assembly: global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemAttribute(typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate), @"mvc.1.0.razor-page", @"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml")]
[assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(@"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml", typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate), @"/About")]
namespace AspNetCore
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line 4 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
using Microsoft.AspNetCore.Mvc.RazorPages;
#line default
#line hidden
[global::Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadataAttribute("RouteTemplate", "/About")]
[global::Microsoft.AspNetCore.Razor.Hosting.RazorSourceChecksumAttribute(@"SHA1", @"d2a113c82e86efc28ea0a17c1f42bbb23a52fecf", @"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml")]
public class TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate : global::Microsoft.AspNetCore.Mvc.RazorPages.Page
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
BeginContext(16, 2, true);
WriteLiteral("\r\n");
EndContext();
BeginContext(79, 2, true);
WriteLiteral("\r\n");
EndContext();
BeginContext(193, 19, true);
WriteLiteral("\r\n<h1>New Customer ");
EndContext();
BeginContext(213, 10, false);
#line 13 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
Write(Model.Name);
#line default
#line hidden
EndContext();
BeginContext(223, 7, true);
WriteLiteral("</h1>\r\n");
EndContext();
}
#pragma warning restore 1998
#line 6 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml"
public class NewModel : PageModel
{
public string Name { get; set; }
}
#line default
#line hidden
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<NewModel> Html { get; private set; }
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel>)PageContext?.ViewData;
public NewModel Model => ViewData.Model;
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,61 @@
Document -
RazorCompiledItemAttribute -
CSharpCode -
IntermediateToken - - CSharp - [assembly:global::Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.RazorPageAttribute(@"/TestFiles/IntegrationTests/CodeGenerationIntegrationTest/RazorPagesWithRouteTemplate.cshtml", typeof(AspNetCore.TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate), @"/About")]
NamespaceDeclaration - - AspNetCore
UsingDirective - (1:0,1 [14] ) - System
UsingDirective - (16:1,1 [34] ) - System.Collections.Generic
UsingDirective - (51:2,1 [19] ) - System.Linq
UsingDirective - (71:3,1 [30] ) - System.Threading.Tasks
UsingDirective - (102:4,1 [32] ) - Microsoft.AspNetCore.Mvc
UsingDirective - (135:5,1 [42] ) - Microsoft.AspNetCore.Mvc.Rendering
UsingDirective - (178:6,1 [45] ) - Microsoft.AspNetCore.Mvc.ViewFeatures
UsingDirective - (36:3,1 [43] RazorPagesWithRouteTemplate.cshtml) - Microsoft.AspNetCore.Mvc.RazorPages
RazorCompiledItemMetadataAttribute -
RazorSourceChecksumAttribute -
ClassDeclaration - - public - TestFiles_IntegrationTests_CodeGenerationIntegrationTest_RazorPagesWithRouteTemplate - global::Microsoft.AspNetCore.Mvc.RazorPages.Page -
MethodDeclaration - - public async override - global::System.Threading.Tasks.Task - ExecuteAsync
CSharpCode -
IntermediateToken - - CSharp - BeginContext(16, 2, true);
HtmlContent - (16:1,0 [2] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (16:1,0 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
CSharpCode -
IntermediateToken - - CSharp - EndContext();
CSharpCode -
IntermediateToken - - CSharp - BeginContext(79, 2, true);
HtmlContent - (79:4,0 [2] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (79:4,0 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
CSharpCode -
IntermediateToken - - CSharp - EndContext();
CSharpCode -
IntermediateToken - - CSharp - BeginContext(193, 19, true);
HtmlContent - (193:11,0 [19] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (193:11,0 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
IntermediateToken - (195:12,0 [4] RazorPagesWithRouteTemplate.cshtml) - Html - <h1>
IntermediateToken - (199:12,4 [13] RazorPagesWithRouteTemplate.cshtml) - Html - New Customer
CSharpCode -
IntermediateToken - - CSharp - EndContext();
CSharpCode -
IntermediateToken - - CSharp - BeginContext(213, 10, false);
CSharpExpression - (213:12,18 [10] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (213:12,18 [10] RazorPagesWithRouteTemplate.cshtml) - CSharp - Model.Name
CSharpCode -
IntermediateToken - - CSharp - EndContext();
CSharpCode -
IntermediateToken - - CSharp - BeginContext(223, 7, true);
HtmlContent - (223:12,28 [7] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (223:12,28 [5] RazorPagesWithRouteTemplate.cshtml) - Html - </h1>
IntermediateToken - (228:12,33 [2] RazorPagesWithRouteTemplate.cshtml) - Html - \n
CSharpCode -
IntermediateToken - - CSharp - EndContext();
CSharpCode - (93:5,12 [97] RazorPagesWithRouteTemplate.cshtml)
IntermediateToken - (93:5,12 [97] RazorPagesWithRouteTemplate.cshtml) - CSharp - \n public class NewModel : PageModel\n {\n public string Name { get; set; }\n }\n
Inject -
Inject -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - public global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel> ViewData => (global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary<NewModel>)PageContext?.ViewData;
CSharpCode -
IntermediateToken - - CSharp - public NewModel Model => ViewData.Model;

View File

@ -65,5 +65,59 @@ namespace Microsoft.AspNetCore.Razor.Language.Extensions
csharp,
ignoreLineEndingDifferences: true);
}
[Fact]
public void WriteRazorCompiledItemAttributeMetadata_RendersCorrectly()
{
// Arrange
var extension = new MetadataAttributeTargetExtension()
{
CompiledItemMetadataAttributeName = "global::TestItemMetadata",
};
var context = TestCodeRenderingContext.CreateRuntime();
var node = new RazorCompiledItemMetadataAttributeIntermediateNode
{
Key = "key",
Value = "value",
};
// Act
extension.WriteRazorCompiledItemMetadataAttribute(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode().Trim();
Assert.Equal(
"[global::TestItemMetadata(\"key\", \"value\")]",
csharp,
ignoreLineEndingDifferences: true);
}
[Fact]
public void WriteRazorCompiledItemAttributeMetadata_EscapesKeysAndValuesCorrectly()
{
// Arrange
var extension = new MetadataAttributeTargetExtension()
{
CompiledItemMetadataAttributeName = "global::TestItemMetadata",
};
var context = TestCodeRenderingContext.CreateRuntime();
var node = new RazorCompiledItemMetadataAttributeIntermediateNode
{
Key = "\"test\" key",
Value = @"""test"" value",
};
// Act
extension.WriteRazorCompiledItemMetadataAttribute(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode().Trim();
Assert.Equal(
"[global::TestItemMetadata(\"\\\"test\\\" key\", \"\\\"test\\\" value\")]",
csharp,
ignoreLineEndingDifferences: true);
}
}
}