Add support for generic-typed components (#1417)

* Add the ability to discover generic types/properties

* Add @typeparam directive

Adds the ability to declare a generic-typed component using Razor.

* Add a 'type parameter' property to generic components

* Adds the ability to consume generic-typed components
This commit is contained in:
Ryan Nowak 2018-09-16 14:01:15 -07:00 committed by GitHub
parent b99d805bc0
commit 354752cf16
59 changed files with 2670 additions and 66 deletions

View File

@ -311,6 +311,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
BoundAttribute = valueAttribute, // Might be null if it doesn't match a component attribute
PropertyName = valueAttribute?.GetPropertyName(),
TagHelper = valueAttribute == null ? null : node.TagHelper,
TypeName = valueAttribute?.IsWeaklyTyped() == false ? valueAttribute.TypeName : null,
};
valueNode.Children.Clear();
@ -326,6 +327,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
BoundAttribute = changeAttribute, // Might be null if it doesn't match a component attribute
PropertyName = changeAttribute?.GetPropertyName(),
TagHelper = changeAttribute == null ? null : node.TagHelper,
TypeName = changeAttribute?.IsWeaklyTyped() == false ? changeAttribute.TypeName : null,
};
changeNode.Children.Clear();

View File

@ -343,6 +343,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
throw new ArgumentNullException(nameof(node));
}
foreach (var typeArgument in node.TypeArguments)
{
context.RenderNode(typeArgument);
}
foreach (var attribute in node.Attributes)
{
context.RenderNode(attribute);
@ -363,7 +368,10 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Consider what would happen if the user's cursor was inside the element. At
// design -time we want to render an empty lambda to provide proper scoping
// for any code that the user types.
context.RenderNode(new ComponentChildContentIntermediateNode());
context.RenderNode(new ComponentChildContentIntermediateNode()
{
TypeName = BlazorApi.RenderFragment.FullTypeName,
});
}
foreach (var capture in node.Captures)
@ -425,7 +433,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.CodeWriter.Write(DesignTimeVariable);
context.CodeWriter.Write(" = ");
context.CodeWriter.Write("new ");
context.CodeWriter.Write(node.BoundAttribute.TypeName);
context.CodeWriter.Write(node.TypeName);
context.CodeWriter.Write("(");
context.CodeWriter.WriteLine();
@ -448,7 +456,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
context.CodeWriter.Write(BlazorApi.RuntimeHelpers.TypeCheck);
context.CodeWriter.Write("<");
context.CodeWriter.Write(node.BoundAttribute.TypeName);
context.CodeWriter.Write(node.TypeName);
context.CodeWriter.Write(">");
context.CodeWriter.Write("(");
}
@ -504,6 +512,41 @@ namespace Microsoft.AspNetCore.Blazor.Razor
_scopeStack.CloseScope(context);
}
public override void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentExtensionNode node)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (node == null)
{
throw new ArgumentNullException(nameof(node));
}
// At design type we want write the equivalent of:
//
// __o = typeof(TItem);
context.CodeWriter.Write(DesignTimeVariable);
context.CodeWriter.Write(" = ");
context.CodeWriter.Write("typeof(");
var tokens = GetCSharpTokens(node);
for (var i = 0; i < tokens.Count; i++)
{
WriteCSharpToken(context, tokens[i]);
}
context.CodeWriter.Write(");");
context.CodeWriter.WriteLine();
IReadOnlyList<IntermediateToken> GetCSharpTokens(ComponentTypeArgumentExtensionNode arg)
{
// We generally expect all children to be CSharp, this is here just in case.
return arg.FindDescendantNodes<IntermediateToken>().Where(t => t.IsCSharp).ToArray();
}
}
public override void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node)
{
if (context == null)

View File

@ -263,5 +263,23 @@ namespace Microsoft.AspNetCore.Blazor.Razor
childContent2.AttributeName,
component2.TagName);
}
public static readonly RazorDiagnosticDescriptor GenericComponentMissingTypeArgument =
new RazorDiagnosticDescriptor(
"BL10000",
() => "The component '{0}' is missing required type arguments. Specify the missing types using the attributes: {1}.",
RazorDiagnosticSeverity.Error);
public static RazorDiagnostic Create_GenericComponentMissingTypeArgument(
SourceSpan? source,
ComponentExtensionNode component,
IEnumerable<BoundAttributeDescriptor> attributes)
{
Debug.Assert(component.Component.IsGenericTypedComponent());
var attributesText = string.Join(", ", attributes.Select(a => $"'{a.Name}'"));
return RazorDiagnostic.Create(GenericComponentMissingTypeArgument, source ?? SourceSpan.Undefined, component.TagName, attributesText);
}
}
}

View File

@ -54,6 +54,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
InjectDirective.Register(builder);
LayoutDirective.Register(builder);
PageDirective.Register(builder);
TypeParamDirective.Register(builder);
builder.Features.Remove(builder.Features.OfType<IImportProjectFeature>().Single());
builder.Features.Add(new BlazorImportProjectFeature());
@ -82,6 +83,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
builder.Features.Add(new RefLoweringPass());
builder.Features.Add(new BindLoweringPass());
builder.Features.Add(new TemplateDiagnosticPass());
builder.Features.Add(new GenericComponentPass());
builder.Features.Add(new ChildContentDiagnosticPass());
builder.Features.Add(new HtmlBlockPass());

View File

@ -46,6 +46,10 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public static readonly string RuntimeName = "Blazor.IComponent";
public readonly static string TagHelperKind = "Blazor.Component";
public readonly static string GenericTypedKey = "Blazor.GenericTyped";
public readonly static string TypeParameterKey = "Blazor.TypeParameter";
}
public static class EventHandler

View File

@ -19,6 +19,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public abstract void WriteComponentChildContent(CodeRenderingContext context, ComponentChildContentIntermediateNode node);
public abstract void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentExtensionNode node);
public abstract void WriteHtmlElement(CodeRenderingContext context, HtmlElementIntermediateNode node);
public abstract void WriteHtmlBlock(CodeRenderingContext context, HtmlBlockIntermediateNode node);

View File

