Make ViewComponentTagHelper use extension intermediate nodes

This commit is contained in:
Ajay Bhargav Baaskaran 2017-08-09 20:03:55 -07:00
parent 364fc1a55d
commit 655a693e4a
20 changed files with 800 additions and 544 deletions

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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension
{
void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node);
}
}

View File

@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
EnsureDesignTime(builder);
builder.Features.Add(new ViewComponentTagHelperPass());
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
}
private static void EnsureDesignTime(IRazorEngineBuilder builder)

View File

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly;
public string ClassName { get; set; }
public TagHelperDescriptor TagHelper { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ViewComponentTagHelperIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IViewComponentTagHelperTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IViewComponentTagHelperTargetExtension>(context);
return;
}
extension.WriteViewComponentTagHelper(context, this);
}
}
}

View File

@ -1,13 +1,8 @@
// 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.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@ -18,8 +13,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
// Run after the default taghelper pass
public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000;
private static readonly string[] PublicModifiers = new[] { "public" };
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @namespace = documentNode.FindPrimaryNamespace();
@ -142,145 +135,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper)
{
var writer = new CodeWriter();
WriteClass(context, writer, tagHelper);
var code = new CSharpCodeIntermediateNode();
code.Children.Add(new IntermediateToken()
var node = new ViewComponentTagHelperIntermediateNode()
{
Kind = TokenKind.CSharp,
Content = writer.GenerateCode()
});
ClassName = context.GetClassName(tagHelper),
TagHelper = tagHelper
};
context.Class.Children.Add(code);
}
private void WriteClass(Context context, CodeWriter writer, TagHelperDescriptor tagHelper)
{
// Add target element.
BuildTargetElementString(writer, tagHelper);
// Initialize declaration.
var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
var className = context.GetClassName(tagHelper);
using (writer.BuildClassDeclaration(PublicModifiers, className, tagHelperTypeName, interfaces: null))
{
// 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, tagHelper);
// Add process method.
BuildProcessMethodString(writer, tagHelper);
}
}
private void BuildConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write("global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment("_helper")
.Write("helper")
.WriteLine(";");
}
}
private void BuildAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute")
.WriteParameterSeparator()
.Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute")
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
$"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext",
"ViewContext");
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void BuildProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
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(tagHelper);
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 tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void BuildTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute")
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
context.Class.Children.Add(node);
}
private struct Context

View File

@ -0,0 +1,178 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension
{
private static readonly string[] PublicModifiers = new[] { "public" };
public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper";
public string ViewComponentHelperVariableName { get; set; } = "_helper";
public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync";
public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute";
public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute";
public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext";
public string ViewContextPropertyName { get; set; } = "ViewContext";
public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute";
public string TagHelperProcessMethodName { get; set; } = "ProcessAsync";
public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext";
public string TagHelperContextVariableName { get; set; } = "context";
public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput";
public string TagHelperOutputVariableName { get; set; } = "output";
public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName";
public string TagHelperOutputContentPropertyName { get; set; } = "Content";
public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent";
public string TagHelperContentVariableName { get; set; } = "content";
public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware";
public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize";
public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node)
{
// Add target element.
WriteTargetElementString(context.CodeWriter, node.TagHelper);
// Initialize declaration.
using (context.CodeWriter.BuildClassDeclaration(PublicModifiers, node.ClassName, TagHelperTypeName, interfaces: null))
{
// Add view component helper.
context.CodeWriter.WriteVariableDeclaration(
$"private readonly {ViewComponentHelperTypeName}",
ViewComponentHelperVariableName,
value: null);
// Add constructor.
WriteConstructorString(context.CodeWriter, node.ClassName);
// Add attributes.
WriteAttributeDeclarations(context.CodeWriter, node.TagHelper);
// Add process method.
WriteProcessMethodString(context.CodeWriter, node.TagHelper);
}
}
private void WriteConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write($"{ViewComponentHelperTypeName} helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment(ViewComponentHelperVariableName)
.Write("helper")
.WriteLine(";");
}
}
private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write(HtmlAttributeNotBoundAttributeTypeName)
.WriteParameterSeparator()
.Write(ViewContextAttributeTypeName)
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
ViewContextTypeName,
ViewContextPropertyName);
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
using (writer.BuildMethodDeclaration(
$"public override async",
$"global::{typeof(Task).FullName}",
TagHelperProcessMethodName,
new Dictionary<string, string>()
{
{ TagHelperContextTypeName, TagHelperContextVariableName },
{ TagHelperOutputTypeName, TagHelperOutputVariableName }
}))
{
writer.WriteInstanceMethodInvocation(
$"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?",
IViewContextAwareContextualizeMethodName,
new[] { ViewContextPropertyName });
var methodParameters = GetMethodParameters(tagHelper);
writer.Write("var ")
.WriteStartAssignment(TagHelperContentVariableName)
.WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters);
writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}")
.WriteLine("null;");
writer.WriteInstanceMethodInvocation(
$"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}",
TagHelperContentSetMethodName,
new[] { TagHelperContentVariableName });
}
}
private string[] GetMethodParameters(TagHelperDescriptor tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName)
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
}
}
}

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.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public interface IViewComponentTagHelperTargetExtension : ICodeTargetExtension
{
void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node);
}
}

