Move Razor.Host to Razor

This commit is contained in:
Ryan Brandenburg 2017-03-20 16:27:04 -07:00
parent cab6eea663
commit 72febdac64
77 changed files with 5650 additions and 1 deletions

2
.gitignore vendored
View File

@ -31,4 +31,4 @@ project.lock.json
.build/
.vs/
launchSettings.json
global.json
global.json

View File

@ -43,6 +43,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageGenerator.Test", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.LanguageServices.Razor.Test\Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj", "{37E61BDB-658E-4F44-A499-D64CC6D35485}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions", "src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj", "{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Test", "test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test.csproj", "{7CFD5646-A757-4498-9E01-9C8528ED60AE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -161,6 +165,22 @@ Global
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Release|Any CPU.Build.0 = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Release|Any CPU.Build.0 = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.Release|Any CPU.Build.0 = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7CFD5646-A757-4498-9E01-9C8528ED60AE}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -180,5 +200,7 @@ Global
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63} = {92463391-81BE-462B-AC3C-78C6C760741F}
{37E61BDB-658E-4F44-A499-D64CC6D35485} = {92463391-81BE-462B-AC3C-78C6C760741F}
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7CFD5646-A757-4498-9E01-9C8528ED60AE} = {92463391-81BE-462B-AC3C-78C6C760741F}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,12 @@
// 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.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public interface IInjectDirectiveTargetExtension : IRuntimeTargetExtension
{
void WriteInjectProperty(CSharpRenderingContext context, InjectDirectiveIRNode node);
}
}

View File

@ -0,0 +1,90 @@
// 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 System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class InjectDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptorBuilder.Create("inject").AddType().AddMember().Build();
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
internal class Pass : RazorIRPassBase, IRazorDirectiveClassifierPass
{
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var visitor = new Visitor();
visitor.Visit(irDocument);
var modelType = ModelDirective.GetModelType(irDocument);
var properties = new HashSet<string>(StringComparer.Ordinal);
for (var i = visitor.Directives.Count - 1; i >= 0; i--)
{
var directive = visitor.Directives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length < 2)
{
continue;
}
var typeName = tokens[0].Content;
var memberName = tokens[1].Content;
if (!properties.Add(memberName))
{
continue;
}
typeName = typeName.Replace("<TModel>", "<" + modelType + ">");
var injectNode = new InjectDirectiveIRNode()
{
TypeName = typeName,
MemberName = memberName,
Source = directive.Source,
Parent = visitor.Class,
};
visitor.Class.Children.Add(injectNode);
}
}
}
private class Visitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Class { get; private set; }
public IList<DirectiveIRNode> Directives { get; } = new List<DirectiveIRNode>();
public override void VisitClass(ClassDeclarationIRNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClass(node);
}
public override void VisitDirective(DirectiveIRNode node)
{
if (node.Descriptor == Directive)
{
Directives.Add(node);
}
}
}
}
}

View File

@ -0,0 +1,45 @@
// 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 System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.CodeGeneration;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectDirectiveIRNode : ExtensionIRNode
{
public string TypeName { get; set; }
public string MemberName { get; set; }
public override IList<RazorIRNode> Children { get; } = new RazorIRNode[0];
public override RazorIRNode Parent { get; set; }
public override SourceSpan? Source { get; set; }
public override void Accept(RazorIRNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<InjectDirectiveIRNode>(this, visitor);
}
public override void WriteNode(RuntimeTarget target, CSharpRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
var extension = target.GetExtension<IInjectDirectiveTargetExtension>();
extension.WriteInjectProperty(context, this);
}
}
}

View File

@ -0,0 +1,44 @@
// 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.Evolution.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectDirectiveTargetExtension : IInjectDirectiveTargetExtension
{
private const string RazorInjectAttribute = "[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]";
public void WriteInjectProperty(CSharpRenderingContext context, InjectDirectiveIRNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
var property = $"public {node.TypeName} {node.MemberName} {{ get; private set; }}";
if (node.Source.HasValue)
{
using (context.Writer.BuildLinePragma(node.Source.Value))
{
context.Writer
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
else
{
context.Writer
.WriteLine(RazorInjectAttribute)
.WriteLine(property);
}
}
}
}

View File

@ -0,0 +1,63 @@
// 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.Globalization;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
{
public static class ClassName
{
public static string GetClassNameFromPath(string path)
{
if (string.IsNullOrEmpty(path))
{
return path;
}
return SanitizeClassName(path);
}
// CSharp Spec §2.4.2
private static bool IsIdentifierStart(char character)
{
return char.IsLetter(character) ||
character == '_' ||
CharUnicodeInfo.GetUnicodeCategory(character) == UnicodeCategory.LetterNumber;
}
public static bool IsIdentifierPart(char character)
{
return char.IsDigit(character) ||
IsIdentifierStart(character) ||
IsIdentifierPartByUnicodeCategory(character);
}
private static bool IsIdentifierPartByUnicodeCategory(char character)
{
var category = CharUnicodeInfo.GetUnicodeCategory(character);
return category == UnicodeCategory.NonSpacingMark || // Mn
category == UnicodeCategory.SpacingCombiningMark || // Mc
category == UnicodeCategory.ConnectorPunctuation || // Pc
category == UnicodeCategory.Format; // Cf
}
private static string SanitizeClassName(string inputName)
{
if (!IsIdentifierStart(inputName[0]) && IsIdentifierPart(inputName[0]))
{
inputName = "_" + inputName;
}
var builder = new InplaceStringBuilder(inputName.Length);
for (var i = 0; i < inputName.Length; i++)
{
var ch = inputName[i];
builder.Append(IsIdentifierPart(ch) ? ch : '_');
}
return builder.ToString();
}
}
}

View File

@ -0,0 +1,34 @@
// 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.Evolution;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal
{
public static class RazorCodeDocumentExtensions
{
private const string RelativePathKey = "relative-path";
public static string GetRelativePath(this RazorCodeDocument document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
return document.Items[RelativePathKey] as string;
}
public static void SetRelativePath(this RazorCodeDocument document, string relativePath)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
document.Items[RelativePathKey] = relativePath;
}
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<Description>ASP.NET Core design time hosting infrastructure for the Razor view engine.</Description>
<TargetFrameworks>net451;netstandard1.6</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore;aspnetcoremvc;cshtml;razor</PackageTags>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.AspNetCore.Razor.Evolution/Microsoft.AspNetCore.Razor.Evolution.csproj" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="$(AspNetCoreVersion)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,117 @@
// 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 System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class ModelDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptorBuilder.Create("model").AddType().Build();
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
builder.AddDirective(Directive);
builder.Features.Add(new Pass());
return builder;
}
public static string GetModelType(DocumentIRNode document)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
var visitor = new Visitor();
return GetModelType(document, visitor);
}
private static string GetModelType(DocumentIRNode document, Visitor visitor)
{
visitor.Visit(document);
for (var i = visitor.ModelDirectives.Count - 1; i >= 0; i--)
{
var directive = visitor.ModelDirectives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length >= 1)
{
return tokens[0].Content;
}
}
if (document.DocumentKind == RazorPageDocumentClassifierPass.RazorPageDocumentKind)
{
return visitor.Class.Name;
}
else
{
return "dynamic";
}
}
internal class Pass : RazorIRPassBase, IRazorDirectiveClassifierPass
{
// Runs after the @inherits directive
public override int Order => 5;
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var visitor = new Visitor();
var modelType = GetModelType(irDocument, visitor);
var baseType = visitor.Class?.BaseType?.Replace("<TModel>", "<" + modelType + ">");
for (var i = visitor.InheritsDirectives.Count - 1; i >= 0; i--)
{
var directive = visitor.InheritsDirectives[i];
var tokens = directive.Tokens.ToArray();
if (tokens.Length >= 1)
{
baseType = tokens[0].Content.Replace("<TModel>", "<" + modelType + ">");
tokens[0].Content = baseType;
break;
}
}
visitor.Class.BaseType = baseType;
}
}
private class Visitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Class { get; private set; }
public IList<DirectiveIRNode> InheritsDirectives { get; } = new List<DirectiveIRNode>();
public IList<DirectiveIRNode> ModelDirectives { get; } = new List<DirectiveIRNode>();
public override void VisitClass(ClassDeclarationIRNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClass(node);
}
public override void VisitDirective(DirectiveIRNode node)
{
if (node.Descriptor == Directive)
{
ModelDirectives.Add(node);
}
else if (node.Descriptor.Name == "inherits")
{
InheritsDirectives.Add(node);
}
}
}
}
}

View File

@ -0,0 +1,109 @@
// 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 System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ModelExpressionPass : RazorIRPassBase, IRazorIROptimizationPass
{
private const string ModelExpressionTypeName = "Microsoft.AspNetCore.Mvc.ViewFeatures.ModelExpression";
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var visitor = new Visitor();
visitor.Visit(irDocument);
}
private class Visitor : RazorIRNodeWalker
{
public List<TagHelperIRNode> TagHelpers { get; } = new List<TagHelperIRNode>();
public override void VisitSetTagHelperProperty(SetTagHelperPropertyIRNode node)
{
if (string.Equals(node.Descriptor.TypeName, ModelExpressionTypeName, StringComparison.Ordinal) ||
(node.IsIndexerNameMatch &&
string.Equals(node.Descriptor.IndexerTypeName, ModelExpressionTypeName, StringComparison.Ordinal)))
{
var expression = new CSharpExpressionIRNode();
var builder = RazorIRBuilder.Create(expression);
builder.Add(new RazorIRToken()
{
Kind = RazorIRToken.TokenKind.CSharp,
Content = "ModelExpressionProvider.CreateModelExpression(ViewData, __model => ",
});
if (node.Children.Count == 1 && node.Children[0] is HtmlContentIRNode)
{
// A 'simple' expression will look like __model => __model.Foo
//
// Note that the fact we're looking for HTML here is based on a bug.
// https://github.com/aspnet/Razor/issues/963
var original = ((HtmlContentIRNode)node.Children[0]);
builder.Add(new RazorIRToken()
{
Kind = RazorIRToken.TokenKind.CSharp,
Content = "__model."
});
builder.Add(new RazorIRToken()
{
Kind = RazorIRToken.TokenKind.CSharp,
Content = original.Content,
Source = original.Source,
});
}
else
{
for (var i = 0; i < node.Children.Count; i++)
{
var nestedExpression = node.Children[i] as CSharpExpressionIRNode;
if (nestedExpression != null)
{
for (var j = 0; j < nestedExpression.Children.Count; j++)
{
var cSharpToken = nestedExpression.Children[j] as RazorIRToken;
if (cSharpToken != null && cSharpToken.Kind == RazorIRToken.TokenKind.CSharp)
{
builder.Add(cSharpToken);
}
}
continue;
}
// Note that the fact we're looking for HTML here is based on a bug.
// https://github.com/aspnet/Razor/issues/963
var html = node.Children[i] as HtmlContentIRNode;
if (html != null)
{
builder.Add(new RazorIRToken()
{
Kind = RazorIRToken.TokenKind.CSharp,
Content = html.Content,
Source = html.Source,
});
}
}
}
builder.Add(new RazorIRToken()
{
Kind = RazorIRToken.TokenKind.CSharp,
Content = ")",
});
node.Children.Clear();
node.Children.Add(expression);
expression.Parent = node;
}
}
}
}
}

View File