@ -307,6 +307,9 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.CodeWriter.Write(");");
context.CodeWriter.WriteLine();
// We can skip type arguments during runtime codegen, they are handled in the
// type/parameter declarations.
foreach (var attribute in node.Attributes)
{
context.RenderNode(attribute);
@ -322,7 +325,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
context.RenderNode(capture);
}
// builder.OpenComponent<TComponent>(42);
// builder.CloseComponent();
context.CodeWriter.Write(_scopeStack.BuilderVarName);
context.CodeWriter.Write(".");
context.CodeWriter.Write(BlazorApi.RenderTreeBuilder.CloseComponent);
@ -376,7 +379,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
(node.BoundAttribute?.IsChildContentProperty() ?? false))
{
context.CodeWriter.Write("new ");
context.CodeWriter.Write(node.BoundAttribute.TypeName);
context.CodeWriter.Write(node.TypeName);
context.CodeWriter.Write("(");
for (var i = 0; i < tokens.Count; i++)
@ -392,7 +395,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
context.CodeWriter.Write(BlazorApi.RuntimeHelpers.TypeCheck);
context.CodeWriter.Write("<");
context.CodeWriter.Write(node.BoundAttribute.TypeName);
context.CodeWriter.Write(node.TypeName);
context.CodeWriter.Write(">");
context.CodeWriter.Write("(");
}
@ -454,6 +457,12 @@ namespace Microsoft.AspNetCore.Blazor.Razor
_scopeStack.CloseScope(context);
}
public override void WriteComponentTypeArgument(CodeRenderingContext context, ComponentTypeArgumentExtensionNode node)
{
// We can skip type arguments during runtime codegen, they are handled in the
// type/parameter declarations.
}
public override void WriteTemplate(CodeRenderingContext context, TemplateIntermediateNode node)
{
if (context == null)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -49,6 +49,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
PropertyName = propertyNode.BoundAttribute.GetPropertyName();
Source = propertyNode.Source;
TagHelper = propertyNode.TagHelper;
TypeName = propertyNode.BoundAttribute.IsWeaklyTyped() ? null : propertyNode.BoundAttribute.TypeName;
for (var i = 0; i < propertyNode.Children.Count; i++)
{
@ -74,6 +75,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
PropertyName = attributeNode.BoundAttribute.GetPropertyName();
Source = attributeNode.Source;
TagHelper = attributeNode.TagHelper;
TypeName = attributeNode.BoundAttribute.IsWeaklyTyped() ? null : attributeNode.BoundAttribute.TypeName;
for (var i = 0; i < attributeNode.Children.Count; i++)
{
@ -98,6 +100,8 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public TagHelperDescriptor TagHelper { get; set; }
public string TypeName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public string ParameterName { get; set; } = "context";
public string TypeName => BoundAttribute?.TypeName == null ? BlazorApi.RenderFragment.FullTypeName : BoundAttribute.TypeName;
public string TypeName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{

View File

@ -1,7 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.Linq;
using System.Text;
@ -91,6 +92,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
@class.Modifiers.Clear();
@class.Modifiers.Add("public");
var documentNode = codeDocument.GetDocumentIntermediateNode();
var typeParamReferences = documentNode.FindDirectiveReferences(TypeParamDirective.Directive);
for (var i = 0; i < typeParamReferences.Count; i++)
{
var typeParamNode = (DirectiveIntermediateNode)typeParamReferences[i].Node;
if (typeParamNode.HasDiagnostics)
{
continue;
}
@class.TypeParameters.Add(new TypeParameter() { ParameterName = typeParamNode.Tokens.First().Content, });
}
method.ReturnType = "void";
method.MethodName = BlazorApi.BlazorComponent.BuildRenderTree;
method.Modifiers.Clear();

View File

@ -23,9 +23,11 @@ namespace Microsoft.AspNetCore.Blazor.Razor
public TagHelperDescriptor Component { get; set; }
public string TagName { get; set; }
public IEnumerable<ComponentTypeArgumentExtensionNode> TypeArguments => Children.OfType<ComponentTypeArgumentExtensionNode>();
public string TypeName => Component?.GetTypeName();
public string TagName { get; set; }
public string TypeName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
@ -76,6 +78,13 @@ namespace Microsoft.AspNetCore.Blazor.Razor
builder.Append("=\"...\"");
}
foreach (var typeArgument in TypeArguments)
{
builder.Append(" ");
builder.Append(typeArgument.TypeParameterName);
builder.Append("=\"...\"");
}
builder.Append(">");
builder.Append(ChildContents.Any() ? "..." : string.Empty);
builder.Append("</");

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;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Blazor.Shared;
using Microsoft.AspNetCore.Razor.Language;
@ -70,6 +69,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
Component = tagHelper,
Source = node.Source,
TagName = node.TagName,
TypeName = tagHelper.GetTypeName(),
};
for (var i = 0; i < node.Diagnostics.Count; i++)
@ -214,6 +214,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
{
BoundAttribute = attribute,
Source = source,
TypeName = attribute?.TypeName ?? BlazorApi.RenderFragment.FullTypeName,
};
// There are two cases here:
@ -332,7 +333,21 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Each 'tag helper property' belongs to a specific tag helper. We want to handle
// the cases for components, but leave others alone. This allows our other passes
// to handle those cases.
_children.Add(node.TagHelper.IsComponentTagHelper() ? (IntermediateNode)new ComponentAttributeExtensionNode(node) : node);
if (!node.TagHelper.IsComponentTagHelper())
{
_children.Add(node);
return;
}
// Another special case here - this might be a type argument. These don't represent 'real' parameters
// that get passed to the component, it needs special code generation support.
if (node.TagHelper.IsGenericTypedComponent() && node.BoundAttribute.IsTypeParameterProperty())
{
_children.Add(new ComponentTypeArgumentExtensionNode(node));
return;
}
_children.Add(new ComponentAttributeExtensionNode(node));
}
public override void VisitDefault(IntermediateNode node)

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Blazor.Shared;
@ -95,6 +96,20 @@ namespace Microsoft.AspNetCore.Blazor.Razor
// Razor ITagHelper runtime.
builder.Metadata[TagHelperMetadata.Runtime.Name] = BlazorMetadata.Component.RuntimeName;
if (type.IsGenericType)
{
builder.Metadata[BlazorMetadata.Component.GenericTypedKey] = bool.TrueString;
for (var i = 0; i < type.TypeArguments.Length; i++)
{
var typeParameter = type.TypeArguments[i] as ITypeParameterSymbol;
if (typeParameter != null)
{
CreateTypeParameterProperty(builder, typeParameter);
}
}
}
var xml = type.GetDocumentationCommentXml();
if (!string.IsNullOrEmpty(xml))
{
@ -111,33 +126,7 @@ namespace Microsoft.AspNetCore.Blazor.Razor
continue;
}
builder.BindAttribute(pb =>
{
pb.Name = property.property.Name;
pb.TypeName = property.property.Type.ToDisplayString(FullNameTypeDisplayFormat);
pb.SetPropertyName(property.property.Name);
if (property.kind == PropertyKind.Enum)
{
pb.IsEnum = true;
}
if (property.kind == PropertyKind.ChildContent)
{
pb.Metadata.Add(BlazorMetadata.Component.ChildContentKey, bool.TrueString);
}
if (property.kind == PropertyKind.Delegate)
{
pb.Metadata.Add(BlazorMetadata.Component.DelegateSignatureKey, bool.TrueString);
}
xml = property.property.GetDocumentationCommentXml();
if (!string.IsNullOrEmpty(xml))
{
pb.Documentation = xml;
}
});
CreateProperty(builder, property.property, property.kind);
}
var descriptor = builder.Build();
@ -145,6 +134,97 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return descriptor;
}
private void CreateProperty(TagHelperDescriptorBuilder builder, IPropertySymbol property, PropertyKind kind)
{
builder.BindAttribute(pb =>
{
pb.Name = property.Name;
pb.TypeName = property.Type.ToDisplayString(FullNameTypeDisplayFormat);
pb.SetPropertyName(property.Name);
if (kind == PropertyKind.Enum)
{
pb.IsEnum = true;
}
if (kind == PropertyKind.ChildContent)
{
pb.Metadata.Add(BlazorMetadata.Component.ChildContentKey, bool.TrueString);
}
if (kind == PropertyKind.Delegate)
{
pb.Metadata.Add(BlazorMetadata.Component.DelegateSignatureKey, bool.TrueString);
}
if (HasTypeParameter(property.Type))
{
pb.Metadata.Add(BlazorMetadata.Component.GenericTypedKey, bool.TrueString);
}
var xml = property.GetDocumentationCommentXml();
if (!string.IsNullOrEmpty(xml))
{
pb.Documentation = xml;
}
});
bool HasTypeParameter(ITypeSymbol type)
{
if (type is ITypeParameterSymbol)
{
return true;
}
// We need to check for cases like:
// [Parameter] List<T> MyProperty { get; set; }
// AND
// [Parameter] List<string> MyProperty { get; set; }
//
// We need to inspect the type arguments to tell the difference between a property that
// uses the containing class' type parameter(s) and a vanilla usage of generic types like
// List<> and Dictionary<,>
//
// Since we need to handle cases like RenderFragment<List<T>>, this check must be recursive.
if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
{
var typeArguments = namedType.TypeArguments;
for (var i = 0; i < typeArguments.Length; i++)
{
if (HasTypeParameter(typeArguments[i]))
{
return true;
}
}
// Another case to handle - if the type being inspected is a nested type
// inside a generic containing class. The common usage for this would be a case
// where a generic templated component defines a 'context' nested class.
if (namedType.ContainingType != null && HasTypeParameter(namedType.ContainingType))
{
return true;
}
}
return false;
}
}
private void CreateTypeParameterProperty(TagHelperDescriptorBuilder builder, ITypeSymbol typeParameter)
{
builder.BindAttribute(pb =>
{
pb.DisplayName = typeParameter.Name;
pb.Name = typeParameter.Name;
pb.TypeName = typeof(Type).FullName;
pb.SetPropertyName(typeParameter.Name);
pb.Metadata[BlazorMetadata.Component.TypeParameterKey] = bool.TrueString;
pb.Documentation = string.Format(Resources.ComponentTypeParameter_Documentation, typeParameter.Name, builder.Name);
});
}
private TagHelperDescriptor CreateChildContentDescriptor(BlazorSymbols symbols, TagHelperDescriptor component, BoundAttributeDescriptor attribute)
{
var typeName = component.GetTypeName() + "." + attribute.Name;
@ -396,7 +476,6 @@ namespace Microsoft.AspNetCore.Blazor.Razor
return
symbol.DeclaredAccessibility == Accessibility.Public &&
!symbol.IsAbstract &&
!symbol.IsGenericType &&
symbol.AllInterfaces.Contains(_symbols.IComponent);
}
}

View File