View File

@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
builder.AddTargetExtension(new TemplateTargetExtension()
{
TemplateTypeName = "global::Microsoft.AspNetCore.Mvc.Razor.HelperResult",

View File

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public sealed class ViewComponentTagHelperIntermediateNode : ExtensionIntermediateNode
{
public override IntermediateNodeCollection Children { get; } = IntermediateNodeCollection.ReadOnly;
public string ClassName { get; set; }
public TagHelperDescriptor TagHelper { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ViewComponentTagHelperIntermediateNode>(this, visitor);
}
public override void WriteNode(CodeTarget target, CodeRenderingContext context)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var extension = target.GetExtension<IViewComponentTagHelperTargetExtension>();
if (extension == null)
{
ReportMissingCodeTargetExtension<IViewComponentTagHelperTargetExtension>(context);
return;
}
extension.WriteViewComponentTagHelper(context, this);
}
}
}

View File

@ -1,13 +1,8 @@
// 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.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@ -18,8 +13,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
// Run after the default taghelper pass
public override int Order => IntermediateNodePassBase.DefaultFeatureOrder + 2000;
private static readonly string[] PublicModifiers = new[] { "public" };
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @namespace = documentNode.FindPrimaryNamespace();
@ -142,145 +135,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
private void AddTagHelperClass(Context context, TagHelperDescriptor tagHelper)
{
var writer = new CodeWriter();
WriteClass(context, writer, tagHelper);
var code = new CSharpCodeIntermediateNode();
code.Children.Add(new IntermediateToken()
var node = new ViewComponentTagHelperIntermediateNode()
{
Kind = TokenKind.CSharp,
Content = writer.GenerateCode()
});
ClassName = context.GetClassName(tagHelper),
TagHelper = tagHelper
};
context.Class.Children.Add(code);
}
private void WriteClass(Context context, CodeWriter writer, TagHelperDescriptor tagHelper)
{
// Add target element.
BuildTargetElementString(writer, tagHelper);
// Initialize declaration.
var tagHelperTypeName = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
var className = context.GetClassName(tagHelper);
using (writer.BuildClassDeclaration(PublicModifiers, className, tagHelperTypeName, interfaces: null))
{
// 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, tagHelper);
// Add process method.
BuildProcessMethodString(writer, tagHelper);
}
}
private void BuildConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write("global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment("_helper")
.Write("helper")
.WriteLine(";");
}
}
private void BuildAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write("Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute")
.WriteParameterSeparator()
.Write($"global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute")
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
$"global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext",
"ViewContext");
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void BuildProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
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(tagHelper);
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 tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void BuildTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation("Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute")
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
context.Class.Children.Add(node);
}
private struct Context

View File