@ -0,0 +1,62 @@
// 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.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
/// <summary>
/// A <see cref="RazorTemplateEngine"/> for Mvc Razor views.
/// </summary>
public class MvcRazorTemplateEngine : RazorTemplateEngine
{
/// <summary>
/// Initializes a new instance of <see cref="MvcRazorTemplateEngine"/>.
/// </summary>
/// <param name="engine">The <see cref="RazorEngine"/>.</param>
/// <param name="project">The <see cref="RazorProject"/>.</param>
public MvcRazorTemplateEngine(
RazorEngine engine,
RazorProject project)
: base(engine, project)
{
Options.DefaultImports = GetDefaultImports();
}
/// <inheritsdoc />
public override RazorCodeDocument CreateCodeDocument(RazorProjectItem projectItem)
{
var codeDocument = base.CreateCodeDocument(projectItem);
codeDocument.SetRelativePath(projectItem.Path);
return codeDocument;
}
private static RazorSourceDocument GetDefaultImports()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.WriteLine("@using System");
writer.WriteLine("@using System.Linq");
writer.WriteLine("@using System.Collections.Generic");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.Rendering");
writer.WriteLine("@using Microsoft.AspNetCore.Mvc.ViewFeatures");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url");
writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider");
writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor");
writer.Flush();
stream.Position = 0;
return RazorSourceDocument.ReadFrom(stream, fileName: null, encoding: Encoding.UTF8);
}
}
}
}

View File

@ -0,0 +1,37 @@
// 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.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class MvcViewDocumentClassifierPass : DocumentClassifierPassBase
{
public readonly string MvcViewDocumentKind = "mvc.1.0.view";
protected override string DocumentKind => MvcViewDocumentKind;
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIRNode irDocument) => true;
protected override void OnDocumentStructureCreated(
RazorCodeDocument codeDocument,
NamespaceDeclarationIRNode @namespace,
ClassDeclarationIRNode @class,
RazorMethodDeclarationIRNode method)
{
var filePath = codeDocument.GetRelativePath() ?? codeDocument.Source.FileName;
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
@class.Name = ClassName.GetClassNameFromPath(filePath);
@class.BaseType = "global::Microsoft.AspNetCore.Razor.RazorPage<TModel>";
@class.AccessModifier = "public";
@namespace.Content = "AspNetCore";
method.Name = "ExecuteAsync";
method.Modifiers = new[] { "async", "override" };
method.AccessModifier = "public";
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
}
}
}

View File

@ -0,0 +1,52 @@
// 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.Linq;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class PageDirective
{
public static readonly DirectiveDescriptor DirectiveDescriptor = DirectiveDescriptorBuilder
.Create("page")
.BeginOptionals()
.AddString()
.Build();
public static IRazorEngineBuilder Register(IRazorEngineBuilder builder)
{
builder.AddDirective(DirectiveDescriptor);
return builder;
}
public static bool TryGetRouteTemplate(DocumentIRNode irDocument, out string routeTemplate)
{
var visitor = new Visitor();
for (var i = 0; i < irDocument.Children.Count; i++)
{
visitor.Visit(irDocument.Children[i]);
}
routeTemplate = visitor.RouteTemplate;
return visitor.DirectiveNode != null;
}
private class Visitor : RazorIRNodeWalker
{
public DirectiveIRNode DirectiveNode { get; private set; }
public string RouteTemplate { get; private set; }
public override void VisitDirective(DirectiveIRNode node)
{
if (node.Descriptor == DirectiveDescriptor)
{
DirectiveNode = node;
RouteTemplate = node.Tokens.FirstOrDefault()?.Content;
}
}
}
}
}

View File

@ -0,0 +1,55 @@
// 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.Extensions
{
public class PagesPropertyInjectionPass : RazorIRPassBase, IRazorIROptimizationPass
{
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
if (irDocument.DocumentKind != RazorPageDocumentClassifierPass.RazorPageDocumentKind)
{
return;
}
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);
}
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