@ -0,0 +1,69 @@
// 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.Blazor.Razor
{
internal class ComponentTypeArgumentExtensionNode : ExtensionIntermediateNode
{
public ComponentTypeArgumentExtensionNode(TagHelperPropertyIntermediateNode propertyNode)
{
if (propertyNode == null)
{
throw new ArgumentNullException(nameof(propertyNode));
}
BoundAttribute = propertyNode.BoundAttribute;
Source = propertyNode.Source;
TagHelper = propertyNode.TagHelper;
for (var i = 0; i < propertyNode.Children.Count; i++)
{
Children.Add(propertyNode.Children[i]);
}
for (var i = 0; i < propertyNode.Diagnostics.Count; i++)
{
Diagnostics.Add(propertyNode.Diagnostics[i]);
}
}
public override IntermediateNodeCollection Children { get; } = new IntermediateNodeCollection();
public BoundAttributeDescriptor BoundAttribute { get; set; }
public string TypeParameterName => BoundAttribute.Name;
public TagHelperDescriptor TagHelper { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
{
throw new ArgumentNullException(nameof(visitor));
}
AcceptExtensionNode<ComponentTypeArgumentExtensionNode>(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 writer = (BlazorNodeWriter)context.NodeWriter;
writer.WriteComponentTypeArgument(context, this);
}
}
}

View File

@ -0,0 +1,118 @@
// 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.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.AspNetCore.Blazor.Razor
{
// This pass:
// 1. Adds diagnostics for missing generic type arguments
// 2. Rewrites the type name of the component to substitute generic type arguments
// 3. Rewrites the type names of parameters/child content to substitute generic type arguments
internal class GenericComponentPass : IntermediateNodePassBase, IRazorOptimizationPass
{
// Runs after components/eventhandlers/ref/bind/templates. We want to validate every component
// and it's usage of ChildContent.
public override int Order => 160;
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var visitor = new Visitor();
visitor.Visit(documentNode);
}
private class Visitor : IntermediateNodeWalker, IExtensionIntermediateNodeVisitor<ComponentExtensionNode>
{
public void VisitExtension(ComponentExtensionNode node)
{
if (node.Component.IsGenericTypedComponent())
{
// Not generic, ignore.
Process(node);
}
base.VisitDefault(node);
}
private void Process(ComponentExtensionNode node)
{
// First collect all of the information we have about each type parameter
var bindings = new Dictionary<string, GenericTypeNameRewriter.Binding>();
foreach (var attribute in node.Component.GetTypeParameters())
{
bindings.Add(attribute.Name, new GenericTypeNameRewriter.Binding() { Attribute = attribute, });
}
foreach (var typeArgumentNode in node.TypeArguments)
{
var binding = bindings[typeArgumentNode.TypeParameterName];
binding.Node = typeArgumentNode;
binding.Content = GetContent(typeArgumentNode);
}
// Right now we don't have type inference, so all type arguments are required.
var missing = new List<BoundAttributeDescriptor>();
foreach (var binding in bindings)
{
if (binding.Value.Node == null || string.IsNullOrWhiteSpace(binding.Value.Content))
{
missing.Add(binding.Value.Attribute);
}
}
if (missing.Count > 0)
{
// We add our own error for this because its likely the user will see other errors due
// to incorrect codegen without the types. Our errors message will pretty clearly indicate
// what to do, whereas the other errors might be confusing.
node.Diagnostics.Add(BlazorDiagnosticFactory.Create_GenericComponentMissingTypeArgument(node.Source, node, missing));
}
var rewriter = new GenericTypeNameRewriter(bindings);
// Rewrite the component type name
node.TypeName = RewriteTypeName(rewriter, node.TypeName);
foreach (var attribute in node.Attributes)
{
if (attribute.BoundAttribute?.IsGenericTypedProperty() ?? false && attribute.TypeName != null)
{
// If we know the type name, then replace any generic type parameter inside it with
// the known types.
attribute.TypeName = RewriteTypeName(rewriter, attribute.TypeName);
}
}
foreach (var childContent in node.ChildContents)
{
if (childContent.BoundAttribute?.IsGenericTypedProperty() ?? false && childContent.TypeName != null)
{
// If we know the type name, then replace any generic type parameter inside it with
// the known types.
childContent.TypeName = RewriteTypeName(rewriter, childContent.TypeName);
}
}
}
private string RewriteTypeName(GenericTypeNameRewriter rewriter, string typeName)
{
var parsed = SyntaxFactory.ParseTypeName(typeName);
var rewritten = (TypeSyntax)rewriter.Visit(parsed);
return rewritten.ToFullString();
}
private string GetContent(ComponentTypeArgumentExtensionNode node)
{
return string.Join(string.Empty, node.FindDescendantNodes<IntermediateToken>().Where(t => t.IsCSharp).Select(t => t.Content));
}
}
}
}

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.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class GenericTypeNameRewriter : CSharpSyntaxRewriter
{
private readonly Dictionary<string, Binding> _bindings;
public GenericTypeNameRewriter(Dictionary<string, Binding> bindings)
{
_bindings = bindings;
}
public override SyntaxNode Visit(SyntaxNode node)
{
// We can handle a single IdentifierNameSyntax at the top level (like 'TItem)
// OR a GenericNameSyntax recursively (like `List<T>`)
if (node is IdentifierNameSyntax identifier && !(identifier.Parent is QualifiedNameSyntax))
{
if (_bindings.TryGetValue(identifier.Identifier.Text, out var binding))
{
// If we don't have a valid replacement, use object. This will make the code at least reasonable
// compared to leaving the type parameter in place.
//
// We add our own diagnostics for missing/invalid type parameters anyway.
var replacement = binding?.Content == null ? typeof(object).FullName : binding.Content;
return identifier.Update(SyntaxFactory.Identifier(replacement));
}
}
return base.Visit(node);
}
public override SyntaxNode VisitGenericName(GenericNameSyntax node)
{
var args = node.TypeArgumentList.Arguments;
for (var i = 0; i < args.Count; i++)
{
var typeArgument = args[i];
args = args.Replace(typeArgument, (TypeSyntax)Visit(typeArgument));
}
return node.WithTypeArgumentList(node.TypeArgumentList.WithArguments(args));
}
public class Binding
{
public BoundAttributeDescriptor Attribute { get; set; }
public string Content { get; set; }
public ComponentTypeArgumentExtensionNode Node { get; set; }
}
}
}

View File