@ -0,0 +1,178 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
internal class ViewComponentTagHelperTargetExtension : IViewComponentTagHelperTargetExtension
{
private static readonly string[] PublicModifiers = new[] { "public" };
public string TagHelperTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelper";
public string ViewComponentHelperTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.IViewComponentHelper";
public string ViewComponentHelperVariableName { get; set; } = "_helper";
public string ViewComponentInvokeMethodName { get; set; } = "InvokeAsync";
public string HtmlAttributeNotBoundAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute";
public string ViewContextAttributeTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute";
public string ViewContextTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext";
public string ViewContextPropertyName { get; set; } = "ViewContext";
public string HtmlTargetElementAttributeTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute";
public string TagHelperProcessMethodName { get; set; } = "ProcessAsync";
public string TagHelperContextTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext";
public string TagHelperContextVariableName { get; set; } = "context";
public string TagHelperOutputTypeName { get; set; } = "Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput";
public string TagHelperOutputVariableName { get; set; } = "output";
public string TagHelperOutputTagNamePropertyName { get; set; } = "TagName";
public string TagHelperOutputContentPropertyName { get; set; } = "Content";
public string TagHelperContentSetMethodName { get; set; } = "SetHtmlContent";
public string TagHelperContentVariableName { get; set; } = "content";
public string IViewContextAwareTypeName { get; set; } = "global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware";
public string IViewContextAwareContextualizeMethodName { get; set; } = "Contextualize";
public void WriteViewComponentTagHelper(CodeRenderingContext context, ViewComponentTagHelperIntermediateNode node)
{
// Add target element.
WriteTargetElementString(context.CodeWriter, node.TagHelper);
// Initialize declaration.
using (context.CodeWriter.BuildClassDeclaration(PublicModifiers, node.ClassName, TagHelperTypeName, interfaces: null))
{
// Add view component helper.
context.CodeWriter.WriteVariableDeclaration(
$"private readonly {ViewComponentHelperTypeName}",
ViewComponentHelperVariableName,
value: null);
// Add constructor.
WriteConstructorString(context.CodeWriter, node.ClassName);
// Add attributes.
WriteAttributeDeclarations(context.CodeWriter, node.TagHelper);
// Add process method.
WriteProcessMethodString(context.CodeWriter, node.TagHelper);
}
}
private void WriteConstructorString(CodeWriter writer, string className)
{
writer.Write("public ")
.Write(className)
.Write("(")
.Write($"{ViewComponentHelperTypeName} helper")
.WriteLine(")");
using (writer.BuildScope())
{
writer.WriteStartAssignment(ViewComponentHelperVariableName)
.Write("helper")
.WriteLine(";");
}
}
private void WriteAttributeDeclarations(CodeWriter writer, TagHelperDescriptor tagHelper)
{
writer.Write("[")
.Write(HtmlAttributeNotBoundAttributeTypeName)
.WriteParameterSeparator()
.Write(ViewContextAttributeTypeName)
.WriteLine("]");
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
ViewContextTypeName,
ViewContextPropertyName);
foreach (var attribute in tagHelper.BoundAttributes)
{
writer.WriteAutoPropertyDeclaration(
PublicModifiers,
attribute.TypeName,
attribute.GetPropertyName());
if (attribute.IndexerTypeName != null)
{
writer.Write(" = ")
.WriteStartNewObject(attribute.TypeName)
.WriteEndMethodInvocation();
}
}
}
private void WriteProcessMethodString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
using (writer.BuildMethodDeclaration(
$"public override async",
$"global::{typeof(Task).FullName}",
TagHelperProcessMethodName,
new Dictionary<string, string>()
{
{ TagHelperContextTypeName, TagHelperContextVariableName },
{ TagHelperOutputTypeName, TagHelperOutputVariableName }
}))
{
writer.WriteInstanceMethodInvocation(
$"({ViewComponentHelperVariableName} as {IViewContextAwareTypeName})?",
IViewContextAwareContextualizeMethodName,
new[] { ViewContextPropertyName });
var methodParameters = GetMethodParameters(tagHelper);
writer.Write("var ")
.WriteStartAssignment(TagHelperContentVariableName)
.WriteInstanceMethodInvocation($"await {ViewComponentHelperVariableName}", ViewComponentInvokeMethodName, methodParameters);
writer.WriteStartAssignment($"{TagHelperOutputVariableName}.{TagHelperOutputTagNamePropertyName}")
.WriteLine("null;");
writer.WriteInstanceMethodInvocation(
$"{TagHelperOutputVariableName}.{TagHelperOutputContentPropertyName}",
TagHelperContentSetMethodName,
new[] { TagHelperContentVariableName });
}
}
private string[] GetMethodParameters(TagHelperDescriptor tagHelper)
{
var propertyNames = tagHelper.BoundAttributes.Select(attribute => attribute.GetPropertyName());
var joinedPropertyNames = string.Join(", ", propertyNames);
var parametersString = $"new {{ { joinedPropertyNames } }}";
var viewComponentName = tagHelper.GetViewComponentName();
var methodParameters = new[] { $"\"{viewComponentName}\"", parametersString };
return methodParameters;
}
private void WriteTargetElementString(CodeWriter writer, TagHelperDescriptor tagHelper)
{
Debug.Assert(tagHelper.TagMatchingRules.Count() == 1);
var rule = tagHelper.TagMatchingRules.First();
writer.Write("[")
.WriteStartMethodInvocation(HtmlTargetElementAttributeTypeName)
.WriteStringLiteral(rule.TagName)
.WriteLine(")]");
}
}
}