@ -0,0 +1,6 @@
// 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.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -0,0 +1,126 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Mvc.Razor.Extensions.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpy
{
get { return GetString("ArgumentCannotBeNullOrEmpy"); }
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpy()
{
return GetString("ArgumentCannotBeNullOrEmpy");
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword
{
get { return GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"); }
}
/// <summary>
/// The 'inherits' keyword is not allowed when a '{0}' keyword is used.
/// </summary>
internal static string FormatMvcRazorCodeParser_CannotHaveModelAndInheritsKeyword(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword"), p0);
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string MvcRazorCodeParser_InjectDirectivePropertyNameRequired
{
get { return GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"); }
}
/// <summary>
/// A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.
/// </summary>
internal static string FormatMvcRazorCodeParser_InjectDirectivePropertyNameRequired(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_InjectDirectivePropertyNameRequired"), p0);
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string MvcRazorCodeParser_KeywordMustBeFollowedByTypeName
{
get { return GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"); }
}
/// <summary>
/// The '{0}' keyword must be followed by a type name on the same line.
/// </summary>
internal static string FormatMvcRazorCodeParser_KeywordMustBeFollowedByTypeName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_KeywordMustBeFollowedByTypeName"), p0);
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string MvcRazorCodeParser_OnlyOneModelStatementIsAllowed
{
get { return GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"); }
}
/// <summary>
/// Only one '{0}' statement is allowed in a file.
/// </summary>
internal static string FormatMvcRazorCodeParser_OnlyOneModelStatementIsAllowed(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorCodeParser_OnlyOneModelStatementIsAllowed"), p0);
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string MvcRazorParser_InvalidPropertyType
{
get { return GetString("MvcRazorParser_InvalidPropertyType"); }
}
/// <summary>
/// Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.
/// </summary>
internal static string FormatMvcRazorParser_InvalidPropertyType(object p0, object p1, object p2)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MvcRazorParser_InvalidPropertyType"), p0, p1, p2);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,41 @@
// 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.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class RazorPageDocumentClassifierPass : DocumentClassifierPassBase
{
public static readonly string RazorPageDocumentKind = "mvc.1.0.razor-page";
protected override string DocumentKind => RazorPageDocumentKind;
protected override bool IsMatch(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
string routePrefix;
return PageDirective.TryGetRouteTemplate(irDocument, out routePrefix);
}
protected override void OnDocumentStructureCreated(
RazorCodeDocument codeDocument,
NamespaceDeclarationIRNode @namespace,
ClassDeclarationIRNode @class,
RazorMethodDeclarationIRNode method)
{
var filePath = codeDocument.GetRelativePath() ?? codeDocument.Source.FileName;
base.OnDocumentStructureCreated(codeDocument, @namespace, @class, method);
@class.BaseType = "global::Microsoft.AspNetCore.RazorPages.Page";
@class.Name = ClassName.GetClassNameFromPath(filePath);
@class.AccessModifier = "public";
@namespace.Content = "AspNetCore";
method.Name = "ExecuteAsync";
method.Modifiers = new[] { "async", "override" };
method.AccessModifier = "public";
method.ReturnType = $"global::{typeof(System.Threading.Tasks.Task).FullName}";
}
}
}

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<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">
<value>Value cannot be null or empty.</value>
</data>
<data name="MvcRazorCodeParser_CannotHaveModelAndInheritsKeyword" xml:space="preserve">
<value>The 'inherits' keyword is not allowed when a '{0}' keyword is used.</value>
</data>
<data name="MvcRazorCodeParser_InjectDirectivePropertyNameRequired" xml:space="preserve">
<value>A property name must be specified when using the '{0}' statement. Format for a '{0}' statement is '@{0} &lt;Type Name&gt; &lt;Property Name&gt;'.</value>
</data>
<data name="MvcRazorCodeParser_KeywordMustBeFollowedByTypeName" xml:space="preserve">
<value>The '{0}' keyword must be followed by a type name on the same line.</value>
</data>
<data name="MvcRazorCodeParser_OnlyOneModelStatementIsAllowed" xml:space="preserve">
<value>Only one '{0}' statement is allowed in a file.</value>
</data>
<data name="MvcRazorParser_InvalidPropertyType" xml:space="preserve">
<value>Invalid tag helper property '{0}.{1}'. Dictionary values must not be of type '{2}'.</value>
</data>
</root>

View File

@ -0,0 +1,27 @@
// 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;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
/// <summary>
/// A library of methods used to generate <see cref="TagHelperDescriptor"/>s for view components.
/// </summary>
public static class ViewComponentTagHelperDescriptorConventions
{
/// <summary>
/// The key in a <see cref="TagHelperDescriptor.Metadata"/> containing
/// the short name of a view component.
/// </summary>
public static readonly string ViewComponentNameKey = "ViewComponentName";
/// <summary>
/// Indicates whether a <see cref="TagHelperDescriptor"/> represents a view component.
/// </summary>
/// <param name="descriptor">The <see cref="TagHelperDescriptor"/> to check.</param>
/// <returns>Whether a <see cref="TagHelperDescriptor"/> represents a view component.</returns>
public static bool IsViewComponentDescriptor(TagHelperDescriptor descriptor) =>
descriptor != null && descriptor.Metadata.ContainsKey(ViewComponentNameKey);
}
}

View File

@ -0,0 +1,276 @@
// 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ViewComponentTagHelperPass : RazorIRPassBase, IRazorIROptimizationPass
{
public override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIRNode irDocument)
{
var visitor = new Visitor();
visitor.Visit(irDocument);
if (visitor.Class == null || visitor.TagHelpers.Count == 0)
{
// Nothing to do, bail.
return;
}
foreach (var tagHelper in visitor.TagHelpers)
{
GenerateVCTHClass(visitor.Class, tagHelper.Value);
var tagHelperTypeName = tagHelper.Value.Metadata[ITagHelperDescriptorBuilder.TypeNameKey];
if (visitor.Fields.UsedTagHelperTypeNames.Remove(tagHelperTypeName))
{
visitor.Fields.UsedTagHelperTypeNames.Add(GetVCTHFullName(visitor.Namespace, visitor.Class, tagHelper.Value));
}
}
foreach (var createNode in visitor.CreateTagHelpers)
{
RewriteCreateNode(visitor.Namespace, visitor.Class, createNode);
}
}
private void GenerateVCTHClass(ClassDeclarationIRNode @class, TagHelperDescriptor tagHelper)
{
var writer = new CSharpCodeWriter();
WriteClass(writer, tagHelper);
@class.Children.Add(new CSharpStatementIRNode()
{
Content = writer.Builder.ToString(),
Parent = @class,
});
}
private void RewriteCreateNode(
NamespaceDeclarationIRNode @namespace,
ClassDeclarationIRNode @class,
CreateTagHelperIRNode node)
{
var originalTypeName = node.TagHelperTypeName;
var newTypeName = GetVCTHFullName(@namespace, @class, node.Descriptor);
for (var i = 0; i < node.Parent.Children.Count; i++)
{
var setProperty = node.Parent.Children[i] as SetTagHelperPropertyIRNode;
if (setProperty != null)
{
setProperty.TagHelperTypeName = newTypeName;
}
}
node.TagHelperTypeName = newTypeName;
}
private static string GetVCTHFullName(
NamespaceDeclarationIRNode @namespace,
ClassDeclarationIRNode @class,
TagHelperDescriptor tagHelper)
{
var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
return $"{@namespace.Content}.{@class.Name}.__Generated__{vcName}ViewComponentTagHelper";
}
private static string GetVCTHClassName(
TagHelperDescriptor tagHelper)
{
var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
return $"__Generated__{vcName}ViewComponentTagHelper";
}
private void WriteClass(CSharpCodeWriter writer, TagHelperDescriptor descriptor)
{
// Add target element.
BuildTargetElementString(writer, descriptor);
// Initialize declaration.
var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
var className = GetVCTHClassName(descriptor);
using (writer.BuildClassDeclaration("public", className, new[] { tagHelperTypeName }))
{
// Add view component helper.
writer.WriteVariableDeclaration(
$"private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper",
"_helper",
value: null);
// Add constructor.
BuildConstructorString(writer, className);
// Add attributes.
BuildAttributeDeclarations(writer, descriptor);
// Add process method.
BuildProcessMethodString(writer, descriptor);
}
}
private void BuildConstructorString(CSharpCodeWriter writer, string className)
{
var helperPair = new KeyValuePair<string, string>(
$"global::Microsoft.AspNetCore.Mvc.IViewComponentHelper",
"helper");
using (writer.BuildConstructor("public", className, new[] { helperPair }))
{
writer.WriteStartAssignment("_helper")
.Write("helper")
.WriteLine(";");
}
}
private void BuildAttributeDeclarations(CSharpCodeWriter writer, TagHelperDescriptor descriptor)
{
writer.Write("[")
.Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute")
.WriteParameterSeparator()
.Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute")
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
"public",
$"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext",
"ViewContext");
foreach (var attribute in descriptor.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
"public", attribute.TypeName, attribute.Metadata[ITagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]);
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void BuildProcessMethodString(CSharpCodeWriter writer, TagHelperDescriptor descriptor)
{
var contextVariable = "context";
var outputVariable = "output";
using (writer.BuildMethodDeclaration(
$"public override async",
$"global::{typeof(Task).FullName}",
"ProcessAsync",
new Dictionary<string, string>()
{
{ "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext", contextVariable },
{ "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput", outputVariable }
}))
{
writer.WriteInstanceMethodInvocation(
$"(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?",
"Contextualize",
new[] { "ViewContext" });
var methodParameters = GetMethodParameters(descriptor);
var contentVariable = "content";
writer.Write("var ")
.WriteStartAssignment(contentVariable)
.WriteInstanceMethodInvocation($"await _helper", "InvokeAsync", methodParameters);
writer.WriteStartAssignment($"{outputVariable}.TagName")
.WriteLine("null;");
writer.WriteInstanceMethodInvocation(
$"{outputVariable}.Content",
"SetHtmlContent",
new[] { contentVariable });
}
}
private string[] GetMethodParameters(TagHelperDescriptor descriptor)
{
var propertyNames = descriptor.BoundAttributes.Select(
attribute => attribute.Metadata[ITagHelperBoundAttributeDescriptorBuilder.PropertyNameKey]);
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = descriptor.Metadata[
ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void BuildTargetElementString(CSharpCodeWriter writer, TagHelperDescriptor descriptor)
{
Debug.Assert(descriptor.TagMatchingRules.Count() == 1);
var rule = descriptor.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute")
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
}
private class Visitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Class { get; private set; }
public DeclareTagHelperFieldsIRNode Fields { get; private set; }
public NamespaceDeclarationIRNode Namespace { get; private set; }
public List<CreateTagHelperIRNode> CreateTagHelpers { get; } = new List<CreateTagHelperIRNode>();
public Dictionary<string, TagHelperDescriptor> TagHelpers { get; } = new Dictionary<string, TagHelperDescriptor>();
public override void VisitCreateTagHelper(CreateTagHelperIRNode node)
{
var tagHelper = node.Descriptor;
if (ViewComponentTagHelperDescriptorConventions.IsViewComponentDescriptor(tagHelper))
{
// Capture all the VCTagHelpers (unique by type name) so we can generate a class for each one.
var vcName = tagHelper.Metadata[ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey];
TagHelpers[vcName] = tagHelper;
CreateTagHelpers.Add(node);
}
}
public override void VisitNamespace(NamespaceDeclarationIRNode node)
{
if (Namespace == null)
{
Namespace = node;
}
base.VisitNamespace(node);
}
public override void VisitClass(ClassDeclarationIRNode node)
{
if (Class == null)
{
Class = node;
}
base.VisitClass(node);
}
public override void VisitDeclareTagHelperFields(DeclareTagHelperFieldsIRNode node)
{
if (Fields == null)
{
Fields = node;
}
base.VisitDeclareTagHelperFields(node);
}
}
}
}

View File

@ -0,0 +1,20 @@
// 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.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
[HtmlTargetElement(Attributes = "prefix-*")]
public class DictionaryPrefixTestTagHelper : TagHelper
{
[HtmlAttributeName(DictionaryAttributePrefix = "prefix-")]
public IDictionary<string, ModelExpression> PrefixValues { get; set; } = new Dictionary<string, ModelExpression>();
public override void Process(TagHelperContext context, TagHelperOutput output)
{
}
}
}

View File

@ -0,0 +1,75 @@
// 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.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.CodeGeneration;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectDirectiveTargetExtensionTest
{
[Fact]
public void InjectDirectiveTargetExtension_WritesProperty()
{
// Arrange
var context = GetRenderingContext();
var target = new InjectDirectiveTargetExtension();
var node = new InjectDirectiveIRNode()
{
TypeName = "PropertyType",
MemberName = "PropertyName",
};
// Act
target.WriteInjectProperty(context, node);
// Assert
Assert.Equal(
"[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
"public PropertyType PropertyName { get; private set; }" + Environment.NewLine,
context.Writer.Builder.ToString());
}
[Fact]
public void InjectDirectiveTargetExtension_WritesPropertyWithLinePragma_WhenSourceIsSet()
{
// Arrange
var context = GetRenderingContext();
var target = new InjectDirectiveTargetExtension();
var node = new InjectDirectiveIRNode()
{
TypeName = "PropertyType<ModelType>",
MemberName = "PropertyName",
Source = new SourceSpan(
filePath: "test-path",
absoluteIndex: 0,
lineIndex: 1,
characterIndex: 1,
length: 10)
};
// Act
target.WriteInjectProperty(context, node);
// Assert
Assert.Equal(
"#line 2 \"test-path\"" + Environment.NewLine +
"[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]" + Environment.NewLine +
"public PropertyType<ModelType> PropertyName { get; private set; }" + Environment.NewLine + Environment.NewLine +
"#line default" + Environment.NewLine +
"#line hidden" + Environment.NewLine,
context.Writer.Builder.ToString());
}
private CSharpRenderingContext GetRenderingContext()
{
return new CSharpRenderingContext()
{
Writer = new CSharpCodeWriter()
};
}
}
}

View File

@ -0,0 +1,225 @@
// 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.Text;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InjectDirectiveTest
{
[Fact]
public void InjectDirectivePass_Execute_DefinesProperty()
{
// Arrange
var codeDocument = CreateDocument(@"
@inject PropertyType PropertyName
");
var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var node = Assert.IsType<InjectDirectiveIRNode>(@class.Children[1]);
Assert.Equal("PropertyType", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
[Fact]
public void InjectDirectivePass_Execute_DedupesPropertiesByName()
{
// Arrange
var codeDocument = CreateDocument(@"
@inject PropertyType PropertyName
@inject PropertyType2 PropertyName
");
var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var node = Assert.IsType<InjectDirectiveIRNode>(@class.Children[1]);
Assert.Equal("PropertyType2", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
[Fact]
public void InjectDirectivePass_Execute_ExpandsTModel_WithDynamic()
{
// Arrange
var codeDocument = CreateDocument(@"
@inject PropertyType<TModel> PropertyName
");
var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var node = Assert.IsType<InjectDirectiveIRNode>(@class.Children[1]);
Assert.Equal("PropertyType<dynamic>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
[Fact]
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelTypeFirst()
{
// Arrange
var codeDocument = CreateDocument(@"
@model ModelType
@inject PropertyType<TModel> PropertyName
");
var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var node = Assert.IsType<InjectDirectiveIRNode>(@class.Children[1]);
Assert.Equal("PropertyType<ModelType>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
[Fact]
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelType()
{
// Arrange
var codeDocument = CreateDocument(@"
@inject PropertyType<TModel> PropertyName
@model ModelType
");
var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var node = Assert.IsType<InjectDirectiveIRNode>(@class.Children[1]);
Assert.Equal("PropertyType<ModelType>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}
private ClassDeclarationIRNode FindClassNode(RazorIRNode node)
{
var visitor = new ClassNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}
private RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
{
// Notice we're not registering the InjectDirective.Pass here so we can run it on demand.
b.AddDirective(InjectDirective.Directive);
b.AddDirective(ModelDirective.Directive);
});
}
private DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private string GetCSharpContent(RazorIRNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as RazorIRToken;
if (child.Kind == RazorIRToken.TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class ClassNodeVisitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Node { get; set; }
public override void VisitClass(ClassDeclarationIRNode node)
{
Node = node;
}
}
}
}

View File

@ -0,0 +1,13 @@
// 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.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class InputTestTagHelper : TagHelper
{
public ModelExpression For { get; set; }
}
}

View File

@ -0,0 +1,10 @@
// 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.
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
{
// This class is hacked up to appear like the one in MVC so that we don't reference MVC
public class ModelExpression
{
}
}

View File

@ -0,0 +1,230 @@
// 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 System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
/// <summary>
/// Reader and, if GENERATE_BASELINES is defined, writer for files compiled into an assembly as resources.
/// </summary>
/// <remarks>Inspired by Razor's BaselineWriter and TestFile test classes.</remarks>
public static class ResourceFile
{
private static object writeLock = new object();
/// <summary>
/// Return <see cref="Stream"/> for <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// <see cref="Stream"/> for <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest. <c>null</c> if <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is
/// <c>false</c>, and <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
public static Stream GetResourceStream(Assembly assembly, string resourceName, bool sourceFile)
{
var fullName = $"{ assembly.GetName().Name }.{ resourceName.Replace('/', '.') }";
if (!Exists(assembly, fullName))
{
#if GENERATE_BASELINES
if (sourceFile)
{
// Even when generating baselines, a missing source file is a serious problem.
Assert.True(false, $"Manifest resource: { fullName } not found.");
}
#else
// When not generating baselines, a missing source or output file is always an error.
Assert.True(false, $"Manifest resource '{ fullName }' not found.");
#endif
return null;
}
var stream = assembly.GetManifestResourceStream(fullName);
if (sourceFile)
{
// Normalize line endings to '\r\n' (CRLF). This removes core.autocrlf, core.eol, core.safecrlf, and
// .gitattributes from the equation and treats "\r\n" and "\n" as equivalent. Does not handle
// some line endings like "\r" but otherwise ensures checksums and line mappings are consistent.
string text;
using (var streamReader = new StreamReader(stream))
{
text = streamReader.ReadToEnd().Replace("\r", "").Replace("\n", "\r\n");
}
var bytes = Encoding.UTF8.GetBytes(text);
stream = new MemoryStream(bytes);
}
return stream;
}
/// <summary>
/// Return <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// A <see cref="Task{string}"/> which on completion returns the <see cref="string"/> content of
/// <paramref name="resourceName"/> from <paramref name="assembly"/>'s manifest. <c>null</c> if
/// <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is <c>false</c>, and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
/// <remarks>Normalizes line endings to <see cref="Environment.NewLine"/>.</remarks>
public static async Task<string> ReadResourceAsync(Assembly assembly, string resourceName, bool sourceFile)
{
using (var stream = GetResourceStream(assembly, resourceName, sourceFile))
{
if (stream == null)
{
return null;
}
using (var streamReader = new StreamReader(stream))
{
return await streamReader.ReadToEndAsync();
}
}
}
/// <summary>
/// Return <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="sourceFile">
/// If <c>true</c> <paramref name="resourceName"/> is used as a source file and must exist. Otherwise
/// <paramref name="resourceName"/> is an output file and, if <c>GENERATE_BASELINES</c> is defined, it will
/// soon be generated if missing.
/// </param>
/// <returns>
/// The <see cref="string"/> content of <paramref name="resourceName"/> from <paramref name="assembly"/>'s
/// manifest. <c>null</c> if <c>GENERATE_BASELINES</c> is defined, <paramref name="sourceFile"/> is
/// <c>false</c>, and <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </returns>
/// <exception cref="Xunit.Sdk.TrueException">
/// Thrown if <c>GENERATE_BASELINES</c> is not defined or <paramref name="sourceFile"/> is <c>true</c> and
/// <paramref name="resourceName"/> is not found in <paramref name="assembly"/>.
/// </exception>
/// <remarks>Normalizes line endings to <see cref="Environment.NewLine"/>.</remarks>
public static string ReadResource(Assembly assembly, string resourceName, bool sourceFile)
{
using (var stream = GetResourceStream(assembly, resourceName, sourceFile))
{
if (stream == null)
{
return null;
}
using (var streamReader = new StreamReader(stream))
{
return streamReader.ReadToEnd();
}
}
}
/// <summary>
/// Write <paramref name="content"/> to file that will become <paramref name="resourceName"/> in
/// <paramref name="assembly"/> the next time the project is built. Does nothing if
/// <paramref name="previousContent"/> and <paramref name="content"/> already match.
/// </summary>
/// <param name="assembly">The <see cref="Assembly"/> containing <paramref name="resourceName"/>.</param>
/// <param name="resourceName">
/// Name of the manifest resource in <paramref name="assembly"/>. A path relative to the test project
/// directory.
/// </param>
/// <param name="previousContent">
/// Current content of <paramref name="resourceName"/>. <c>null</c> if <paramref name="resourceName"/> does
/// not currently exist in <paramref name="assembly"/>.
/// </param>
/// <param name="content">
/// New content of <paramref name="resourceName"/> in <paramref name="assembly"/>.
/// </param>
[Conditional("GENERATE_BASELINES")]
public static void UpdateFile(Assembly assembly, string resourceName, string previousContent, string content)
{
// Normalize line endings to '\r\n' for comparison. This removes Environment.NewLine from the equation. Not
// worth updating files just because we generate baselines on a different system.
var normalizedPreviousContent = previousContent?.Replace("\r", "").Replace("\n", "\r\n");
var normalizedContent = content.Replace("\r", "").Replace("\n", "\r\n");
if (!string.Equals(normalizedPreviousContent, normalizedContent, StringComparison.Ordinal))
{
// The build system compiles every file under the resources folder as a resource available at runtime
// with the same name as the file name. Need to update this file on disc.
var projectPath = SolutionPathUtility.GetProjectPath("test", assembly);
var fullPath = Path.Combine(projectPath, resourceName);
WriteFile(fullPath, content);
}
}
private static bool Exists(Assembly assembly, string fullName)
{
var resourceNames = assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames)
{
// Resource names are case-sensitive.
if (string.Equals(fullName, resourceName, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
private static void WriteFile(string fullPath, string content)
{
// Serialize writes to minimize contention for file handles and directory access.
lock (writeLock)
{
// Write content to the file, creating it if necessary.
using (var stream = File.Open(fullPath, FileMode.Create, FileAccess.Write))
{
using (var writer = new StreamWriter(stream))
{
writer.Write(content);
}
}
}
}
}
}

View File

@ -0,0 +1,45 @@
// 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 System.IO;
using System.Reflection;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class SolutionPathUtility
{
private const string SolutionName = "Razor.sln";
/// <summary>
/// Gets the full path to the project.
/// </summary>
/// <param name="solutionRelativePath">
/// The parent directory of the project.
/// e.g. samples, test, or test/Websites
/// </param>
/// <param name="assembly">The project's assembly.</param>
/// <returns>The full path to the project.</returns>
public static string GetProjectPath(string solutionRelativePath, Assembly assembly)
{
var projectName = assembly.GetName().Name;
var applicationBasePath = PlatformServices.Default.Application.ApplicationBasePath;
var directoryInfo = new DirectoryInfo(applicationBasePath);
do
{
var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, SolutionName));
if (solutionFileInfo.Exists)
{
return Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath, projectName));
}
directoryInfo = directoryInfo.Parent;
}
while (directoryInfo.Parent != null);
throw new Exception($"Solution root could not be located using application root {applicationBasePath}.");
}
}
}

View File

@ -0,0 +1,54 @@
// 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 System.Text;
using Microsoft.AspNetCore.Razor.Evolution;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public static class LineMappingsSerializer
{
public static string Serialize(RazorCSharpDocument csharpDocument, RazorSourceDocument sourceDocument)
{
var builder = new StringBuilder();
var sourceFileName = sourceDocument.FileName;
var charBuffer = new char[sourceDocument.Length];
sourceDocument.CopyTo(0, charBuffer, 0, sourceDocument.Length);
var sourceContent = new string(charBuffer);
for (var i = 0; i < csharpDocument.LineMappings.Count; i++)
{
var lineMapping = csharpDocument.LineMappings[i];
if (!string.Equals(lineMapping.OriginalSpan.FilePath, sourceFileName, StringComparison.Ordinal))
{
continue;
}
builder.Append("Source Location: ");
AppendMappingLocation(builder, lineMapping.OriginalSpan, sourceContent);
builder.Append("Generated Location: ");
AppendMappingLocation(builder, lineMapping.GeneratedSpan, csharpDocument.GeneratedCode);
builder.AppendLine();
}
return builder.ToString();
}
private static void AppendMappingLocation(StringBuilder builder, SourceSpan location, string content)
{
builder
.AppendLine(location.ToString())
.Append("|");
for (var i = 0; i < location.Length; i++)
{
builder.Append(content[location.AbsoluteIndex + i]);
}
builder.AppendLine("|");
}
}
}

View File

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<TargetFrameworks>netcoreapp1.1;net452</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp1.1</TargetFrameworks>
<PreserveCompilationContext>true</PreserveCompilationContext>
<DefineConstants Condition="'$(GenerateBaselines)'=='true'">$(DefineConstants);GENERATE_BASELINES</DefineConstants>
<DefineConstants>$(DefineConstants);__RemoveThisBitTo__GENERATE_BASELINES</DefineConstants>
<DefaultItemExcludes>$(DefaultItemExcludes);TestFiles\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="TestFiles\**" />
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Runtime\Microsoft.AspNetCore.Razor.Runtime.csproj" />
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(DependencyModelVersion)" />
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,220 @@
// 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 System.IO;
using System.Text;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ModelDirectiveTest
{
[Fact]
public void ModelDirective_GetModelType_GetsTypeFromLastWellFormedDirective()
{
// Arrange
var codeDocument = CreateDocument(@"
@model Type1
@model Type2
@model
");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
var result = ModelDirective.GetModelType(irDocument);
// Assert
Assert.Equal("Type2", result);
}
[Fact]
public void ModelDirective_GetModelType_DefaultsToDynamic()
{
// Arrange
var codeDocument = CreateDocument(@" ");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
var result = ModelDirective.GetModelType(irDocument);
// Assert
Assert.Equal("dynamic", result);
}
[Fact]
public void ModelDirectivePass_Execute_ReplacesTModelInBaseType()
{
// Arrange
var codeDocument = CreateDocument(@"
@inherits BaseType<TModel>
@model Type1
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal("BaseType<Type1>", @class.BaseType);
}
[Fact]
public void ModelDirectivePass_Execute_ReplacesTModelInBaseType_DifferentOrdering()
{
// Arrange
var codeDocument = CreateDocument(@"
@model Type1
@inherits BaseType<TModel>
@model Type2
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal("BaseType<Type2>", @class.BaseType);
}
[Fact]
public void ModelDirectivePass_Execute_NoOpWithoutTModel()
{
// Arrange
var codeDocument = CreateDocument(@"
@inherits BaseType
@model Type1
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal("BaseType", @class.BaseType);
}
[Fact]
public void ModelDirectivePass_Execute_ReplacesTModelInBaseType_DefaultDynamic()
{
// Arrange
var codeDocument = CreateDocument(@"
@inherits BaseType<TModel>
");
var engine = CreateEngine();
var pass = new ModelDirective.Pass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal("BaseType<dynamic>", @class.BaseType);
}
private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}
private ClassDeclarationIRNode FindClassNode(RazorIRNode node)
{
var visitor = new ClassNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}
private RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
{
// Notice we're not registering the ModelDirective.Pass here so we can run it on demand.
b.AddDirective(ModelDirective.Directive);
});
}
private DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private string GetCSharpContent(RazorIRNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as RazorIRToken;
if (child.Kind == RazorIRToken.TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class ClassNodeVisitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Node { get; set; }
public override void VisitClass(ClassDeclarationIRNode node)
{
Node = node;
}
}
}
}

View File

@ -0,0 +1,235 @@
// 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.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ModelExpressionPassTest
{
[Fact]
public void ModelExpressionPass_NonModelExpressionProperty_Ignored()
{
// Arrange
var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<p foo=""17"">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Int32"))
.TagMatchingRule(rule =>
rule.RequireTagName("p"))
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ModelExpressionPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var tagHelper = FindTagHelperNode(irDocument);
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
var child = Assert.IsType<HtmlContentIRNode>(Assert.Single(setProperty.Children));
Assert.Equal("17", child.Content);
}
[Fact]
public void ModelExpressionPass_ModelExpressionProperty_SimpleExpression()
{
// Arrange
// Using \r\n here because we verify line mappings
var codeDocument = CreateDocument(
"@addTagHelper TestTagHelper, TestAssembly\r\n<p foo=\"Bar\">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName(typeof(ModelExpression).FullName))
.TagMatchingRule(rule =>
rule.RequireTagName("p"))
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ModelExpressionPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var tagHelper = FindTagHelperNode(irDocument);
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
var expression = Assert.IsType<CSharpExpressionIRNode>(Assert.Single(setProperty.Children));
Assert.Equal("ModelExpressionProvider.CreateModelExpression(ViewData, __model => __model.Bar)", GetCSharpContent(expression));
var originalNode = Assert.IsType<RazorIRToken>(expression.Children[2]);
Assert.Equal(RazorIRToken.TokenKind.CSharp, originalNode.Kind);
Assert.Equal("Bar", originalNode.Content);
Assert.Equal(new SourceSpan("test.cshtml", 51, 1, 8, 3), originalNode.Source.Value);
}
[Fact]
public void ModelExpressionPass_ModelExpressionProperty_ComplexExpression()
{
// Arrange
// Using \r\n here because we verify line mappings
var codeDocument = CreateDocument(
"@addTagHelper TestTagHelper, TestAssembly\r\n<p foo=\"@Bar\">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName(typeof(ModelExpression).FullName))
.TagMatchingRule(rule =>
rule.RequireTagName("p"))
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ModelExpressionPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var tagHelper = FindTagHelperNode(irDocument);
var setProperty = tagHelper.Children.OfType<SetTagHelperPropertyIRNode>().Single();
var expression = Assert.IsType<CSharpExpressionIRNode>(Assert.Single(setProperty.Children));
Assert.Equal("ModelExpressionProvider.CreateModelExpression(ViewData, __model => Bar)", GetCSharpContent(expression));
var originalNode = Assert.IsType<RazorIRToken>(expression.Children[1]);
Assert.Equal(RazorIRToken.TokenKind.CSharp, originalNode.Kind);
Assert.Equal("Bar", originalNode.Content);
Assert.Equal(new SourceSpan("test.cshtml", 52, 1, 9, 3), originalNode.Source.Value);
}
private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}
private RazorEngine CreateEngine(params TagHelperDescriptor[] tagHelpers)
{
return RazorEngine.Create(b =>
{
b.Features.Add(new TagHelperFeature(tagHelpers));
});
}
private DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDirectiveClassifierPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private TagHelperIRNode FindTagHelperNode(RazorIRNode node)
{
var visitor = new TagHelperNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}
private string GetCSharpContent(RazorIRNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as RazorIRToken;
if (child.Kind == RazorIRToken.TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class TagHelperNodeVisitor : RazorIRNodeWalker
{
public TagHelperIRNode Node { get; set; }
public override void VisitTagHelper(TagHelperIRNode node)
{
Node = node;
}
}
private class TagHelperFeature : ITagHelperFeature
{
public TagHelperFeature(TagHelperDescriptor[] tagHelpers)
{
Resolver = new TagHelperDescriptorResolver(tagHelpers);
}
public RazorEngine Engine { get; set; }
public ITagHelperDescriptorResolver Resolver { get; }
}
private class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
{
public TagHelperDescriptorResolver(TagHelperDescriptor[] tagHelpers)
{
TagHelpers = tagHelpers;
}
public TagHelperDescriptor[] TagHelpers { get; }
public IEnumerable<TagHelperDescriptor> Resolve(IList<RazorDiagnostic> errors)
{
return TagHelpers;
}
}
}
}

View File

@ -0,0 +1,126 @@
// 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 System.Linq;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.Extensions.FileProviders;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class MvcRazorTemplateEngineTest
{
[Fact]
public void GetDefaultImports_IncludesDefaultImports()
{
// Arrange
var expectedImports = new[]
{
"@using System",
"@using System.Linq",
"@using System.Collections.Generic",
"@using Microsoft.AspNetCore.Mvc",
"@using Microsoft.AspNetCore.Mvc.Rendering",
"@using Microsoft.AspNetCore.Mvc.ViewFeatures",
};
var mvcRazorTemplateEngine = new MvcRazorTemplateEngine(
RazorEngine.Create(),
GetRazorProject(new TestFileProvider()));
// Act
var imports = mvcRazorTemplateEngine.Options.DefaultImports;
// Assert
var importContent = GetContent(imports)
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Where(line => line.StartsWith("@using"));
Assert.Equal(expectedImports, importContent);
}
[Fact]
public void GetDefaultImports_IncludesDefaulInjects()
{
// Arrange
var expectedImports = new[]
{
"@inject global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> Html",
"@inject global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json",
"@inject global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component",
"@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url",
"@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider",
};
var mvcRazorTemplateEngine = new MvcRazorTemplateEngine(
RazorEngine.Create(),
GetRazorProject(new TestFileProvider()));
// Act
var imports = mvcRazorTemplateEngine.Options.DefaultImports;
// Assert
var importContent = GetContent(imports)
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Where(line => line.StartsWith("@inject"));
Assert.Equal(expectedImports, importContent);
}
[Fact]
public void GetDefaultImports_IncludesUrlTagHelper()
{
// Arrange
var mvcRazorTemplateEngine = new MvcRazorTemplateEngine(
RazorEngine.Create(),
GetRazorProject(new TestFileProvider()));
// Act
var imports = mvcRazorTemplateEngine.Options.DefaultImports;
// Assert
var importContent = GetContent(imports)
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Where(line => line.StartsWith("@addTagHelper"));
var addTagHelper = Assert.Single(importContent);
Assert.Equal("@addTagHelper Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor",
addTagHelper);
}
[Fact]
public void CreateCodeDocument_SetsRelativePathOnOutput()
{
// Arrange
var path = "/Views/Home/Index.cshtml";
var fileProvider = new TestFileProvider();
fileProvider.AddFile(path, "Hello world");
var mvcRazorTemplateEngine = new MvcRazorTemplateEngine(
RazorEngine.Create(),
GetRazorProject(fileProvider));
// Act
var codeDocument = mvcRazorTemplateEngine.CreateCodeDocument(path);
// Assert
Assert.Equal(path, codeDocument.GetRelativePath());
}
private string GetContent(RazorSourceDocument imports)
{
var contentChars = new char[imports.Length];
imports.CopyTo(0, contentChars, 0, imports.Length);
return new string(contentChars);
}
private static RazorProject GetRazorProject(IFileProvider fileProvider)
{
var razorProject = new Mock<RazorProject>();
razorProject.Setup(s => s.GetItem(It.IsAny<string>()))
.Returns((string path) => {
var fileInfo = fileProvider.GetFileInfo(path);
return new DefaultRazorProjectItem(fileInfo, null, path);
});
return razorProject.Object;
}
}
}

View File

@ -0,0 +1,244 @@
// 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.IO;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class MvcViewDocumentClassifierPassTest
{
[Fact]
public void MvcViewDocumentClassifierPass_SetsDocumentKind()
{
// Arrange
var codeDocument = CreateDocument("some-content");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Assert.Equal("mvc.1.0.view", irDocument.DocumentKind);
}
[Fact]
public void MvcViewDocumentClassifierPass_NoOpsIfDocumentKindIsAlreadySet()
{
// Arrange
var codeDocument = CreateDocument("some-content");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
irDocument.DocumentKind = "some-value";
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Assert.Equal("some-value", irDocument.DocumentKind);
}
[Fact]
public void MvcViewDocumentClassifierPass_SetsNamespace()
{
// Arrange
var codeDocument = CreateDocument("some-content");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal("AspNetCore", visitor.Namespace.Content);
}
[Fact]
public void MvcViewDocumentClassifierPass_SetsClass()
{
// Arrange
var codeDocument = CreateDocument("some-content");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
codeDocument.SetRelativePath("Test.cshtml");
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal("global::Microsoft.AspNetCore.Razor.RazorPage<TModel>", visitor.Class.BaseType);
Assert.Equal("public", visitor.Class.AccessModifier);
Assert.Equal("Test_cshtml", visitor.Class.Name);
}
[Theory]
[InlineData("/Views/Home/Index.cshtml", "_Views_Home_Index_cshtml")]
[InlineData("/Areas/MyArea/Views/Home/About.cshtml", "_Areas_MyArea_Views_Home_About_cshtml")]
public void MvcViewDocumentClassifierPass_UsesRelativePathToGenerateTypeName(string relativePath, string expected)
{
// Arrange
var codeDocument = CreateDocument("some-content");
codeDocument.SetRelativePath(relativePath);
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void MvcViewDocumentClassifierPass_UsesAbsolutePath_IfRelativePathIsNotSet()
{
// Arrange
var expected = "x___application_Views_Home_Index_cshtml";
var path = @"x::\application\Views\Home\Index.cshtml";
var codeDocument = CreateDocument("some-content", path);
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void MvcViewDocumentClassifierPass_SanitizesClassName()
{
// Arrange
var expected = "path_with_invalid_chars";
var codeDocument = CreateDocument("some-content");
codeDocument.SetRelativePath("path.with+invalid-chars");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void MvcViewDocumentClassifierPass_SetsUpExecuteAsyncMethod()
{
// Arrange
var codeDocument = CreateDocument("some-content");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new MvcViewDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal("ExecuteAsync", visitor.Method.Name);
Assert.Equal("public", visitor.Method.AccessModifier);
Assert.Equal("global::System.Threading.Tasks.Task", visitor.Method.ReturnType);
Assert.Equal(new[] { "async", "override" }, visitor.Method.Modifiers);
}
private static RazorCodeDocument CreateDocument(string content, string filePath = null)
{
filePath = filePath ?? Path.Combine(Directory.GetCurrentDirectory(), "Test.cshtml");
var source = RazorSourceDocument.Create(content, filePath);
return RazorCodeDocument.Create(source);
}
private static RazorEngine CreateEngine() => RazorEngine.Create();
private static DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorIRLoweringPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private class Visitor : RazorIRNodeWalker
{
public NamespaceDeclarationIRNode Namespace { get; private set; }
public ClassDeclarationIRNode Class { get; private set; }
public RazorMethodDeclarationIRNode Method { get; private set; }
public override void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
{
Method = node;
}
public override void VisitNamespace(NamespaceDeclarationIRNode node)
{
Namespace = node;
base.VisitNamespace(node);
}
public override void VisitClass(ClassDeclarationIRNode node)
{
Class = node;
base.VisitClass(node);
}
}
}
}

View File

@ -0,0 +1,6 @@
// 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.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -0,0 +1,286 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.FileProviders;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class RazorEngineTest
{
private static Assembly _assembly = typeof(RazorEngineTest).GetTypeInfo().Assembly;
#region Runtime
[Fact]
public void RazorEngine_Basic_Runtime()
{
RunRuntimeTest("Basic");
}
[Fact]
public void RazorEngine_ViewImports_Runtime()
{
RunRuntimeTest("_ViewImports");
}
[Fact]
public void RazorEngine_Inject_Runtime()
{
RunRuntimeTest("Inject");
}
[Fact]
public void RazorEngine_InjectWithModel_Runtime()
{
RunRuntimeTest("InjectWithModel");
}
[Fact]
public void RazorEngine_InjectWithSemicolon_Runtime()
{
RunRuntimeTest("InjectWithSemicolon");
}
[Fact]
public void RazorEngine_Model_Runtime()
{
RunRuntimeTest("Model");
}
[Fact]
public void RazorEngine_ModelExpressionTagHelper_Runtime()
{
RunRuntimeTest("ModelExpressionTagHelper");
}
#endregion
#region DesignTime
[Fact]
public void RazorEngine_Basic_DesignTime()
{
RunDesignTimeTest("Basic");
}
[Fact]
public void RazorEngine_ViewImports_DesignTime()
{
RunDesignTimeTest("_ViewImports");
}
[Fact]
public void RazorEngine_Inject_DesignTime()
{
RunDesignTimeTest("Inject");
}
[Fact]
public void RazorEngine_InjectWithModel_DesignTime()
{
RunDesignTimeTest("InjectWithModel");
}
[Fact]
public void RazorEngine_InjectWithSemicolon_DesignTime()
{
RunDesignTimeTest("InjectWithSemicolon");
}
[Fact]
public void RazorEngine_Model_DesignTime()
{
RunDesignTimeTest("Model");
}
[Fact]
public void RazorEngine_MultipleModels_DesignTime()
{
RunDesignTimeTest("MultipleModels");
}
[Fact]
public void RazorEngine_ModelExpressionTagHelper_DesignTime()
{
RunDesignTimeTest("ModelExpressionTagHelper");
}
#endregion
private static void RunRuntimeTest(string testName)
{
// Arrange
var inputFile = "TestFiles/Input/" + testName + ".cshtml";
var outputFile = "TestFiles/Output/Runtime/" + testName + ".cs";
var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false);
var engine = RazorEngine.Create(b =>
{
InjectDirective.Register(b);
ModelDirective.Register(b);
b.AddTargetExtension(new InjectDirectiveTargetExtension());
b.Features.Add(new ModelExpressionPass());
b.Features.Add(new MvcViewDocumentClassifierPass());
b.Features.Add(new DefaultInstrumentationPass());
b.Features.Add(new DefaultTagHelperFeature());
b.Features.Add(GetMetadataReferenceFeature());
});
var inputContent = ResourceFile.ReadResource(_assembly, inputFile, sourceFile: true);
var fileProvider = new TestFileProvider();
fileProvider.AddFile(inputFile, inputContent);
var fileInfo = fileProvider.GetFileInfo(inputFile);
var razorTemplateEngine = new MvcRazorTemplateEngine(engine, GetRazorProject(fileProvider));
var razorProjectItem = new DefaultRazorProjectItem(fileInfo, basePath: null, path: inputFile);
var codeDocument = razorTemplateEngine.CreateCodeDocument(razorProjectItem);
codeDocument.Items["SuppressUniqueIds"] = "test";
codeDocument.Items["NewLineString"] = "\r\n";
// Act
var csharpDocument = razorTemplateEngine.GenerateCode(codeDocument);
// Assert
Assert.Empty(csharpDocument.Diagnostics);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, csharpDocument.GeneratedCode);
#else
Assert.Equal(expectedCode, csharpDocument.GeneratedCode, ignoreLineEndingDifferences: true);
#endif
}
private static void RunDesignTimeTest(string testName)
{
// Arrange
var inputFile = "TestFiles/Input/" + testName + ".cshtml";
var outputFile = "TestFiles/Output/DesignTime/" + testName + ".cs";
var expectedCode = ResourceFile.ReadResource(_assembly, outputFile, sourceFile: false);
var lineMappingOutputFile = "TestFiles/Output/DesignTime/" + testName + ".mappings.txt";
var expectedMappings = ResourceFile.ReadResource(_assembly, lineMappingOutputFile, sourceFile: false);
var engine = RazorEngine.CreateDesignTime(b =>
{
InjectDirective.Register(b);
ModelDirective.Register(b);
b.AddTargetExtension(new InjectDirectiveTargetExtension());
b.Features.Add(new ModelExpressionPass());
b.Features.Add(new MvcViewDocumentClassifierPass());
b.Features.Add(new DefaultTagHelperFeature());
b.Features.Add(GetMetadataReferenceFeature());
});
var inputContent = ResourceFile.ReadResource(_assembly, inputFile, sourceFile: true);
var fileProvider = new TestFileProvider();
fileProvider.AddFile(inputFile, inputContent);
var fileInfo = fileProvider.GetFileInfo(inputFile);
var razorTemplateEngine = new MvcRazorTemplateEngine(engine, GetRazorProject(fileProvider));
var razorProjectItem = new DefaultRazorProjectItem(fileInfo, basePath: null, path: inputFile);
var codeDocument = razorTemplateEngine.CreateCodeDocument(razorProjectItem);
codeDocument.Items["SuppressUniqueIds"] = "test";
codeDocument.Items["NewLineString"] = "\r\n";
// Act
var csharpDocument = razorTemplateEngine.GenerateCode(codeDocument);
// Assert
Assert.Empty(csharpDocument.Diagnostics);
var serializedMappings = LineMappingsSerializer.Serialize(csharpDocument, codeDocument.Source);
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_assembly, outputFile, expectedCode, csharpDocument.GeneratedCode);
ResourceFile.UpdateFile(_assembly, lineMappingOutputFile, expectedMappings, serializedMappings);
#else
Assert.Equal(expectedCode, csharpDocument.GeneratedCode, ignoreLineEndingDifferences: true);
Assert.Equal(expectedMappings, serializedMappings, ignoreLineEndingDifferences: true);
#endif
}
private static IRazorEngineFeature GetMetadataReferenceFeature()
{
var currentAssembly = typeof(RazorEngineTest).GetTypeInfo().Assembly;
var dependencyContext = DependencyContext.Load(currentAssembly);
var references = dependencyContext.CompileLibraries.SelectMany(l => l.ResolveReferencePaths())
.Select(assemblyPath => MetadataReference.CreateFromFile(assemblyPath))
.ToList<MetadataReference>();
var syntaxTree = CreateTagHelperSyntaxTree();
var compilation = CSharpCompilation.Create("Microsoft.AspNetCore.Mvc.Razor", syntaxTree, references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
var stream = new MemoryStream();
var compilationResult = compilation.Emit(stream, options: new EmitOptions() );
stream.Position = 0;
Assert.True(compilationResult.Success);
references.Add(MetadataReference.CreateFromStream(stream));
var feature = new DefaultMetadataReferenceFeature()
{
References = references,
};
return feature;
}
private static IEnumerable<SyntaxTree> CreateTagHelperSyntaxTree()
{
var text = $@"
public class UrlResolutionTagHelper : {typeof(TagHelper).FullName}
{{
}}";
return new SyntaxTree[] { CSharpSyntaxTree.ParseText(text) };
}
private static RazorProject GetRazorProject(IFileProvider fileProvider)
{
var razorProject = new Mock<RazorProject>();
return razorProject.Object;
}
}
public class DefaultRazorProjectItem : RazorProjectItem
{
public DefaultRazorProjectItem(IFileInfo fileInfo, string basePath, string path)
{
FileInfo = fileInfo;
BasePath = basePath;
Path = path;
}
public IFileInfo FileInfo { get; }
public override string BasePath { get; }
public override string Path { get; }
public override string PhysicalPath { get; }
public override bool Exists => FileInfo.Exists;
public override Stream Read()
{
return FileInfo.CreateReadStream();
}
}
}

View File

@ -0,0 +1,270 @@
// 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.IO;
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class RazorPageDocumentClassifierPassTest
{
[Fact]
public void RazorPageDocumentClassifierPass_SetsDocumentKind()
{
// Arrange
var codeDocument = CreateDocument("@page");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new RazorPageDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Assert.Equal("mvc.1.0.razor-page", irDocument.DocumentKind);
}
[Fact]
public void RazorPageDocumentClassifierPass_NoOpsIfDocumentKindIsAlreadySet()
{
// Arrange
var codeDocument = CreateDocument("@page");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
irDocument.DocumentKind = "some-value";
var pass = new RazorPageDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Assert.Equal("some-value", irDocument.DocumentKind);
}
[Fact]
public void RazorPageDocumentClassifierPass_NoOpsIfPageDirectiveIsMalformed()
{
// Arrange
var codeDocument = CreateDocument("@page+1");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
irDocument.DocumentKind = "some-value";
var pass = new RazorPageDocumentClassifierPass
{
Engine = engine
};
// Act
pass.Execute(codeDocument, irDocument);
// Assert
Assert.Equal("some-value", irDocument.DocumentKind);
}
[Fact]
public void RazorPageDocumentClassifierPass_SetsNamespace()
{
// Arrange
var codeDocument = CreateDocument("@page");
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
Assert.Equal("AspNetCore", visitor.Namespace.Content);
}
[Fact]
public void RazorPageDocumentClassifierPass_SetsClass()
{
// Arrange
var codeDocument = CreateDocument("@page");
var engine = CreateEngine();
var irDocument = CreateIRDocument(engine, codeDocument);
var pass = new RazorPageDocumentClassifierPass
{
Engine = engine
};
codeDocument.SetRelativePath("Test.cshtml");
// Act
pass.Execute(codeDocument, irDocument);
var visitor = new Visitor();
visitor.Visit(irDocument);
// Assert
Assert.Equal("global::Microsoft.AspNetCore.RazorPages.Page", visitor.Class.BaseType);
Assert.Equal("public", visitor.Class.AccessModifier);
Assert.Equal("Test_cshtml", visitor.Class.Name);
}
[Theory]
[InlineData("/Views/Home/Index.cshtml", "_Views_Home_Index_cshtml")]
[InlineData("/Areas/MyArea/Views/Home/About.cshtml", "_Areas_MyArea_Views_Home_About_cshtml")]
public void RazorPageDocumentClassifierPass_UsesRelativePathToGenerateTypeName(string relativePath, string expected)
{
// Arrange
var codeDocument = CreateDocument("@page");
codeDocument.SetRelativePath(relativePath);
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
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void RazorPageDocumentClassifierPass_UsesAbsolutePath_IfRelativePathIsNotSet()
{
// Arrange
var expected = "x___application_Views_Home_Index_cshtml";
var path = @"x::\application\Views\Home\Index.cshtml";
var codeDocument = CreateDocument("@page", path);
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
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void RazorPageDocumentClassifierPass_SanitizesClassName()
{
// Arrange
var expected = "path_with_invalid_chars";
var codeDocument = CreateDocument("@page");
codeDocument.SetRelativePath("path.with+invalid-chars");
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
Assert.Equal(expected, visitor.Class.Name);
}
[Fact]
public void RazorPageDocumentClassifierPass_SetsUpExecuteAsyncMethod()
{
// Arrange
var codeDocument = CreateDocument("@page");
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
Assert.Equal("ExecuteAsync", visitor.Method.Name);
Assert.Equal("public", visitor.Method.AccessModifier);
Assert.Equal("global::System.Threading.Tasks.Task", visitor.Method.ReturnType);
Assert.Equal(new[] { "async", "override" }, visitor.Method.Modifiers);
}
private static RazorCodeDocument CreateDocument(string content, string filePath = null)
{
filePath = filePath ?? Path.Combine(Directory.GetCurrentDirectory(), "Test.cshtml");
var source = RazorSourceDocument.Create(content, filePath);
return RazorCodeDocument.Create(source);
}
private static RazorEngine CreateEngine()
{
return RazorEngine.Create(b =>
{
PageDirective.Register(b);
});
}
private static DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorIRLoweringPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private class Visitor : RazorIRNodeWalker
{
public NamespaceDeclarationIRNode Namespace { get; private set; }
public ClassDeclarationIRNode Class { get; private set; }
public RazorMethodDeclarationIRNode Method { get; private set; }
public override void VisitRazorMethodDeclaration(RazorMethodDeclarationIRNode node)
{
Method = node;
}
public override void VisitNamespace(NamespaceDeclarationIRNode node)
{
Namespace = node;
base.VisitNamespace(node);
}
public override void VisitClass(ClassDeclarationIRNode node)
{
Class = node;
base.VisitClass(node);
}
}
}
}

View File

@ -0,0 +1,186 @@
// 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 System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class TestFileChangeToken : IChangeToken
{
public bool HasChanged => throw new NotImplementedException();
public bool ActiveChangeCallbacks => throw new NotImplementedException();
public IDisposable RegisterChangeCallback(Action<object> callback, object state)
{
throw new NotImplementedException();
}
}
public class TestFileInfo : IFileInfo
{
private string _content;
public bool IsDirectory { get; } = false;
public DateTimeOffset LastModified { get; set; }
public long Length { get; set; }
public string Name { get; set; }
public string PhysicalPath { get; set; }
public string Content
{
get { return _content; }
set
{
_content = value;
Length = Encoding.UTF8.GetByteCount(Content);
}
}
public bool Exists
{
get { return true; }
}
public Stream CreateReadStream()
{
var bytes = Encoding.UTF8.GetBytes(Content);
return new MemoryStream(bytes);
}
}
public class TestFileProvider : IFileProvider
{
private readonly Dictionary<string, IFileInfo> _lookup =
new Dictionary<string, IFileInfo>(StringComparer.Ordinal);
private readonly Dictionary<string, IDirectoryContents> _directoryContentsLookup =
new Dictionary<string, IDirectoryContents>();
private readonly Dictionary<string, TestFileChangeToken> _fileTriggers =
new Dictionary<string, TestFileChangeToken>(StringComparer.Ordinal);
public virtual IDirectoryContents GetDirectoryContents(string subpath)
{
if (_directoryContentsLookup.TryGetValue(subpath, out var value))
{
return value;
}
return new NotFoundDirectoryContents();
}
public TestFileInfo AddFile(string path, string contents)
{
var fileInfo = new TestFileInfo
{
Content = contents,
PhysicalPath = path,
Name = Path.GetFileName(path),
LastModified = DateTime.UtcNow,
};
AddFile(path, fileInfo);
return fileInfo;
}
public void AddFile(string path, IFileInfo contents)
{
_lookup[path] = contents;
}
public void DeleteFile(string path)
{
_lookup.Remove(path);
}
public virtual IFileInfo GetFileInfo(string subpath)
{
if (_lookup.ContainsKey(subpath))
{
return _lookup[subpath];
}
else
{
return new NotFoundFileInfo();
}
}
public virtual IChangeToken Watch(string filter)
{
TestFileChangeToken changeToken;
if (!_fileTriggers.TryGetValue(filter, out changeToken) || changeToken.HasChanged)
{
changeToken = new TestFileChangeToken();
_fileTriggers[filter] = changeToken;
}
return changeToken;
}
private class NotFoundFileInfo : IFileInfo
{
public bool Exists
{
get
{
return false;
}
}
public bool IsDirectory
{
get
{
throw new NotImplementedException();
}
}
public DateTimeOffset LastModified
{
get
{
throw new NotImplementedException();
}
}
public long Length
{
get
{
throw new NotImplementedException();
}
}
public string Name
{
get
{
throw new NotImplementedException();
}
}
public string PhysicalPath
{
get
{
throw new NotImplementedException();
}
}
public Stream CreateReadStream()
{
throw new NotImplementedException();
}
}
}
}

View File

@ -0,0 +1,4 @@
<div class="@logo">
Hello world
@Html.Input("SomeKey")
</div>

View File

@ -0,0 +1,2 @@
@using MyNamespace
@inject MyApp MyPropertyName

View File

@ -0,0 +1,3 @@
@model MyModel
@inject MyApp MyPropertyName
@inject MyService<TModel> Html

View File

@ -0,0 +1,5 @@
@model MyModel
@inject MyApp MyPropertyName;
@inject MyService<TModel> Html;
@inject MyApp MyPropertyName2 ;
@inject MyService<TModel> Html2 ;

View File

@ -0,0 +1 @@
@model System.Collections.IEnumerable

View File

@ -0,0 +1,6 @@
@model DateTime
@addTagHelper Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test
<input-test for="Now" />
<input-test for="@Model" />

View File

@ -0,0 +1,2 @@
@model ThisShouldBeGenerated
@model System.Collections.IEnumerable

View File

@ -0,0 +1 @@
@inject IHtmlHelper<TModel> Model

View File

@ -0,0 +1,108 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_Basic_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
#line 1 "TestFiles/Input/Basic.cshtml"
__o = logo;
#line default
#line hidden
#line 3 "TestFiles/Input/Basic.cshtml"
__o = Html.Input("SomeKey");
#line default
#line hidden
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

View File

@ -0,0 +1,10 @@
Source Location: (13:0,13 [4] TestFiles/Input/Basic.cshtml)
|logo|
Generated Location: (2321:85,13 [4] )
|logo|
Source Location: (43:2,5 [21] TestFiles/Input/Basic.cshtml)
|Html.Input("SomeKey")|
Generated Location: (2405:90,6 [21] )
|Html.Input("SomeKey")|

View File

@ -0,0 +1,113 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
#line 1 "TestFiles/Input/Inject.cshtml"
using MyNamespace;
#line default
#line hidden
public class TestFiles_Input_Inject_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
MyApp __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object MyPropertyName = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

View File

@ -0,0 +1,10 @@
Source Location: (28:1,8 [5] TestFiles/Input/Inject.cshtml)
|MyApp|
Generated Location: (2166:84,0 [5] )
|MyApp|
Source Location: (34:1,14 [14] TestFiles/Input/Inject.cshtml)
|MyPropertyName|
Generated Location: (2268:88,14 [14] )
|MyPropertyName|

View File

@ -0,0 +1,120 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_InjectWithModel_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<MyModel>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
MyModel __typeHelper = null;
}
))();
((System.Action)(() => {
MyApp __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object MyPropertyName = null;
}
))();
((System.Action)(() => {
MyService<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
}
}

View File

@ -0,0 +1,25 @@
Source Location: (7:0,7 [7] TestFiles/Input/InjectWithModel.cshtml)
|MyModel|
Generated Location: (2083:79,0 [7] )
|MyModel|
Source Location: (24:1,8 [5] TestFiles/Input/InjectWithModel.cshtml)
|MyApp|
Generated Location: (2173:83,0 [5] )
|MyApp|
Source Location: (30:1,14 [14] TestFiles/Input/InjectWithModel.cshtml)
|MyPropertyName|
Generated Location: (2275:87,14 [14] )
|MyPropertyName|
Source Location: (54:2,8 [17] TestFiles/Input/InjectWithModel.cshtml)
|MyService<TModel>|
Generated Location: (2359:91,0 [17] )
|MyService<TModel>|
Source Location: (72:2,26 [4] TestFiles/Input/InjectWithModel.cshtml)
|Html|
Generated Location: (2473:95,14 [4] )
|Html|

View File

@ -0,0 +1,140 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_InjectWithSemicolon_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<MyModel>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
MyModel __typeHelper = null;
}
))();
((System.Action)(() => {
MyApp __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object MyPropertyName = null;
}
))();
((System.Action)(() => {
MyService<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
MyApp __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object MyPropertyName2 = null;
}
))();
((System.Action)(() => {
MyService<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html2 = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html2 { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName2 { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
}
}

View File

@ -0,0 +1,45 @@
Source Location: (7:0,7 [7] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyModel|
Generated Location: (2087:79,0 [7] )
|MyModel|
Source Location: (24:1,8 [5] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyApp|
Generated Location: (2177:83,0 [5] )
|MyApp|
Source Location: (30:1,14 [14] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyPropertyName|
Generated Location: (2279:87,14 [14] )
|MyPropertyName|
Source Location: (58:2,8 [17] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyService<TModel>|
Generated Location: (2363:91,0 [17] )
|MyService<TModel>|
Source Location: (76:2,26 [4] TestFiles/Input/InjectWithSemicolon.cshtml)
|Html|
Generated Location: (2477:95,14 [4] )
|Html|
Source Location: (93:3,8 [5] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyApp|
Generated Location: (2551:99,0 [5] )
|MyApp|
Source Location: (99:3,14 [15] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyPropertyName2|
Generated Location: (2653:103,14 [15] )
|MyPropertyName2|
Source Location: (129:4,8 [17] TestFiles/Input/InjectWithSemicolon.cshtml)
|MyService<TModel>|
Generated Location: (2738:107,0 [17] )
|MyService<TModel>|
Source Location: (147:4,26 [5] TestFiles/Input/InjectWithSemicolon.cshtml)
|Html2|
Generated Location: (2852:111,14 [5] )
|Html2|

View File

@ -0,0 +1,102 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_Model_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<System.Collections.IEnumerable>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
System.Collections.IEnumerable __typeHelper = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<System.Collections.IEnumerable> Html { get; private set; }
}
}

View File

@ -0,0 +1,5 @@
Source Location: (7:0,7 [30] TestFiles/Input/Model.cshtml)
|System.Collections.IEnumerable|
Generated Location: (2096:79,0 [30] )
|System.Collections.IEnumerable|

View File

@ -0,0 +1,119 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_ModelExpressionTagHelper_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<DateTime>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
DateTime __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test";
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
private global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper __Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper>();
#line 5 "TestFiles/Input/ModelExpressionTagHelper.cshtml"
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For = ModelExpressionProvider.CreateModelExpression(ViewData, __model => __model.Now);
#line default
#line hidden
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper>();
#line 6 "TestFiles/Input/ModelExpressionTagHelper.cshtml"
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For = ModelExpressionProvider.CreateModelExpression(ViewData, __model => Model);
#line default
#line hidden
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<DateTime> Html { get; private set; }
}
}

View File

@ -0,0 +1,20 @@
Source Location: (7:0,7 [8] TestFiles/Input/ModelExpressionTagHelper.cshtml)
|DateTime|
Generated Location: (2093:79,0 [8] )
|DateTime|
Source Location: (33:2,14 [108] TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test|
Generated Location: (2214:83,30 [108] )
|Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Extensions.Test|
Source Location: (162:4,17 [3] TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Now|
Generated Location: (3108:95,144 [3] )
|Now|
Source Location: (189:5,18 [5] TestFiles/Input/ModelExpressionTagHelper.cshtml)
|Model|
Generated Location: (3508:101,136 [5] )
|Model|

View File

@ -0,0 +1,106 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_MultipleModels_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<System.Collections.IEnumerable>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
ThisShouldBeGenerated __typeHelper = null;
}
))();
((System.Action)(() => {
System.Collections.IEnumerable __typeHelper = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<System.Collections.IEnumerable> Html { get; private set; }
}
}

View File

@ -0,0 +1,10 @@
Source Location: (7:0,7 [21] TestFiles/Input/MultipleModels.cshtml)
|ThisShouldBeGenerated|
Generated Location: (2105:79,0 [21] )
|ThisShouldBeGenerated|
Source Location: (37:1,7 [30] TestFiles/Input/MultipleModels.cshtml)
|System.Collections.IEnumerable|
Generated Location: (2209:83,0 [30] )
|System.Collections.IEnumerable|

View File

@ -0,0 +1,108 @@
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input__ViewImports_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Html = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Json = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IViewComponentHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Component = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.IUrlHelper __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Url = null;
}
))();
((System.Action)(() => {
global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object ModelExpressionProvider = null;
}
))();
((System.Action)(() => {
System.Object __typeHelper = "Microsoft.AspNetCore.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor";
}
))();
((System.Action)(() => {
IHtmlHelper<TModel> __typeHelper = null;
}
))();
((System.Action)(() => {
System.Object Model = null;
}
))();
}
#pragma warning restore 219
private static System.Object __o = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public IHtmlHelper<dynamic> Model { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

View File

@ -0,0 +1,10 @@
Source Location: (8:0,8 [19] TestFiles/Input/_ViewImports.cshtml)
|IHtmlHelper<TModel>|
Generated Location: (2080:79,0 [19] )
|IHtmlHelper<TModel>|
Source Location: (28:0,28 [5] TestFiles/Input/_ViewImports.cshtml)
|Model|
Generated Location: (2196:83,14 [5] )
|Model|

View File

@ -0,0 +1,73 @@
#pragma checksum "TestFiles/Input/Basic.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "54a70ff4c6d27ac6cdc6725cb6bab12012015729"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_Basic_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
BeginContext(0, 4, true);
WriteLiteral("<div");
EndContext();
BeginWriteAttribute("class", " class=\"", 4, "\"", 17, 1);
#line 1 "TestFiles/Input/Basic.cshtml"
WriteAttributeValue("", 12, logo, 12, 5, false);
#line default
#line hidden
EndWriteAttribute();
BeginContext(18, 24, true);
WriteLiteral(">\r\n Hello world\r\n ");
EndContext();
BeginContext(43, 21, false);
#line 3 "TestFiles/Input/Basic.cshtml"
Write(Html.Input("SomeKey"));
#line default
#line hidden
EndContext();
BeginContext(64, 8, true);
WriteLiteral("\r\n</div>");
EndContext();
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

View File

@ -0,0 +1,57 @@
#pragma checksum "TestFiles/Input/Inject.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "225760ec3beca02a80469066fab66433e90ddc2e"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
#line 1 "TestFiles/Input/Inject.cshtml"
using MyNamespace;
#line default
#line hidden
public class TestFiles_Input_Inject_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

View File

@ -0,0 +1,52 @@
#pragma checksum "TestFiles/Input/InjectWithModel.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "1f010500f93116162444110956e512df61642f4e"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_InjectWithModel_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<MyModel>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
}
}

View File

@ -0,0 +1,56 @@
#pragma checksum "TestFiles/Input/InjectWithSemicolon.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "fc807ec0dc76610bdca62f482fefd7f584348df9"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_InjectWithSemicolon_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<MyModel>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html2 { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName2 { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyService<MyModel> Html { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public MyApp MyPropertyName { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
}
}

View File

@ -0,0 +1,50 @@
#pragma checksum "TestFiles/Input/Model.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "31c5b047a450ac9f6dc4116626667d26bfb657ba"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_Model_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<System.Collections.IEnumerable>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<System.Collections.IEnumerable> Html { get; private set; }
}
}

View File

@ -0,0 +1,121 @@
#pragma checksum "TestFiles/Input/ModelExpressionTagHelper.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "55aa7d9113d1666f0c8e05c6ad9b86fc8464b277"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input_ModelExpressionTagHelper_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<DateTime>
{
#line hidden
#pragma warning disable 0414
private string __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext __tagHelperExecutionContext = null;
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner __tagHelperRunner = new global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner();
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __backed__tagHelperScopeManager = null;
private global::Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager __tagHelperScopeManager
{
get
{
if (__backed__tagHelperScopeManager == null)
{
__backed__tagHelperScopeManager = new Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperScopeManager(StartTagHelperWritingScope, EndTagHelperWritingScope);
}
return __backed__tagHelperScopeManager;
}
}
private global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper __Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = null;
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
BeginContext(17, 2, true);
WriteLiteral("\r\n");
EndContext();
BeginContext(143, 2, true);
WriteLiteral("\r\n");
EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input-test", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.SelfClosing, "test", async() => {
}
);
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper>();
__tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper);
#line 5 "TestFiles/Input/ModelExpressionTagHelper.cshtml"
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For = ModelExpressionProvider.CreateModelExpression(ViewData, __model => __model.Now);
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("for", __Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
BeginContext(145, 24, false);
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
if (!__tagHelperExecutionContext.Output.IsContentModified)
{
await __tagHelperExecutionContext.SetOutputContentAsync();
}
Write(__tagHelperExecutionContext.Output);
__tagHelperExecutionContext = __tagHelperScopeManager.End();
EndContext();
BeginContext(169, 2, true);
WriteLiteral("\r\n");
EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input-test", global::Microsoft.AspNetCore.Razor.TagHelpers.TagMode.SelfClosing, "test", async() => {
}
);
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper = CreateTagHelper<global::Microsoft.AspNetCore.Mvc.Razor.Extensions.InputTestTagHelper>();
__tagHelperExecutionContext.Add(__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper);
#line 6 "TestFiles/Input/ModelExpressionTagHelper.cshtml"
__Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For = ModelExpressionProvider.CreateModelExpression(ViewData, __model => Model);
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("for", __Microsoft_AspNetCore_Mvc_Razor_Extensions_InputTestTagHelper.For, global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
BeginContext(171, 27, false);
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
if (!__tagHelperExecutionContext.Output.IsContentModified)
{
await __tagHelperExecutionContext.SetOutputContentAsync();
}
Write(__tagHelperExecutionContext.Output);
__tagHelperExecutionContext = __tagHelperScopeManager.End();
EndContext();
BeginContext(198, 2, true);
WriteLiteral("\r\n");
EndContext();
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<DateTime> Html { get; private set; }
}
}

View File

@ -0,0 +1,52 @@
#pragma checksum "TestFiles/Input/_ViewImports.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "778b41f9406fcda776cc3f1bf093f3b21956e582"
namespace AspNetCore
{
#line hidden
using System;
using System.Threading.Tasks;
#line 2 ""
using System.Linq;
#line default
#line hidden
#line 3 ""
using System.Collections.Generic;
#line default
#line hidden
#line 4 ""
using Microsoft.AspNetCore.Mvc;
#line default
#line hidden
#line 5 ""
using Microsoft.AspNetCore.Mvc.Rendering;
#line default
#line hidden
#line 6 ""
using Microsoft.AspNetCore.Mvc.ViewFeatures;
#line default
#line hidden
public class TestFiles_Input__ViewImports_cshtml : global::Microsoft.AspNetCore.Razor.RazorPage<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
}
#pragma warning restore 1998
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public IHtmlHelper<dynamic> Model { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IUrlHelper Url { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.IViewComponentHelper Component { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IJsonHelper Json { get; private set; }
[global::Microsoft.AspNetCore.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
}
}

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 Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ViewComponentTagHelperDescriptorConventionsTest
{
[Fact]
public void IsViewComponentDescriptor_ReturnsFalseForInvalidDescriptor()
{
//Arrange
var tagHelperDescriptor = CreateTagHelperDescriptor();
// Act
var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions
.IsViewComponentDescriptor(tagHelperDescriptor);
// Assert
Assert.False(isViewComponentDescriptor);
}
[Fact]
public void IsViewComponentDescriptor_ReturnsTrueForValidDescriptor()
{
// Arrange
var descriptor = CreateViewComponentTagHelperDescriptor();
// Act
var isViewComponentDescriptor = ViewComponentTagHelperDescriptorConventions
.IsViewComponentDescriptor(descriptor);
// Assert
Assert.True(isViewComponentDescriptor);
}
private static TagHelperDescriptor CreateTagHelperDescriptor()
{
var descriptor = ITagHelperDescriptorBuilder.Create("TypeName", "AssemblyName")
.TagMatchingRule(rule =>
rule.RequireTagName("tag-name"))
.Build();
return descriptor;
}
private static TagHelperDescriptor CreateViewComponentTagHelperDescriptor()
{
var descriptor = ITagHelperDescriptorBuilder.Create("TypeName", "AssemblyName")
.TagMatchingRule(rule =>
rule.RequireTagName("tag-name"))
.AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "ViewComponentName")
.Build();
return descriptor;
}
}
}

View File

@ -0,0 +1,388 @@
// 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.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Razor.Evolution.Intermediate;
using Microsoft.AspNetCore.Razor.Evolution.Legacy;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ViewComponentTagHelperPassTest
{
[Fact]
public void ViewComponentTagHelperPass_Execute_IgnoresRegularTagHelper()
{
// Arrange
var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<p foo=""17"">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Int32"))
.TagMatchingRule(rule =>
rule.RequireTagName("p"))
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ViewComponentTagHelperPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var @class = FindClassNode(irDocument);
Assert.Equal(2, @class.Children.Count); // No class node created for a VCTH
for (var i = 0; i < @class.Children.Count; i++)
{
Assert.IsNotType<CSharpStatementIRNode>(@class.Children[i]);
}
}
[Fact]
public void ViewComponentTagHelperPass_Execute_CreatesViewComponentTagHelper()
{
// Arrange
var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<tagcloud foo=""17"">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Int32")
.PropertyName("Foo"))
.TagMatchingRule(rule =>
rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud")
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ViewComponentTagHelperPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
var expectedVCTHName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper";
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var tagHelper = FindTagHelperNode(irDocument);
Assert.Equal(expectedVCTHName, Assert.IsType<CreateTagHelperIRNode>(tagHelper.Children[1]).TagHelperTypeName);
Assert.Equal(expectedVCTHName, Assert.IsType<SetTagHelperPropertyIRNode>(tagHelper.Children[2]).TagHelperTypeName);
var @class = FindClassNode(irDocument);
Assert.Equal(3, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpStatementIRNode>(@class.Children[2]);
Assert.Equal(
@"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")]
public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)
{
_helper = helper;
}
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }
public System.Int32 Foo { get; set; }
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)
{
(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var content = await _helper.InvokeAsync(""TagCloud"", new { Foo });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
",
vcthClass.Content,
ignoreLineEndingDifferences: true);
}
[Fact]
public void ViewComponentTagHelperPass_Execute_CreatesViewComponentTagHelper_WithIndexer()
{
// Arrange
var codeDocument = CreateDocument(@"
@addTagHelper TestTagHelper, TestAssembly
<tagcloud tag-foo=""17"">");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>")
.PropertyName("Tags")
.AsDictionary("foo-", "System.Int32"))
.TagMatchingRule(rule =>
rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud")
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ViewComponentTagHelperPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
var expectedVCTHName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper";
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var tagHelper = FindTagHelperNode(irDocument);
Assert.Equal(expectedVCTHName, Assert.IsType<CreateTagHelperIRNode>(tagHelper.Children[1]).TagHelperTypeName);
Assert.IsType<AddTagHelperHtmlAttributeIRNode>(tagHelper.Children[2]);
var @class = FindClassNode(irDocument);
Assert.Equal(3, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpStatementIRNode>(@class.Children[2]);
Assert.Equal(
@"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")]
public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)
{
_helper = helper;
}
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }
public System.Collections.Generic.Dictionary<System.String, System.Int32> Tags { get; set; }
= new System.Collections.Generic.Dictionary<System.String, System.Int32>();
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)
{
(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var content = await _helper.InvokeAsync(""TagCloud"", new { Tags });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
",
vcthClass.Content,
ignoreLineEndingDifferences: true);
}
[Fact]
public void ViewComponentTagHelperPass_Execute_CreatesViewComponentTagHelper_Nested()
{
// Arrange
var codeDocument = CreateDocument(@"
@addTagHelper *, TestAssembly
<p foo=""17""><tagcloud foo=""17""></p>");
var tagHelpers = new[]
{
ITagHelperDescriptorBuilder.Create("PTestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Int32"))
.TagMatchingRule(rule =>
rule.RequireTagName("p"))
.Build(),
ITagHelperDescriptorBuilder.Create("TestTagHelper", "TestAssembly")
.BindAttribute(attribute =>
attribute
.Name("Foo")
.TypeName("System.Int32")
.PropertyName("Foo"))
.TagMatchingRule(rule =>
rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperDescriptorConventions.ViewComponentNameKey, "TagCloud")
.Build()
};
var engine = CreateEngine(tagHelpers);
var pass = new ViewComponentTagHelperPass()
{
Engine = engine,
};
var irDocument = CreateIRDocument(engine, codeDocument);
var expectedTagHelperName = "PTestTagHelper";
var expectedVCTHName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper";
// Act
pass.Execute(codeDocument, irDocument);
// Assert
var outerTagHelper = FindTagHelperNode(irDocument);
Assert.Equal(expectedTagHelperName, Assert.IsType<CreateTagHelperIRNode>(outerTagHelper.Children[1]).TagHelperTypeName);
Assert.Equal(expectedTagHelperName, Assert.IsType<SetTagHelperPropertyIRNode>(outerTagHelper.Children[2]).TagHelperTypeName);
var vcth = FindTagHelperNode(outerTagHelper.Children[0]);
Assert.Equal(expectedVCTHName, Assert.IsType<CreateTagHelperIRNode>(vcth.Children[1]).TagHelperTypeName);
Assert.Equal(expectedVCTHName, Assert.IsType<SetTagHelperPropertyIRNode>(vcth.Children[2]).TagHelperTypeName);
var @class = FindClassNode(irDocument);
Assert.Equal(3, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpStatementIRNode>(@class.Children[2]);
Assert.Equal(
@"[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute(""tagcloud"")]
public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TagCloudViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)
{
_helper = helper;
}
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }
public System.Int32 Foo { get; set; }
public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)
{
(_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);
var content = await _helper.InvokeAsync(""TagCloud"", new { Foo });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
",
vcthClass.Content,
ignoreLineEndingDifferences: true);
}
private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}
private RazorEngine CreateEngine(params TagHelperDescriptor[] tagHelpers)
{
return RazorEngine.Create(b =>
{
b.Features.Add(new MvcViewDocumentClassifierPass());
b.Features.Add(new TagHelperFeature(tagHelpers));
});
}
private DocumentIRNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
for (var i = 0; i < engine.Phases.Count; i++)
{
var phase = engine.Phases[i];
phase.Execute(codeDocument);
if (phase is IRazorDirectiveClassifierPhase)
{
break;
}
}
return codeDocument.GetIRDocument();
}
private ClassDeclarationIRNode FindClassNode(RazorIRNode node)
{
var visitor = new ClassDeclarationNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}
private TagHelperIRNode FindTagHelperNode(RazorIRNode node)
{
var visitor = new TagHelperNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}
private string GetCSharpContent(RazorIRNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as RazorIRToken;
if (child.Kind == RazorIRToken.TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class ClassDeclarationNodeVisitor : RazorIRNodeWalker
{
public ClassDeclarationIRNode Node { get; set; }
public override void VisitClass(ClassDeclarationIRNode node)
{
Node = node;
}
}
private class TagHelperNodeVisitor : RazorIRNodeWalker
{
public TagHelperIRNode Node { get; set; }
public override void VisitTagHelper(TagHelperIRNode node)
{
Node = node;
}
}
private class TagHelperFeature : ITagHelperFeature
{
public TagHelperFeature(TagHelperDescriptor[] tagHelpers)
{
Resolver = new TagHelperDescriptorResolver(tagHelpers);
}
public RazorEngine Engine { get; set; }
public ITagHelperDescriptorResolver Resolver { get; }
}
private class TagHelperDescriptorResolver : ITagHelperDescriptorResolver
{
public TagHelperDescriptorResolver(TagHelperDescriptor[] tagHelpers)
{
TagHelpers = tagHelpers;
}
public TagHelperDescriptor[] TagHelpers { get; }
public IEnumerable<TagHelperDescriptor> Resolve(IList<RazorDiagnostic> errors)
{
return TagHelpers;
}
}
}
}

View File

@ -0,0 +1,3 @@
{
"shadowCopy": false
}