@ -114,6 +114,15 @@ namespace Microsoft.AspNetCore.Blazor.Razor {
}
}
/// <summary>
/// Looks up a localized string similar to Specifies the type of the type parameter {0} for the {1} component..
/// </summary>
internal static string ComponentTypeParameter_Documentation {
get {
return ResourceManager.GetString("ComponentTypeParameter_Documentation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sets the &apos;{0}&apos; attribute to the provided string or delegate value. A delegate value should be of type &apos;{1}&apos;..
/// </summary>
@ -221,5 +230,32 @@ namespace Microsoft.AspNetCore.Blazor.Razor {
return ResourceManager.GetString("RefTagHelper_Documentation", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Declares a generic type parameter for the generated component class..
/// </summary>
internal static string TypeParamDirective_Description {
get {
return ResourceManager.GetString("TypeParamDirective_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The name of the type parameter..
/// </summary>
internal static string TypeParamDirective_Token_Description {
get {
return ResourceManager.GetString("TypeParamDirective_Token_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to type parameter.
/// </summary>
internal static string TypeParamDirective_Token_Name {
get {
return ResourceManager.GetString("TypeParamDirective_Token_Name", resourceCulture);
}
}
}
}

View File

@ -135,6 +135,9 @@
<data name="ChildContentParameterName_Documentation" xml:space="preserve">
<value>Specifies the parameter name for the '{0}' lambda expression.</value>
</data>
<data name="ComponentTypeParameter_Documentation" xml:space="preserve">
<value>Specifies the type of the type parameter {0} for the {1} component.</value>
</data>
<data name="EventHandlerTagHelper_Documentation" xml:space="preserve">
<value>Sets the '{0}' attribute to the provided string or delegate value. A delegate value should be of type '{1}'.</value>
</data>
@ -171,4 +174,13 @@
<data name="RefTagHelper_Documentation" xml:space="preserve">
<value>Populates the specified field or property with a reference to the element or component.</value>
</data>
<data name="TypeParamDirective_Description" xml:space="preserve">
<value>Declares a generic type parameter for the generated component class.</value>
</data>
<data name="TypeParamDirective_Token_Description" xml:space="preserve">
<value>The name of the type parameter.</value>
</data>
<data name="TypeParamDirective_Token_Name" xml:space="preserve">
<value>type parameter</value>
</data>
</root>

View File

@ -22,6 +22,30 @@ namespace Microsoft.AspNetCore.Blazor.Razor
string.Equals(value, bool.TrueString);
}
public static bool IsGenericTypedProperty(this BoundAttributeDescriptor attribute)
{
if (attribute == null)
{
throw new ArgumentNullException(nameof(attribute));
}
return
attribute.Metadata.TryGetValue(BlazorMetadata.Component.GenericTypedKey, out var value) &&
string.Equals(value, bool.TrueString);
}
public static bool IsTypeParameterProperty(this BoundAttributeDescriptor attribute)
{
if (attribute == null)
{
throw new ArgumentNullException(nameof(attribute));
}
return
attribute.Metadata.TryGetValue(BlazorMetadata.Component.TypeParameterKey, out var value) &&
string.Equals(value, bool.TrueString);
}
public static bool IsWeaklyTyped(this BoundAttributeDescriptor attribute)
{
if (attribute == null)

View File

@ -35,6 +35,19 @@ namespace Microsoft.AspNetCore.Blazor.Razor
string.Equals(bool.TrueString, fallback);
}
public static bool IsGenericTypedComponent(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
return
IsComponentTagHelper(tagHelper) &&
tagHelper.Metadata.TryGetValue(BlazorMetadata.Component.GenericTypedKey, out var value) &&
string.Equals(bool.TrueString, value);
}
public static bool IsInputElementBindTagHelper(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
@ -160,5 +173,27 @@ namespace Microsoft.AspNetCore.Blazor.Razor
}
}
}
/// <summary>
/// Gets the set of component attributes that represent generic type parameters of the component type.
/// </summary>
/// <param name="tagHelper">The <see cref="TagHelperDescriptor"/>.</param>
/// <returns>The type parameter attributes</returns>
public static IEnumerable<BoundAttributeDescriptor> GetTypeParameters(this TagHelperDescriptor tagHelper)
{
if (tagHelper == null)
{
throw new ArgumentNullException(nameof(tagHelper));
}
for (var i = 0; i < tagHelper.BoundAttributes.Count; i++)
{
var attribute = tagHelper.BoundAttributes[i];
if (attribute.IsTypeParameterProperty())
{
yield return attribute;
}
}
}
}
}

View File

@ -0,0 +1,32 @@
// 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;
namespace Microsoft.AspNetCore.Blazor.Razor
{
internal class TypeParamDirective
{
public static readonly DirectiveDescriptor Directive = DirectiveDescriptor.CreateDirective(
"typeparam",
DirectiveKind.SingleLine,
builder =>
{
builder.AddMemberToken(Resources.TypeParamDirective_Token_Name, Resources.TypeParamDirective_Token_Description);
builder.Usage = DirectiveUsage.FileScopedMultipleOccurring;
builder.Description = Resources.TypeParamDirective_Description;
});
public static RazorProjectEngineBuilder Register(RazorProjectEngineBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.AddDirective(Directive);
return builder;
}
}
}

View File

@ -11,8 +11,8 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
internal override bool UseTwoPhaseCompilation => true;
public CodeGenerationTestBase()
: base(generateBaselines: false)
{
GenerateBaselines = true;
}
#region Basics
@ -81,6 +81,36 @@ namespace Test
CompileToAssembly(generated);
}
[Fact]
public void ComponentWithTypeParameters()
{
// Arrange
// Act
var generated = CompileToCSharp(@"
@using Microsoft.AspNetCore.Blazor;
@typeparam TItem1
@typeparam TItem2
<h1>Item1</h1>
@foreach (var item2 in Items2)
{
<p>
@ChildContent(item2);
</p>
}
@functions {
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
}");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void ChildComponent_WithExplicitStringParameter()
{
@ -1199,6 +1229,146 @@ namespace Test
#endregion
#region Generics
[Fact]
public void ChildComponent_Generic()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse(@"
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<TItem> : BlazorComponent
{
[Parameter] TItem Item { get; set; }
}
}
"));
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<MyComponent TItem=string Item=""@(""hi"")""/>");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void ChildComponent_GenericBind()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse(@"
using System;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<TItem> : BlazorComponent
{
[Parameter]
TItem Value { get; set; }
[Parameter]
Action<TItem> ValueChanged { get; set; }
}
}
"));
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<MyComponent TItem=string bind-Item=Value/>
@functions {
string Value;
}");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void ChildComponent_GenericChildContent()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse(@"
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<TItem> : BlazorComponent
{
[Parameter] TItem Item { get; set; }
[Parameter] RenderFragment<TItem> ChildContent { get; set; }
}
}
"));
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<MyComponent TItem=string Item=""@(""hi"")"">
<div>@context.ToLower()</div>
</MyComponent>");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void ChildComponent_MultipleGenerics()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse(@"
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<TItem1, TItem2> : BlazorComponent
{
[Parameter] TItem1 Item { get; set; }
[Parameter] RenderFragment<TItem1> ChildContent { get; set; }
[Parameter] RenderFragment<Context> AnotherChildContent { get; set; }
public class Context
{
public TItem2 Item { get; set; }
}
}
}
"));
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<MyComponent TItem1=string TItem2=int Item=""@(""hi"")"">
<ChildContent><div>@context.ToLower()</div></ChildContent>
<AnotherChildContent Context=""item"">
@System.Math.Max(0, item.Item);
</AnotherChildContent>
</MyComponent>");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
#endregion
#region Ref
[Fact]
@ -1335,7 +1505,7 @@ namespace Test
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void RazorTemplate_NonGeneric_InImplicitExpression()
{

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -85,5 +85,43 @@ namespace Test.AnotherNamespace
var bindings = result.CodeDocument.GetTagHelperContext();
Assert.Single(bindings.TagHelpers, t => t.Name == "Microsoft.AspNetCore.Blazor.Routing.NavLink");
}
[Fact]
public void ComponentDiscovery_CanFindComponent_WithTypeParameter()
{
// Arrange
// Act
var result = CompileToCSharp("UniqueName.cshtml", @"
@addTagHelper *, TestAssembly
@typeparam TItem
@functions {
[Parameter] TItem Item { get; set; }
}");
// Assert
var bindings = result.CodeDocument.GetTagHelperContext();
Assert.Single(bindings.TagHelpers, t => t.Name == "Test.UniqueName<TItem>");
}
[Fact]
public void ComponentDiscovery_CanFindComponent_WithMultipleTypeParameters()
{
// Arrange
// Act
var result = CompileToCSharp("UniqueName.cshtml", @"
@addTagHelper *, TestAssembly
@typeparam TItem1
@typeparam TItem2
@typeparam TItem3
@functions {
[Parameter] TItem1 Item { get; set; }
}");
// Assert
var bindings = result.CodeDocument.GetTagHelperContext();
Assert.Single(bindings.TagHelpers, t => t.Name == "Test.UniqueName<TItem1, TItem2, TItem3>");
}
}
}

View File

@ -0,0 +1,190 @@
// 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.Blazor.Razor;
using Microsoft.AspNetCore.Blazor.RenderTree;
using Microsoft.AspNetCore.Blazor.Test.Helpers;
using Microsoft.CodeAnalysis.CSharp;
using System.Collections.Generic;
using System.Linq;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Build.Test
{
public class GenericComponentRazorIntegrationTest : RazorIntegrationTestBase
{
private readonly CSharpSyntaxTree GenericContextComponent = Parse(@"
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
using Microsoft.AspNetCore.Blazor.RenderTree;
namespace Test
{
public class GenericContext<TItem> : BlazorComponent
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
var items = (IReadOnlyList<TItem>)Items ?? Array.Empty<TItem>();
for (var i = 0; i < items.Count; i++)
{
builder.AddContent(i, ChildContent, new Context() { Index = i, Item = items[i], });
}
}
[Parameter]
List<TItem> Items { get; set; }
[Parameter]
RenderFragment<Context> ChildContent { get; set; }
public class Context
{
public int Index { get; set; }
public TItem Item { get; set; }
}
}
}
");
private readonly CSharpSyntaxTree MultipleGenericParameterComponent = Parse(@"
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
using Microsoft.AspNetCore.Blazor.RenderTree;
namespace Test
{
public class MultipleGenericParameter<TItem1, TItem2, TItem3> : BlazorComponent
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.AddContent(0, Item1);
builder.AddContent(1, Item2);
builder.AddContent(2, Item3);
}
[Parameter]
TItem1 Item1 { get; set; }
[Parameter]
TItem2 Item2 { get; set; }
[Parameter]
TItem3 Item3 { get; set; }
}
}
");
internal override bool UseTwoPhaseCompilation => true;
[Fact]
public void Render_GenericComponent_WithChildContent()
{
// Arrange
AdditionalSyntaxTrees.Add(GenericContextComponent);
var component = CompileToComponent(@"
@addTagHelper *, TestAssembly
<GenericContext TItem=int Items=""@(new List<int>() { 1, 2, })"">
<div>@(context.Item * context.Index)</div>
</GenericContext>");
// Act
var frames = GetRenderTree(component);
// Assert
var genericComponentType = component.GetType().Assembly.DefinedTypes
.Where(t => t.Name == "GenericContext`1")
.Single()
.MakeGenericType(typeof(int));
Assert.Collection(
frames,
frame => AssertFrame.Component(frame, genericComponentType.FullName, 3, 0),
frame => AssertFrame.Attribute(frame, "Items", typeof(List<int>), 1),
frame => AssertFrame.Attribute(frame, RenderTreeBuilder.ChildContent, 2),
frame => AssertFrame.Whitespace(frame, 3),
frame => AssertFrame.Element(frame, "div", 2, 4),
frame => AssertFrame.Text(frame, "0", 5),
frame => AssertFrame.Whitespace(frame, 6),
frame => AssertFrame.Whitespace(frame, 3),
frame => AssertFrame.Element(frame, "div", 2, 4),
frame => AssertFrame.Text(frame, "2", 5),
frame => AssertFrame.Whitespace(frame, 6));
}
[Fact]
public void Render_GenericComponent_MultipleParameters_WithChildContent()
{
// Arrange
AdditionalSyntaxTrees.Add(MultipleGenericParameterComponent);
var component = CompileToComponent(@"
@addTagHelper *, TestAssembly
<MultipleGenericParameter
TItem1=""int""
TItem2=""string""
TItem3=long
Item1=3
Item2=""@(""FOO"")""
Item3=39L/>");
// Act
var frames = GetRenderTree(component);
// Assert
var genericComponentType = component.GetType().Assembly.DefinedTypes
.Where(t => t.Name == "MultipleGenericParameter`3")
.Single()
.MakeGenericType(typeof(int), typeof(string), typeof(long));
Assert.Collection(
frames,
frame => AssertFrame.Component(frame, genericComponentType.FullName, 4, 0),
frame => AssertFrame.Attribute(frame, "Item1", 3, 1),
frame => AssertFrame.Attribute(frame, "Item2", "FOO", 2),
frame => AssertFrame.Attribute(frame, "Item3", 39L, 3),
frame => AssertFrame.Text(frame, "3", 0),
frame => AssertFrame.Text(frame, "FOO", 1),
frame => AssertFrame.Text(frame, "39", 2));
}
[Fact]
public void GenericComponent_WithoutAnyTypeParameters_TriggersDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(GenericContextComponent);
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<GenericContext />");
// Assert
var diagnostic = Assert.Single(generated.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.GenericComponentMissingTypeArgument.Id, diagnostic.Id);
Assert.Equal(
"The component 'GenericContext' is missing required type arguments. Specify the missing types using the attributes: 'TItem'.",
diagnostic.GetMessage());
}
[Fact]
public void GenericComponent_WithMissingTypeParameters_TriggersDiagnostic()
{
// Arrange
AdditionalSyntaxTrees.Add(MultipleGenericParameterComponent);
// Act
var generated = CompileToCSharp(@"
@addTagHelper *, TestAssembly
<MultipleGenericParameter TItem1=int />");
// Assert
var diagnostic = Assert.Single(generated.Diagnostics);
Assert.Same(BlazorDiagnosticFactory.GenericComponentMissingTypeArgument.Id, diagnostic.Id);
Assert.Equal(
"The component 'MultipleGenericParameter' is missing required type arguments. " +
"Specify the missing types using the attributes: 'TItem2', 'TItem3'.",
diagnostic.GetMessage());
}
}
}

View File

@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
IExtensionIntermediateNodeVisitor<ComponentExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentAttributeExtensionNode>,
IExtensionIntermediateNodeVisitor<ComponentChildContentIntermediateNode>,
IExtensionIntermediateNodeVisitor<ComponentTypeArgumentExtensionNode>,
IExtensionIntermediateNodeVisitor<RouteAttributeExtensionNode>,
IExtensionIntermediateNodeVisitor<RefExtensionNode>
{
@ -291,6 +292,11 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
WriteContentNode(node, node.AttributeName);
}
void IExtensionIntermediateNodeVisitor<ComponentTypeArgumentExtensionNode>.VisitExtension(ComponentTypeArgumentExtensionNode node)
{
WriteContentNode(node, node.TypeParameterName);
}
void IExtensionIntermediateNodeVisitor<RouteAttributeExtensionNode>.VisitExtension(RouteAttributeExtensionNode node)
{
WriteContentNode(node, node.Template);

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -17,9 +17,14 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
{
private static readonly AsyncLocal<string> _directoryPath = new AsyncLocal<string>();
protected RazorBaselineIntegrationTestBase()
protected RazorBaselineIntegrationTestBase(bool? generateBaselines = null)
{
TestProjectRoot = TestProject.GetProjectDirectory(GetType());
if (generateBaselines.HasValue)
{
GenerateBaselines = generateBaselines.Value;
}
}
// Used by the test framework to set the directory for test files.
@ -30,9 +35,9 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
}
#if GENERATE_BASELINES
protected bool GenerateBaselines { get; set; } = true;
protected bool GenerateBaselines { get; } = true;
#else
protected bool GenerateBaselines { get; set; } = false;
protected bool GenerateBaselines { get; } = false;
#endif
protected string TestProjectRoot { get; }
@ -47,6 +52,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
// Force consistent paths since they are going to be recorded in files.
internal override string WorkingDirectory => ArbitraryWindowsPath;
[Fact]
public void GenerateBaselinesMustBeFalse()
{
Assert.False(GenerateBaselines, "GenerateBaselines should be set back to false before you check in!");
}
protected void AssertDocumentNodeMatchesBaseline(RazorCodeDocument codeDocument)
{
var document = codeDocument.GetDocumentIntermediateNode();

View File

@ -0,0 +1,50 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object __typeHelper = "*, TestAssembly";
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
__o = typeof(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
string
#line default
#line hidden
);
__o = Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
"hi"
#line default
#line hidden
);
builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
}
));
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,30 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [33] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
DesignTimeDirective -
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
DirectiveToken - (14:0,14 [9] ) - "*, Test"
DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentExtensionNode - (31:1,0 [42] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (63:1,32 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (64:1,33 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,15 @@
Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml)
|*, TestAssembly|
Generated Location: (559:16,38 [15] )
|*, TestAssembly|
Source Location: (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|string|
Generated Location: (1083:30,19 [6] )
|string|
Source Location: (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml)
|"hi"|
Generated Location: (1315:37,34 [4] )
|"hi"|

View File

@ -0,0 +1,57 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object __typeHelper = "*, TestAssembly";
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
__o = typeof(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
string
#line default
#line hidden
);
__o = Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
Value
#line default
#line hidden
);
__o = Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Value = __value, Value);
builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
}
));
}
#pragma warning restore 1998
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
string Value;
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,39 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [33] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
DesignTimeDirective -
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
DirectiveToken - (14:0,14 [9] ) - "*, Test"
DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentExtensionNode - (31:1,0 [43] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Item -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Value
IntermediateToken - - CSharp - )
ComponentAttributeExtensionNode - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - ItemChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Value = __value, Value)
HtmlContent - (74:1,43 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (74:1,43 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n string Value;\n

View File

@ -0,0 +1,24 @@
Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml)
|*, TestAssembly|
Generated Location: (559:16,38 [15] )
|*, TestAssembly|
Source Location: (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|string|
Generated Location: (1083:30,19 [6] )
|string|
Source Location: (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml)
|Value|
Generated Location: (1305:37,36 [5] )
|Value|
Source Location: (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml)
|
string Value;
|
Generated Location: (1740:49,12 [21] )
|
string Value;
|

View File

@ -0,0 +1,55 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object __typeHelper = "*, TestAssembly";
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
__o = typeof(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
string
#line default
#line hidden
);
__o = Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
"hi"
#line default
#line hidden
);
builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<string>)((context) => (builder2) => {
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = context.ToLower();
#line default
#line hidden
}
));
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,38 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [33] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
DesignTimeDirective -
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
DirectiveToken - (14:0,14 [9] ) - "*, Test"
DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentExtensionNode - (31:1,0 [90] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentChildContent - - ChildContent
HtmlContent - (72:1,41 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (72:1,41 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlElement - (76:2,2 [29] x:\dir\subdir\Test\TestComponent.cshtml) - div
CSharpExpression - (82:2,8 [17] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (82:2,8 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - context.ToLower()
HtmlContent - (105:2,31 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (105:2,31 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (63:1,32 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (64:1,33 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,20 @@
Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml)
|*, TestAssembly|
Generated Location: (559:16,38 [15] )
|*, TestAssembly|
Source Location: (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|string|
Generated Location: (1083:30,19 [6] )
|string|
Source Location: (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml)
|"hi"|
Generated Location: (1315:37,34 [4] )
|"hi"|
Source Location: (82:2,8 [17] x:\dir\subdir\Test\TestComponent.cshtml)
|context.ToLower()|
Generated Location: (1563:44,8 [17] )
|context.ToLower()|

View File

@ -0,0 +1,70 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object __typeHelper = "*, TestAssembly";
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
__o = typeof(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
string
#line default
#line hidden
);
__o = typeof(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
int
#line default
#line hidden
);
__o = Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>(
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
"hi"
#line default
#line hidden
);
builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<string>)((context) => (builder2) => {
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = context.ToLower();
#line default
#line hidden
}
));
builder.AddAttribute(-1, "AnotherChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<Test.MyComponent<string, int>.Context>)((item) => (builder2) => {
#line 5 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = System.Math.Max(0, item.Item);
#line default
#line hidden
}
));
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,43 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [33] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
DesignTimeDirective -
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
DirectiveToken - (14:0,14 [9] ) - "*, Test"
DirectiveToken - (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml) - *, TestAssembly
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (29:0,29 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentExtensionNode - (31:1,0 [228] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string, int>
ComponentChildContent - (88:2,2 [58] x:\dir\subdir\Test\TestComponent.cshtml) - ChildContent
HtmlElement - (102:2,16 [29] x:\dir\subdir\Test\TestComponent.cshtml) - div
CSharpExpression - (108:2,22 [17] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (108:2,22 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - context.ToLower()
ComponentChildContent - (148:3,0 [95] x:\dir\subdir\Test\TestComponent.cshtml) - AnotherChildContent
HtmlContent - (184:3,36 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (184:3,36 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpExpression - (189:4,3 [29] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (189:4,3 [29] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - System.Math.Max(0, item.Item)
HtmlContent - (218:4,32 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (218:4,32 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - ;\n
ComponentTypeArgumentExtensionNode - (51:1,20 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem1
IntermediateToken - (51:1,20 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentTypeArgumentExtensionNode - (65:1,34 [3] x:\dir\subdir\Test\TestComponent.cshtml) - TItem2
IntermediateToken - (65:1,34 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - int
ComponentAttributeExtensionNode - (75:1,44 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (76:1,45 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (77:1,46 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,30 @@
Source Location: (14:0,14 [15] x:\dir\subdir\Test\TestComponent.cshtml)
|*, TestAssembly|
Generated Location: (559:16,38 [15] )
|*, TestAssembly|
Source Location: (51:1,20 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|string|
Generated Location: (1084:30,20 [6] )
|string|
Source Location: (65:1,34 [3] x:\dir\subdir\Test\TestComponent.cshtml)
|int|
Generated Location: (1251:37,34 [3] )
|int|
Source Location: (77:1,46 [4] x:\dir\subdir\Test\TestComponent.cshtml)
|"hi"|
Generated Location: (1492:44,46 [4] )
|"hi"|
Source Location: (108:2,22 [17] x:\dir\subdir\Test\TestComponent.cshtml)
|context.ToLower()|
Generated Location: (1754:51,22 [17] )
|context.ToLower()|
Source Location: (189:4,3 [29] x:\dir\subdir\Test\TestComponent.cshtml)
|System.Math.Max(0, item.Item)|
Generated Location: (2065:59,6 [29] )
|System.Math.Max(0, item.Item)|

View File

@ -0,0 +1,67 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
using Microsoft.AspNetCore.Blazor;
#line default
#line hidden
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent<TItem1, TItem2> : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
((System.Action)(() => {
global::System.Object TItem1 = null;
}
))();
((System.Action)(() => {
global::System.Object TItem2 = null;
}
))();
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
#line 6 "x:\dir\subdir\Test\TestComponent.cshtml"
foreach (var item2 in Items2)
{
#line default
#line hidden
#line 9 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = ChildContent(item2);
#line default
#line hidden
#line 10 "x:\dir\subdir\Test\TestComponent.cshtml"
}
#line default
#line hidden
}
#pragma warning restore 1998
#line 12 "x:\dir\subdir\Test\TestComponent.cshtml"
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,47 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [34] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [44] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
DesignTimeDirective -
DirectiveToken - (14:0,14 [32] ) - "*, Microsoft.AspNetCore.Blazor"
DirectiveToken - (14:0,14 [9] ) - "*, Test"
DirectiveToken - (48:1,11 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem1
DirectiveToken - (67:2,11 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem2
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlContent - (35:0,35 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (35:0,35 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlContent - (75:3,0 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (75:3,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlElement - (77:4,0 [14] x:\dir\subdir\Test\TestComponent.cshtml) - h1
HtmlContent - (81:4,4 [5] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (81:4,4 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Item1
HtmlContent - (91:4,14 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (91:4,14 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (94:5,1 [38] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (94:5,1 [38] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - foreach (var item2 in Items2)\n{\n
HtmlElement - (132:7,4 [40] x:\dir\subdir\Test\TestComponent.cshtml) - p
HtmlContent - (135:7,7 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (135:7,7 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpExpression - (142:8,5 [19] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (142:8,5 [19] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ChildContent(item2)
HtmlContent - (161:8,24 [7] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (161:8,24 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Html - ;\n
CSharpCode - (172:9,8 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (172:9,8 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n}
HtmlContent - (175:10,1 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (175:10,1 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n [Parameter] TItem1 Item1 { get; set; }\n [Parameter] List<TItem2> Items2 { get; set; }\n [Parameter] RenderFragment<TItem2> ChildContent { get; set; }\n

View File

@ -0,0 +1,49 @@
Source Location: (1:0,1 [34] x:\dir\subdir\Test\TestComponent.cshtml)
|using Microsoft.AspNetCore.Blazor;|
Generated Location: (257:10,0 [34] )
|using Microsoft.AspNetCore.Blazor;|
Source Location: (48:1,11 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|TItem1|
Generated Location: (637:20,22 [6] )
|TItem1|
Source Location: (67:2,11 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|TItem2|
Generated Location: (735:24,22 [6] )
|TItem2|
Source Location: (94:5,1 [38] x:\dir\subdir\Test\TestComponent.cshtml)
|foreach (var item2 in Items2)
{
|
Generated Location: (1211:37,1 [38] )
|foreach (var item2 in Items2)
{
|
Source Location: (142:8,5 [19] x:\dir\subdir\Test\TestComponent.cshtml)
|ChildContent(item2)|
Generated Location: (1339:44,6 [19] )
|ChildContent(item2)|
Source Location: (172:9,8 [3] x:\dir\subdir\Test\TestComponent.cshtml)
|
}|
Generated Location: (1452:49,8 [3] )
|
}|
Source Location: (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml)
|
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
|
Generated Location: (1601:57,12 [164] )
|
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
|

View File

@ -0,0 +1,25 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenComponent<Test.MyComponent<string>>(0);
builder.AddAttribute(1, "Item", Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>("hi"));
builder.CloseComponent();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,18 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [35] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
ComponentExtensionNode - (31:1,0 [42] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (63:1,32 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (64:1,33 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,32 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenComponent<Test.MyComponent<string>>(0);
builder.AddAttribute(1, "Item", Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(Value));
builder.AddAttribute(2, "ItemChanged", Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Value = __value, Value));
builder.CloseComponent();
}
#pragma warning restore 1998
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
string Value;
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,25 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [35] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
ComponentExtensionNode - (31:1,0 [43] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Item -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.GetValue(
IntermediateToken - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Value
IntermediateToken - - CSharp - )
ComponentAttributeExtensionNode - (67:1,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - ItemChanged -
CSharpExpression -
IntermediateToken - - CSharp - Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler(__value => Value = __value, Value)
CSharpCode - (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n string Value;\n

View File

@ -0,0 +1,9 @@
Source Location: (88:2,12 [21] x:\dir\subdir\Test\TestComponent.cshtml)
|
string Value;
|
Generated Location: (1087:24,12 [21] )
|
string Value;
|

View File

@ -0,0 +1,33 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenComponent<Test.MyComponent<string>>(0);
builder.AddAttribute(1, "Item", Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>("hi"));
builder.AddAttribute(2, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<string>)((context) => (builder2) => {
builder2.AddContent(3, "\n ");
builder2.OpenElement(4, "div");
builder2.AddContent(5, context.ToLower());
builder2.CloseElement();
builder2.AddContent(6, "\n");
}
));
builder.CloseComponent();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,26 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [35] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
ComponentExtensionNode - (31:1,0 [90] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string>
ComponentChildContent - - ChildContent
HtmlContent - (72:1,41 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (72:1,41 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
HtmlElement - (76:2,2 [29] x:\dir\subdir\Test\TestComponent.cshtml) - div
CSharpExpression - (82:2,8 [17] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (82:2,8 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - context.ToLower()
HtmlContent - (105:2,31 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (105:2,31 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
ComponentTypeArgumentExtensionNode - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
IntermediateToken - (50:1,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentAttributeExtensionNode - (63:1,32 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (64:1,33 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (65:1,34 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,37 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenComponent<Test.MyComponent<string, int>>(0);
builder.AddAttribute(1, "Item", Microsoft.AspNetCore.Blazor.Components.RuntimeHelpers.TypeCheck<string>("hi"));
builder.AddAttribute(2, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<string>)((context) => (builder2) => {
builder2.OpenElement(3, "div");
builder2.AddContent(4, context.ToLower());
builder2.CloseElement();
}
));
builder.AddAttribute(5, "AnotherChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment<Test.MyComponent<string, int>.Context>)((item) => (builder2) => {
builder2.AddContent(6, "\n ");
builder2.AddContent(7, System.Math.Max(0, item.Item));
builder2.AddContent(8, ";\n");
}
));
builder.CloseComponent();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,31 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [35] ) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
ComponentExtensionNode - (31:1,0 [228] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent - Test.MyComponent<string, int>
ComponentChildContent - (88:2,2 [58] x:\dir\subdir\Test\TestComponent.cshtml) - ChildContent
HtmlElement - (102:2,16 [29] x:\dir\subdir\Test\TestComponent.cshtml) - div
CSharpExpression - (108:2,22 [17] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (108:2,22 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - context.ToLower()
ComponentChildContent - (148:3,0 [95] x:\dir\subdir\Test\TestComponent.cshtml) - AnotherChildContent
HtmlContent - (184:3,36 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (184:3,36 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpExpression - (189:4,3 [29] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (189:4,3 [29] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - System.Math.Max(0, item.Item)
HtmlContent - (218:4,32 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (218:4,32 [3] x:\dir\subdir\Test\TestComponent.cshtml) - Html - ;\n
ComponentTypeArgumentExtensionNode - (51:1,20 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TItem1
IntermediateToken - (51:1,20 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
ComponentTypeArgumentExtensionNode - (65:1,34 [3] x:\dir\subdir\Test\TestComponent.cshtml) - TItem2
IntermediateToken - (65:1,34 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - int
ComponentAttributeExtensionNode - (75:1,44 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item
CSharpExpression - (76:1,45 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (77:1,46 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "hi"

View File

@ -0,0 +1,49 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
public class TestComponent<TItem1, TItem2> : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.AddMarkupContent(0, "<h1>Item1</h1>\n");
#line 6 "x:\dir\subdir\Test\TestComponent.cshtml"
foreach (var item2 in Items2)
{
#line default
#line hidden
builder.AddContent(1, " ");
builder.OpenElement(2, "p");
builder.AddContent(3, "\n ");
builder.AddContent(4, ChildContent(item2));
builder.AddContent(5, ";\n ");
builder.CloseElement();
builder.AddContent(6, "\n");
#line 11 "x:\dir\subdir\Test\TestComponent.cshtml"
}
#line default
#line hidden
}
#pragma warning restore 1998
#line 12 "x:\dir\subdir\Test\TestComponent.cshtml"
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
#line default
#line hidden
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,30 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (1:0,1 [36] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Blazor
UsingDirective - (140:6,1 [46] ) - Microsoft.AspNetCore.Blazor.Components
ClassDeclaration - - public - TestComponent - Microsoft.AspNetCore.Blazor.Components.BlazorComponent -
MethodDeclaration - - protected override - void - BuildRenderTree
CSharpCode -
IntermediateToken - - CSharp - base.BuildRenderTree(builder);
HtmlBlock - - <h1>Item1</h1>\n
CSharpCode - (94:5,1 [34] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (94:5,1 [34] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - foreach (var item2 in Items2)\n{\n
HtmlContent - (128:7,0 [4] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (128:7,0 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
HtmlElement - (132:7,4 [40] x:\dir\subdir\Test\TestComponent.cshtml) - p
HtmlContent - (135:7,7 [6] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (135:7,7 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpExpression - (142:8,5 [19] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (142:8,5 [19] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ChildContent(item2)
HtmlContent - (161:8,24 [7] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (161:8,24 [7] x:\dir\subdir\Test\TestComponent.cshtml) - Html - ;\n
HtmlContent - (172:9,8 [2] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (172:9,8 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (174:10,0 [3] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (174:10,0 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - }\n
CSharpCode - (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml)
IntermediateToken - (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n [Parameter] TItem1 Item1 { get; set; }\n [Parameter] List<TItem2> Items2 { get; set; }\n [Parameter] RenderFragment<TItem2> ChildContent { get; set; }\n

View File

@ -0,0 +1,29 @@
Source Location: (94:5,1 [34] x:\dir\subdir\Test\TestComponent.cshtml)
|foreach (var item2 in Items2)
{
|
Generated Location: (731:20,1 [34] )
|foreach (var item2 in Items2)
{
|
Source Location: (174:10,0 [3] x:\dir\subdir\Test\TestComponent.cshtml)
|}
|
Generated Location: (1163:34,0 [3] )
|}
|
Source Location: (189:11,12 [164] x:\dir\subdir\Test\TestComponent.cshtml)
|
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
|
Generated Location: (1310:41,12 [164] )
|
[Parameter] TItem1 Item1 { get; set; }
[Parameter] List<TItem2> Items2 { get; set; }
[Parameter] RenderFragment<TItem2> ChildContent { get; set; }
|

View File

@ -124,6 +124,73 @@ namespace Test
kvp => { Assert.Equal(TagHelperMetadata.Common.PropertyName, kvp.Key); Assert.Equal("MyProperty", kvp.Value); });
}
[Fact]
public void Excecute_FindsIComponentType_CreatesDescriptor_Generic()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : IComponent
{
public void Init(RenderHandle renderHandle) { }
public void SetParameters(ParameterCollection parameters) { }
[Parameter]
private string MyProperty { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components);
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Equal("Test.MyComponent<T>", component.DisplayName);
Assert.Equal("Test.MyComponent<T>", component.GetTypeName());
Assert.True(component.IsGenericTypedComponent());
var rule = Assert.Single(component.TagMatchingRules);
Assert.Equal("MyComponent", rule.TagName);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("MyProperty", a.Name);
Assert.Equal("MyProperty", a.GetPropertyName());
Assert.Equal("string Test.MyComponent<T>.MyProperty", a.DisplayName);
Assert.Equal("System.String", a.TypeName);
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
}
[Fact]
public void Excecute_FindsBlazorComponentType_CreatesDescriptor()
{
@ -263,6 +330,142 @@ namespace Test
Assert.False(attribute.IsStringProperty);
}
[Fact]
public void Excecute_GenericProperty_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
T MyProperty { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components);
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("MyProperty", a.Name);
Assert.Equal("MyProperty", a.GetPropertyName());
Assert.Equal("T Test.MyComponent<T>.MyProperty", a.DisplayName);
Assert.Equal("T", a.TypeName);
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
}
[Fact]
public void Excecute_MultipleGenerics_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T, U, V> : BlazorComponent
{
[Parameter]
T MyProperty1 { get; set; }
[Parameter]
U MyProperty2 { get; set; }
[Parameter]
V MyProperty3 { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components);
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T, U, V>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("MyProperty1", a.Name);
Assert.Equal("T", a.TypeName);
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("MyProperty2", a.Name);
Assert.Equal("U", a.TypeName);
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("MyProperty3", a.Name);
Assert.Equal("V", a.TypeName);
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.True(a.IsTypeParameterProperty());
},
a =>
{
Assert.Equal("U", a.Name);
Assert.True(a.IsTypeParameterProperty());
},
a =>
{
Assert.Equal("V", a.Name);
Assert.True(a.IsTypeParameterProperty());
});
}
[Fact]
public void Execute_DelegateProperty_CreatesDescriptor()
{
@ -313,6 +516,68 @@ namespace Test
Assert.False(attribute.IsChildContentProperty());
}
[Fact]
public void Execute_DelegateProperty_CreatesDescriptor_Generic()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using System;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
Action<T> OnClick { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components);
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("OnClick", a.Name);
Assert.Equal("System.Action<T>", a.TypeName);
Assert.False(a.HasIndexer);
Assert.False(a.IsBooleanProperty);
Assert.False(a.IsEnum);
Assert.False(a.IsStringProperty);
Assert.True(a.IsDelegateProperty());
Assert.False(a.IsChildContentProperty());
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
}
[Fact]
public void Execute_RenderFragmentProperty_CreatesDescriptors()
{
@ -418,6 +683,7 @@ namespace Test
Assert.False(attribute.IsDelegateProperty()); // We treat RenderFragment as separate from generalized delegates
Assert.True(attribute.IsChildContentProperty());
Assert.True(attribute.IsParameterizedChildContentProperty());
Assert.False(attribute.IsGenericTypedProperty());
var childContent = Assert.Single(components, c => c.IsChildContentTagHelper());
@ -431,6 +697,313 @@ namespace Test
Assert.Equal("Specifies the parameter name for the 'ChildContent2' lambda expression.", contextAttribute.Documentation);
}
[Fact]
public void Execute_RenderFragmentGenericProperty_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
RenderFragment<T> ChildContent2 { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components, c => c.IsComponentTagHelper());
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("ChildContent2", a.Name);
Assert.Equal("Microsoft.AspNetCore.Blazor.RenderFragment<T>", a.TypeName);
Assert.False(a.HasIndexer);
Assert.False(a.IsBooleanProperty);
Assert.False(a.IsEnum);
Assert.False(a.IsStringProperty);
Assert.False(a.IsDelegateProperty()); // We treat RenderFragment as separate from generalized delegates
Assert.True(a.IsChildContentProperty());
Assert.True(a.IsParameterizedChildContentProperty());
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
var childContent = Assert.Single(components, c => c.IsChildContentTagHelper());
Assert.Equal("TestAssembly", childContent.AssemblyName);
Assert.Equal("Test.MyComponent<T>.ChildContent2", childContent.Name);
// A RenderFragment<T> tag helper has a parameter to allow you to set the lambda parameter name.
var contextAttribute = Assert.Single(childContent.BoundAttributes);
Assert.Equal("Context", contextAttribute.Name);
Assert.Equal("System.String", contextAttribute.TypeName);
Assert.Equal("Specifies the parameter name for the 'ChildContent2' lambda expression.", contextAttribute.Documentation);
}
[Fact]
public void Execute_RenderFragmentClosedGenericListProperty_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using System.Collections.Generic;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
RenderFragment<List<string>> ChildContent2 { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components, c => c.IsComponentTagHelper());
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("ChildContent2", a.Name);
Assert.Equal("Microsoft.AspNetCore.Blazor.RenderFragment<System.Collections.Generic.List<System.String>>", a.TypeName);
Assert.False(a.HasIndexer);
Assert.False(a.IsBooleanProperty);
Assert.False(a.IsEnum);
Assert.False(a.IsStringProperty);
Assert.False(a.IsDelegateProperty()); // We treat RenderFragment as separate from generalized delegates
Assert.True(a.IsChildContentProperty());
Assert.True(a.IsParameterizedChildContentProperty());
Assert.False(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
var childContent = Assert.Single(components, c => c.IsChildContentTagHelper());
Assert.Equal("TestAssembly", childContent.AssemblyName);
Assert.Equal("Test.MyComponent<T>.ChildContent2", childContent.Name);
// A RenderFragment<T> tag helper has a parameter to allow you to set the lambda parameter name.
var contextAttribute = Assert.Single(childContent.BoundAttributes);
Assert.Equal("Context", contextAttribute.Name);
Assert.Equal("System.String", contextAttribute.TypeName);
Assert.Equal("Specifies the parameter name for the 'ChildContent2' lambda expression.", contextAttribute.Documentation);
}
[Fact]
public void Execute_RenderFragmentGenericListProperty_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using System.Collections.Generic;
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
RenderFragment<List<T>> ChildContent2 { get; set; }
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components, c => c.IsComponentTagHelper());
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("ChildContent2", a.Name);
Assert.Equal("Microsoft.AspNetCore.Blazor.RenderFragment<System.Collections.Generic.List<T>>", a.TypeName);
Assert.False(a.HasIndexer);
Assert.False(a.IsBooleanProperty);
Assert.False(a.IsEnum);
Assert.False(a.IsStringProperty);
Assert.False(a.IsDelegateProperty()); // We treat RenderFragment as separate from generalized delegates
Assert.True(a.IsChildContentProperty());
Assert.True(a.IsParameterizedChildContentProperty());
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
var childContent = Assert.Single(components, c => c.IsChildContentTagHelper());
Assert.Equal("TestAssembly", childContent.AssemblyName);
Assert.Equal("Test.MyComponent<T>.ChildContent2", childContent.Name);
// A RenderFragment<T> tag helper has a parameter to allow you to set the lambda parameter name.
var contextAttribute = Assert.Single(childContent.BoundAttributes);
Assert.Equal("Context", contextAttribute.Name);
Assert.Equal("System.String", contextAttribute.TypeName);
Assert.Equal("Specifies the parameter name for the 'ChildContent2' lambda expression.", contextAttribute.Documentation);
}
[Fact]
public void Execute_RenderFragmentGenericContextProperty_CreatesDescriptor()
{
// Arrange
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
using Microsoft.AspNetCore.Blazor;
using Microsoft.AspNetCore.Blazor.Components;
namespace Test
{
public class MyComponent<T> : BlazorComponent
{
[Parameter]
RenderFragment<Context> ChildContent2 { get; set; }
public class Context
{
public T Item { get; set; }
}
}
}
"));
Assert.Empty(compilation.GetDiagnostics());
var context = TagHelperDescriptorProviderContext.Create();
context.SetCompilation(compilation);
var provider = new ComponentTagHelperDescriptorProvider();
// Act
provider.Execute(context);
// Assert
var components = ExcludeBuiltInComponents(context);
var component = Assert.Single(components, c => c.IsComponentTagHelper());
Assert.Equal("TestAssembly", component.AssemblyName);
Assert.Equal("Test.MyComponent<T>", component.Name);
Assert.Collection(
component.BoundAttributes.OrderBy(a => a.Name),
a =>
{
Assert.Equal("ChildContent2", a.Name);
Assert.Equal("Microsoft.AspNetCore.Blazor.RenderFragment<Test.MyComponent<T>.Context>", a.TypeName);
Assert.False(a.HasIndexer);
Assert.False(a.IsBooleanProperty);
Assert.False(a.IsEnum);
Assert.False(a.IsStringProperty);
Assert.False(a.IsDelegateProperty()); // We treat RenderFragment as separate from generalized delegates
Assert.True(a.IsChildContentProperty());
Assert.True(a.IsParameterizedChildContentProperty());
Assert.True(a.IsGenericTypedProperty());
},
a =>
{
Assert.Equal("T", a.Name);
Assert.Equal("T", a.GetPropertyName());
Assert.Equal("T", a.DisplayName);
Assert.Equal("System.Type", a.TypeName);
Assert.True(a.IsTypeParameterProperty());
});
var childContent = Assert.Single(components, c => c.IsChildContentTagHelper());
Assert.Equal("TestAssembly", childContent.AssemblyName);
Assert.Equal("Test.MyComponent<T>.ChildContent2", childContent.Name);
// A RenderFragment<T> tag helper has a parameter to allow you to set the lambda parameter name.
var contextAttribute = Assert.Single(childContent.BoundAttributes);
Assert.Equal("Context", contextAttribute.Name);
Assert.Equal("System.String", contextAttribute.TypeName);
Assert.Equal("Specifies the parameter name for the 'ChildContent2' lambda expression.", contextAttribute.Documentation);
}
[Fact]
public void Execute_MultipleRenderFragmentProperties_CreatesDescriptor()
{

View File

@ -0,0 +1,46 @@
// 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.CodeAnalysis.CSharp;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Razor
{
public class GenericTypeNameRewriterTest
{
[Theory]
[InlineData("TItem2", "Type2")]
// Unspecified argument -> System.Object
[InlineData("TItem3", "System.Object")]
// Not a type parameter
[InlineData("TItem4", "TItem4")]
// In a qualified name, not a type parameter
[InlineData("TItem1.TItem2", "TItem1.TItem2")]
// Type parameters can't have type parameters
[InlineData("TItem1.TItem2<TItem1, TItem2, TItem3>", "TItem1.TItem2<Type1, Type2, System.Object>")]
[InlineData("TItem2<TItem1<TItem3>, System.TItem2, RenderFragment<List<TItem1>>", "TItem2<TItem1<System.Object>, System.TItem2, RenderFragment<List<Type1>>")]
public void GenericTypeNameRewriter_CanReplaceTypeParametersWithTypeArguments(string original, string expected)
{
// Arrange
var visitor = new GenericTypeNameRewriter(new Dictionary<string, GenericTypeNameRewriter.Binding>()
{
{ "TItem1", new GenericTypeNameRewriter.Binding(){ Content = "Type1", } },
{ "TItem2", new GenericTypeNameRewriter.Binding(){ Content = "Type2", } },
{ "TItem3", new GenericTypeNameRewriter.Binding(){ Content = null, } },
});
var parsed = SyntaxFactory.ParseTypeName(original);
// Act
var actual = visitor.Visit(parsed);
// Assert
Assert.Equal(expected, actual.ToString());
}
}
}

View File

@ -1,4 +1,4 @@
<TemplatedTable Items="@Items">
<TemplatedTable Items="@Items" TItem="Item">
<Header><tr><th>Col1</th><th>Col2</th><th>Col3</th></tr></Header>
<Footer>
@if (ShowFooter)
@ -14,12 +14,19 @@
Toggle: <input type="checkbox" bind="ShowFooter" id="toggle"/>
@functions {
List<TemplatedTable.Item> Items { get; } = new List<TemplatedTable.Item>()
List<Item> Items { get; } = new List<Item>()
{
new TemplatedTable.Item(){ Col1 = "a0", Col2 = "b0", Col3 = "c0", },
new TemplatedTable.Item(){ Col1 = "a1", Col2 = "b1", Col3 = "c1", },
new TemplatedTable.Item(){ Col1 = "a2", Col2 = "b2", Col3 = "c2", },
new Item(){ Col1 = "a0", Col2 = "b0", Col3 = "c0", },
new Item(){ Col1 = "a1", Col2 = "b1", Col3 = "c1", },
new Item(){ Col1 = "a2", Col2 = "b2", Col3 = "c2", },
};
bool ShowFooter;
public class Item
{
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
}
}

View File

@ -1,3 +1,5 @@
@typeparam TItem
<ol>
@{
var index = 1;
@ -9,7 +11,7 @@
</ol>
@functions{
[Parameter] IEnumerable<string> Items { get; set; }
[Parameter] IEnumerable<TItem> Items { get; set; }
[Parameter] RenderFragment<Context> Template { get; set; }
@ -17,6 +19,6 @@
{
public int Index { get; set; }
public string Item { get; set; }
public TItem Item { get; set; }
}
}

View File

@ -4,7 +4,7 @@
<div id="codeblocktemplate">
@{
RenderFragment<OrderedList.Context> template = (context) => @<li>#@context.Index - @context.Item.ToLower()</li>;
RenderFragment<OrderedList<string>.Context> template = (context) => @<li>#@context.Index - @context.Item.ToLower()</li>;
}
<OrderedList Items="@items" Template="@template" />
<OrderedList Items="@items" Template="@template" TItem="string"/>
</div>

View File

@ -1,3 +1,4 @@
@typeparam TItem
<table>
@if (Header != null)
{
@ -24,18 +25,11 @@
RenderFragment Header { get; set; }
[Parameter]
RenderFragment<Item> ItemTemplate { get; set; }
RenderFragment<TItem> ItemTemplate { get; set; }
[Parameter]
RenderFragment Footer { get; set; }
[Parameter]
IReadOnlyList<Item> Items { get; set; }
public class Item
{
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
}
IReadOnlyList<TItem> Items { get; set; }
}