View File

@ -57,25 +57,24 @@ global::System.Object __typeHelper = "*, AppCode";
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
}
}
#pragma warning restore 1591

View File

@ -56,5 +56,4 @@ Document -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n
ViewComponentTagHelper -

View File

@ -87,25 +87,24 @@ namespace AspNetCore
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
}
}
#pragma warning restore 1591

View File

@ -41,5 +41,4 @@ Document -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n
ViewComponentTagHelper -

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
Assert.Equal(3, @class.Children.Count); // No class node created for a VCTH
for (var i = 0; i < @class.Children.Count; i++)
{
Assert.IsNotType<CSharpCodeIntermediateNode>(@class.Children[i]);
Assert.IsNotType<ViewComponentTagHelperIntermediateNode>(@class.Children[i]);
}
}
@ -94,32 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
var @class = FindClassNode(irDocument);
Assert.Equal(4, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children.Last());
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children.Last());
}
[Fact]
@ -165,33 +139,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
var @class = FindClassNode(irDocument);
Assert.Equal(4, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children[3]);
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children[3]);
}
[Fact]
@ -249,32 +197,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
var @class = FindClassNode(irDocument);
Assert.Equal(5, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children.Last());
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children.Last());
}
private RazorCodeDocument CreateDocument(string content)
@ -329,21 +252,6 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
return visitor.Node;
}
private string GetCSharpContent(IntermediateNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as IntermediateToken;
if (child.Kind == TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class ClassDeclarationNodeVisitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Node { get; set; }

View File

@ -0,0 +1,120 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
{
public class ViewComponentTagHelperTargetExtensionTest
{
[Fact]
public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper()
{
// Arrange
var tagHelper = TagHelperDescriptorBuilder
.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly")
.TypeName("__Generated__TagCloudViewComponentTagHelper")
.BoundAttributeDescriptor(attribute => attribute
.Name("Foo")
.TypeName("System.Int32")
.PropertyName("Foo"))
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud")
.Build();
var extension = new ViewComponentTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateRuntime();
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = "__Generated__TagCloudViewComponentTagHelper",
TagHelper = tagHelper
};
// Act
extension.WriteViewComponentTagHelper(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode();
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);
}
}
",
csharp,
ignoreLineEndingDifferences: true);
}
[Fact]
public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper_WithIndexer()
{
// Arrange
var tagHelper = TagHelperDescriptorBuilder
.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly")
.TypeName("__Generated__TagCloudViewComponentTagHelper")
.BoundAttributeDescriptor(attribute => attribute
.Name("Foo")
.TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>")
.PropertyName("Tags")
.AsDictionaryAttribute("foo-", "System.Int32"))
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud")
.Build();
var extension = new ViewComponentTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateRuntime();
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = "__Generated__TagCloudViewComponentTagHelper",
TagHelper = tagHelper
};
// Act
extension.WriteViewComponentTagHelper(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode();
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);
}
}
",
csharp,
ignoreLineEndingDifferences: true);
}
}
}

View File

@ -57,25 +57,24 @@ global::System.Object __typeHelper = "*, AppCode";
[global::Microsoft.AspNetCore.Mvc.Razor.Internal.RazorInjectAttribute]
public global::Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper<dynamic> Html { get; private set; }
[Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
public class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper
{
private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;
public __Generated__TestViewComponentTagHelper(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.String firstName { 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("Test", new { firstName });
output.TagName = null;
output.Content.SetHtmlContent(content);
}
}
}
}
#pragma warning restore 1591

View File

@ -54,5 +54,4 @@ Document -
Inject -
Inject -
Inject -
CSharpCode -
IntermediateToken - - CSharp - [Microsoft.AspNetCore.Razor.TagHelpers.HtmlTargetElementAttribute("vc:test")]\npublic class __Generated__TestViewComponentTagHelper : Microsoft.AspNetCore.Razor.TagHelpers.TagHelper\n{\n private readonly global::Microsoft.AspNetCore.Mvc.IViewComponentHelper _helper = null;\n public __Generated__TestViewComponentTagHelper(global::Microsoft.AspNetCore.Mvc.IViewComponentHelper helper)\n {\n _helper = helper;\n }\n [Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeNotBoundAttribute, global::Microsoft.AspNetCore.Mvc.ViewFeatures.ViewContextAttribute]\n public global::Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }\n public System.String firstName { get; set; }\n public override async global::System.Threading.Tasks.Task ProcessAsync(Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext context, Microsoft.AspNetCore.Razor.TagHelpers.TagHelperOutput output)\n {\n (_helper as global::Microsoft.AspNetCore.Mvc.ViewFeatures.IViewContextAware)?.Contextualize(ViewContext);\n var content = await _helper.InvokeAsync("Test", new { firstName });\n output.TagName = null;\n output.Content.SetHtmlContent(content);\n }\n}\n
ViewComponentTagHelper -

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
Assert.Equal(3, @class.Children.Count); // No class node created for a VCTH
for (var i = 0; i < @class.Children.Count; i++)
{
Assert.IsNotType<CSharpCodeIntermediateNode>(@class.Children[i]);
Assert.IsNotType<ViewComponentTagHelperIntermediateNode>(@class.Children[i]);
}
}
@ -94,32 +93,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
var @class = FindClassNode(irDocument);
Assert.Equal(4, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children.Last());
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children.Last());
}
[Fact]
@ -165,33 +139,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
var @class = FindClassNode(irDocument);
Assert.Equal(4, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children[3]);
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children[3]);
}
[Fact]
@ -230,7 +178,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
};
var irDocument = CreateIRDocument(engine, codeDocument);
var vcthFullName = "AspNetCore.test_cshtml.__Generated__TagCloudViewComponentTagHelper";
// Act
@ -249,32 +197,7 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
var @class = FindClassNode(irDocument);
Assert.Equal(5, @class.Children.Count);
var vcthClass = Assert.IsType<CSharpCodeIntermediateNode>(@class.Children.Last());
var tokenNode = vcthClass.Children[0] as IntermediateToken;
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);
}
}
",
tokenNode.Content,
ignoreLineEndingDifferences: true);
Assert.Equal(TokenKind.CSharp, tokenNode.Kind);
Assert.IsType<ViewComponentTagHelperIntermediateNode>(@class.Children.Last());
}
private RazorCodeDocument CreateDocument(string content)
@ -329,21 +252,6 @@ public class __Generated__TagCloudViewComponentTagHelper : Microsoft.AspNetCore.
return visitor.Node;
}
private string GetCSharpContent(IntermediateNode node)
{
var builder = new StringBuilder();
for (var i = 0; i < node.Children.Count; i++)
{
var child = node.Children[i] as IntermediateToken;
if (child.Kind == TokenKind.CSharp)
{
builder.Append(child.Content);
}
}
return builder.ToString();
}
private class ClassDeclarationNodeVisitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Node { get; set; }

View File

@ -0,0 +1,120 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.CodeGeneration;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
{
public class ViewComponentTagHelperTargetExtensionTest
{
[Fact]
public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper()
{
// Arrange
var tagHelper = TagHelperDescriptorBuilder
.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly")
.TypeName("__Generated__TagCloudViewComponentTagHelper")
.BoundAttributeDescriptor(attribute => attribute
.Name("Foo")
.TypeName("System.Int32")
.PropertyName("Foo"))
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud")
.Build();
var extension = new ViewComponentTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateRuntime();
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = "__Generated__TagCloudViewComponentTagHelper",
TagHelper = tagHelper
};
// Act
extension.WriteViewComponentTagHelper(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode();
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);
}
}
",
csharp,
ignoreLineEndingDifferences: true);
}
[Fact]
public void WriteViewComponentTagHelper_GeneratesViewComponentTagHelper_WithIndexer()
{
// Arrange
var tagHelper = TagHelperDescriptorBuilder
.Create(ViewComponentTagHelperConventions.Kind, "TestTagHelper", "TestAssembly")
.TypeName("__Generated__TagCloudViewComponentTagHelper")
.BoundAttributeDescriptor(attribute => attribute
.Name("Foo")
.TypeName("System.Collections.Generic.Dictionary<System.String, System.Int32>")
.PropertyName("Tags")
.AsDictionaryAttribute("foo-", "System.Int32"))
.TagMatchingRuleDescriptor(rule => rule.RequireTagName("tagcloud"))
.AddMetadata(ViewComponentTagHelperMetadata.Name, "TagCloud")
.Build();
var extension = new ViewComponentTagHelperTargetExtension();
var context = TestCodeRenderingContext.CreateRuntime();
var node = new ViewComponentTagHelperIntermediateNode()
{
ClassName = "__Generated__TagCloudViewComponentTagHelper",
TagHelper = tagHelper
};
// Act
extension.WriteViewComponentTagHelper(context, node);
// Assert
var csharp = context.CodeWriter.GenerateCode();
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);
}
}
",
csharp,
ignoreLineEndingDifferences: true);
}
}
}