Add ability for unbound complex `TagHelper` attributes to flow through MVC attribute resolution system.

- Today MVC has specific rules about resolving Razor attribute values. Ex: `true` => attribute name being used as attribute value. This change ensures that unbound complex `TagHelper` attribute use that same logic.
- Added configuration to `GeneratedTagHelperContext` for `AddHtmlAttributeValues`.
- Had to be careful with code generating `AddHtmlAttributeValues`. In the case of `data-`; they can appear as complex attributes but may not contain any pieces that are `DynamicAttributeBlockChunk`s. Had to protect against this scenario.
- Updated existing test files.
- Added a new code gen test case to showcase the various use-cases of unbound dynamic `TagHelper` attributes.

#247
This commit is contained in:
N. Taylor Mullen 2015-08-04 15:29:29 -07:00
parent fa9f2ace5f
commit 4604c807c4
11 changed files with 1113 additions and 143 deletions

View File

@ -404,25 +404,15 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
private void RenderUnboundAttribute(string attributeName, Chunk attributeValueChunk)
{
string textValue = null;
var isPlainTextValue = false;
// A null attribute value means the HTML attribute is minimized.
if (attributeValueChunk != null)
{
isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue);
// HTML attributes are always strings. So if this value is not plain text i.e. if the value contains
// C# code, then we need to buffer it.
if (!isPlainTextValue)
{
BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: true);
}
}
// Execution contexts are a runtime feature, therefore no need to add anything to them.
// Render children to provide IntelliSense at design time. No need for the execution context logic, it's
// a runtime feature.
if (_designTimeMode)
{
if (attributeValueChunk != null)
{
_bodyVisitor.Accept(attributeValueChunk);
}
return;
}
@ -438,27 +428,60 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
}
else
{
_writer
.WriteStartInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
.WriteStringLiteral(attributeName)
.WriteParameterSeparator()
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName);
string textValue = null;
var isPlainTextValue = TryGetPlainTextValue(attributeValueChunk, out textValue);
// If it's a plain text value then we need to surround the value with quotes.
if (isPlainTextValue)
{
_writer.WriteStringLiteral(textValue);
// If it's a plain text value then we need to surround the value with quotes.
_writer
.WriteStartInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
.WriteStringLiteral(attributeName)
.WriteParameterSeparator()
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName)
.WriteStringLiteral(textValue)
.WriteEndMethodInvocation(endLine: false)
.WriteEndMethodInvocation();
}
else if (IsDynamicAttributeValue(attributeValueChunk))
{
// Dynamic attribute value should be run through the conditional attribute removal system. It's
// unbound and contains C#.
_writer
.WriteStartMethodInvocation(_tagHelperContext.AddHtmlAttributeValuesMethodName)
.WriteStringLiteral(attributeName)
.WriteParameterSeparator()
.Write(ExecutionContextVariableName);
_bodyVisitor.Accept(attributeValueChunk);
_writer.WriteEndMethodInvocation();
}
else
{
RenderBufferedAttributeValueAccessor(_writer);
}
// HTML attributes are always strings. This attribute contains C# but is not dynamic. This occurs
// when the attribute is a data-* attribute.
_writer
.WriteEndMethodInvocation(endLine: false)
.WriteEndMethodInvocation();
// Attribute value is not plain text, must be buffered to determine its final value.
BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: true);
_writer
.WriteStartInstanceMethodInvocation(
ExecutionContextVariableName,
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
.WriteStringLiteral(attributeName)
.WriteParameterSeparator()
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName);
RenderBufferedAttributeValueAccessor(_writer);
_writer
.WriteEndMethodInvocation(endLine: false)
.WriteEndMethodInvocation();
}
}
}
@ -616,6 +639,17 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
}
}
private static bool IsDynamicAttributeValue(Chunk attributeValueChunk)
{
var parentChunk = attributeValueChunk as ParentChunk;
if (parentChunk != null)
{
return parentChunk.Children.Any(child => child is DynamicCodeAttributeChunk);
}
return false;
}
private static bool TryGetPlainTextValue(Chunk chunk, out string plainText)
{
var parentChunk = chunk as ParentChunk;

View File

@ -13,6 +13,7 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
/// </summary>
public GeneratedTagHelperContext()
{
AddHtmlAttributeValuesMethodName = "AddHtmlAttributeValues";
CreateTagHelperMethodName = "CreateTagHelper";
RunnerRunAsyncMethodName = "RunAsync";
ScopeManagerBeginMethodName = "Begin";
@ -34,6 +35,20 @@ namespace Microsoft.AspNet.Razor.CodeGenerators
WriteTagHelperToAsyncMethodName = "WriteTagHelperToAsync";
}
/// <summary>
/// The name of the method used to add unbound, complex tag helper attributes to TagHelperExecutionContexts.
/// </summary>
/// <remarks>
/// Method signature should be
/// <code>
/// public void AddHtmlAttributeValues(
/// string attributeName,
/// TagHelperExecutionContext executionContext,
/// params Microsoft.AspNet.Mvc.Razor.AttributeValue[] values)
/// </code>
/// </remarks>
public string AddHtmlAttributeValuesMethodName { get; set; }
/// <summary>
/// The name of the method used to create a tag helper.
/// </summary>

View File

@ -324,7 +324,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
// We need to rebuild the chunk generators of the builder and its children (this is needed to
// ensure we don't do special attribute chunk generation since this is a tag helper).
block = RebuildChunkGenerators(builder.Build());
block = RebuildChunkGenerators(builder.Build(), result.IsBoundAttribute);
// If there's only 1 child at this point its value could be a simple markup span (treated differently than
// block level elements for attributes).
@ -376,10 +376,27 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
return blockBuilder.Build();
}
private static Block RebuildChunkGenerators(Block block)
private static Block RebuildChunkGenerators(Block block, bool isBound)
{
var builder = new BlockBuilder(block);
// Don't want to rebuild unbound dynamic attributes. They need to run through the conditional attribute
// removal system at runtime. A conditional attribute at the parse tree rewriting level is defined by
// having at least 1 child with a DynamicAttributeBlockChunkGenerator.
if (!isBound &&
block.Children.Any(
child => child.IsBlock &&
((Block)child).ChunkGenerator is DynamicAttributeBlockChunkGenerator))
{
// The parent chunk generator must be removed because it's normally responsible for conditionally
// generating the attribute prefix (class=") and suffix ("). The prefix and suffix concepts aren't
// applicable for the TagHelper use case since the attributes are put into a dictionary like object as
// name value pairs.
builder.ChunkGenerator = ParentChunkGenerator.Null;
return builder.Build();
}
var isDynamic = builder.ChunkGenerator is DynamicAttributeBlockChunkGenerator;
// We don't want any attribute specific logic here, null out the block chunk generator.
@ -395,7 +412,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers.Internal
if (child.IsBlock)
{
// The child is a block, recurse down into the block to rebuild its children
builder.Children[i] = RebuildChunkGenerators((Block)child);
builder.Children[i] = RebuildChunkGenerators((Block)child, isBound);
}
else
{

View File

@ -63,6 +63,29 @@ namespace Microsoft.AspNet.Razor.Test.Generator
}
}
private static IEnumerable<TagHelperDescriptor> DynamicAttributeTagHelpers_Descriptors
{
get
{
return new[]
{
new TagHelperDescriptor(
tagName: "input",
typeName: "InputTagHelper",
assemblyName: "SomeAssembly",
attributes: new[]
{
new TagHelperAttributeDescriptor(
"bound",
"Bound",
typeof(string).FullName,
isIndexer: false,
designTimeDescriptor: null)
}),
};
}
}
private static IEnumerable<TagHelperDescriptor> DuplicateTargetTagHelperDescriptors
{
get
@ -922,6 +945,261 @@ namespace Microsoft.AspNet.Razor.Test.Generator
contentLength: 1),
}
},
{
"DynamicAttributeTagHelpers",
"DynamicAttributeTagHelpers.DesignTime",
DynamicAttributeTagHelpers_Descriptors,
new List<LineMapping>
{
BuildLineMapping(
documentAbsoluteIndex: 14,
documentLineIndex: 0,
generatedAbsoluteIndex: 497,
generatedLineIndex: 15,
characterOffsetIndex: 14,
contentLength: 17),
BuildLineMapping(
documentAbsoluteIndex: 59,
documentLineIndex: 2,
documentCharacterOffsetIndex: 24,
generatedAbsoluteIndex: 1002,
generatedLineIndex: 34,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 96,
documentLineIndex: 4,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 1160,
generatedLineIndex: 40,
generatedCharacterOffsetIndex: 0,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 109,
documentLineIndex: 4,
documentCharacterOffsetIndex: 30,
generatedAbsoluteIndex: 1258,
generatedLineIndex: 46,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 121,
documentLineIndex: 4,
documentCharacterOffsetIndex: 42,
generatedAbsoluteIndex: 1349,
generatedLineIndex: 51,
generatedCharacterOffsetIndex: 0,
contentLength: 10),
BuildLineMapping(
documentAbsoluteIndex: 132,
documentLineIndex: 4,
documentCharacterOffsetIndex: 53,
generatedAbsoluteIndex: 1445,
generatedLineIndex: 57,
generatedCharacterOffsetIndex: 6,
contentLength: 5),
BuildLineMapping(
documentAbsoluteIndex: 137,
documentLineIndex: 4,
documentCharacterOffsetIndex: 58,
generatedAbsoluteIndex: 1529,
generatedLineIndex: 62,
generatedCharacterOffsetIndex: 0,
contentLength: 2),
BuildLineMapping(
documentAbsoluteIndex: 176,
documentLineIndex: 6,
documentCharacterOffsetIndex: 22,
generatedAbsoluteIndex: 1684,
generatedLineIndex: 69,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 214,
documentLineIndex: 6,
documentCharacterOffsetIndex: 60,
generatedAbsoluteIndex: 1833,
generatedLineIndex: 75,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 256,
documentLineIndex: 8,
documentCharacterOffsetIndex: 15,
generatedAbsoluteIndex: 1997,
generatedLineIndex: 81,
generatedCharacterOffsetIndex: 6,
contentLength: 13),
BuildLineMapping(
documentAbsoluteIndex: 271,
documentLineIndex: 8,
documentCharacterOffsetIndex: 30,
generatedAbsoluteIndex: 2089,
generatedLineIndex: 86,
generatedCharacterOffsetIndex: 0,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 284,
documentLineIndex: 8,
documentCharacterOffsetIndex: 43,
generatedAbsoluteIndex: 2187,
generatedLineIndex: 92,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 296,
documentLineIndex: 8,
documentCharacterOffsetIndex: 55,
generatedAbsoluteIndex: 2278,
generatedLineIndex: 97,
generatedCharacterOffsetIndex: 0,
contentLength: 10),
BuildLineMapping(
documentAbsoluteIndex: 307,
documentLineIndex: 8,
documentCharacterOffsetIndex: 66,
generatedAbsoluteIndex: 2374,
generatedLineIndex: 103,
generatedCharacterOffsetIndex: 6,
contentLength: 5),
BuildLineMapping(
documentAbsoluteIndex: 312,
documentLineIndex: 8,
documentCharacterOffsetIndex: 71,
generatedAbsoluteIndex: 2458,
generatedLineIndex: 108,
generatedCharacterOffsetIndex: 0,
contentLength: 2),
BuildLineMapping(
documentAbsoluteIndex: 316,
documentLineIndex: 8,
documentCharacterOffsetIndex: 75,
generatedAbsoluteIndex: 2546,
generatedLineIndex: 114,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 348,
documentLineIndex: 9,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 2696,
generatedLineIndex: 120,
generatedCharacterOffsetIndex: 6,
contentLength: 13),
BuildLineMapping(
documentAbsoluteIndex: 363,
documentLineIndex: 9,
documentCharacterOffsetIndex: 32,
generatedAbsoluteIndex: 2789,
generatedLineIndex: 125,
generatedCharacterOffsetIndex: 0,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 376,
documentLineIndex: 9,
documentCharacterOffsetIndex: 45,
generatedAbsoluteIndex: 2888,
generatedLineIndex: 131,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 388,
documentLineIndex: 9,
documentCharacterOffsetIndex: 57,
generatedAbsoluteIndex: 2980,
generatedLineIndex: 136,
generatedCharacterOffsetIndex: 0,
contentLength: 10),
BuildLineMapping(
documentAbsoluteIndex: 399,
documentLineIndex: 9,
documentCharacterOffsetIndex: 68,
generatedAbsoluteIndex: 3077,
generatedLineIndex: 142,
generatedCharacterOffsetIndex: 6,
contentLength: 5),
BuildLineMapping(
documentAbsoluteIndex: 404,
documentLineIndex: 9,
documentCharacterOffsetIndex: 73,
generatedAbsoluteIndex: 3162,
generatedLineIndex: 147,
generatedCharacterOffsetIndex: 0,
contentLength: 2),
BuildLineMapping(
documentAbsoluteIndex: 408,
documentLineIndex: 9,
documentCharacterOffsetIndex: 77,
generatedAbsoluteIndex: 3251,
generatedLineIndex: 153,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 445,
documentLineIndex: 11,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 3416,
generatedLineIndex: 159,
generatedCharacterOffsetIndex: 6,
contentLength: 13),
BuildLineMapping(
documentAbsoluteIndex: 460,
documentLineIndex: 11,
documentCharacterOffsetIndex: 32,
generatedAbsoluteIndex: 3515,
generatedLineIndex: 164,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 492,
documentLineIndex: 11,
documentCharacterOffsetIndex: 64,
generatedAbsoluteIndex: 3613,
generatedLineIndex: 169,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 529,
documentLineIndex: 13,
documentCharacterOffsetIndex: 17,
generatedAbsoluteIndex: 3772,
generatedLineIndex: 175,
generatedCharacterOffsetIndex: 0,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 542,
documentLineIndex: 13,
documentCharacterOffsetIndex: 30,
generatedAbsoluteIndex: 3871,
generatedLineIndex: 181,
generatedCharacterOffsetIndex: 6,
contentLength: 12),
BuildLineMapping(
documentAbsoluteIndex: 554,
documentLineIndex: 13,
documentCharacterOffsetIndex: 42,
generatedAbsoluteIndex: 3963,
generatedLineIndex: 186,
generatedCharacterOffsetIndex: 0,
contentLength: 10),
BuildLineMapping(
documentAbsoluteIndex: 565,
documentLineIndex: 13,
documentCharacterOffsetIndex: 53,
generatedAbsoluteIndex: 4060,
generatedLineIndex: 192,
generatedCharacterOffsetIndex: 6,
contentLength: 5),
BuildLineMapping(
documentAbsoluteIndex: 570,
documentLineIndex: 13,
documentCharacterOffsetIndex: 58,
generatedAbsoluteIndex: 4145,
generatedLineIndex: 197,
generatedCharacterOffsetIndex: 0,
contentLength: 2),
}
},
};
}
}
@ -965,6 +1243,7 @@ namespace Microsoft.AspNet.Razor.Test.Generator
PrefixedAttributeTagHelperDescriptors.Reverse()
},
{ "DuplicateAttributeTagHelpers", null, DefaultPAndInputTagHelperDescriptors },
{ "DynamicAttributeTagHelpers", null, DynamicAttributeTagHelpers_Descriptors },
};
}
}

View File

@ -32,17 +32,15 @@ namespace Microsoft.AspNet.Razor.TagHelpers
{
return new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(10, 0, 10)),
new SourceLocation(10, 0, 10)),
new StatementBlock(
factory.CodeTransition(),
factory.Code("do {" + extraCode).AsStatement())));
};
var dateTimeNow = new MarkupBlock(
new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))));
return new TheoryData<string, MarkupBlock, RazorError[]>
{
@ -301,7 +299,20 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>(
"class",
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(9, 0, 9)),
new SourceLocation(9, 0, 9)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))))
})),
new []
{
@ -803,12 +814,6 @@ namespace Microsoft.AspNet.Razor.TagHelpers
var blockFactory = new BlockFactory(factory);
var malformedErrorFormat = "Found a malformed '{0}' tag helper. Tag helpers must have a start and " +
"end tag or be self closing.";
var dateTimeNow = new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
yield return new object[]
{
@ -818,7 +823,20 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>(
"dynamic",
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(21, 0, 21)),
new SourceLocation(21, 0, 21)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))))),
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;"))
},
new MarkupTagHelperBlock("strong")),
@ -991,25 +1009,45 @@ namespace Microsoft.AspNet.Razor.TagHelpers
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var dateTimeNowString = "@DateTime.Now";
var dateTimeNow = new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
var dateTimeNow = new Func<int, SyntaxTreeNode>(index =>
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(index, 0, index)),
new SourceLocation(index, 0, index)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))));
var doWhileString = "@do { var foo = bar; <text>Foo</text> foo++; } while (foo<bar>);";
var doWhile = new MarkupBlock(
new StatementBlock(
factory.CodeTransition(),
factory.Code("do { var foo = bar;").AsStatement(),
new MarkupBlock(
new MarkupTagBlock(
factory.MarkupTransition("<text>")),
factory.Markup("Foo").Accepts(AcceptedCharacters.None),
new MarkupTagBlock(
factory.MarkupTransition("</text>")),
factory.CodeMarkup(" ").With(new StatementChunkGenerator()).Accepts(AcceptedCharacters.None)),
factory.Code("foo++; } while (foo<bar>);").AsStatement().Accepts(AcceptedCharacters.None)));
var doWhile = new Func<int, SyntaxTreeNode>(index =>
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(index, 0, index)),
new SourceLocation(index, 0, index)),
new StatementBlock(
factory.CodeTransition(),
factory.Code("do { var foo = bar;").AsStatement(),
new MarkupBlock(
new MarkupTagBlock(
factory.MarkupTransition("<text>")),
factory.Markup("Foo").Accepts(AcceptedCharacters.None),
new MarkupTagBlock(
factory.MarkupTransition("</text>")),
factory
.CodeMarkup(" ")
.With(new StatementChunkGenerator())
.Accepts(AcceptedCharacters.None)),
factory
.Code("foo++; } while (foo<bar>);")
.AsStatement()
.Accepts(AcceptedCharacters.None)))));
var currentFormattedString = "<p class=\"{0}\" style='{0}'></p>";
yield return new object[]
@ -1019,8 +1057,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10)),
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(32))
}))
};
yield return new object[]
@ -1030,8 +1068,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(doWhile)),
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(doWhile))
new KeyValuePair<string, SyntaxTreeNode>("class", doWhile(10)),
new KeyValuePair<string, SyntaxTreeNode>("style", doWhile(83))
}))
};
@ -1043,8 +1081,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10)),
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(32))
},
factory.Markup("Hello World")))
};
@ -1055,8 +1093,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(doWhile)),
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(doWhile))
new KeyValuePair<string, SyntaxTreeNode>("class", doWhile(10)),
new KeyValuePair<string, SyntaxTreeNode>("style", doWhile(83))
},
factory.Markup("Hello World")))
};
@ -1069,14 +1107,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10))
},
factory.Markup("Hello")),
factory.Markup(" "),
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(45))
},
factory.Markup("World")))
};
@ -1087,14 +1125,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(doWhile))
new KeyValuePair<string, SyntaxTreeNode>("class", doWhile(10))
},
factory.Markup("Hello")),
factory.Markup(" "),
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(doWhile))
new KeyValuePair<string, SyntaxTreeNode>("style", doWhile(96))
},
factory.Markup("World")))
};
@ -1108,8 +1146,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new MarkupTagHelperBlock("p",
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("style", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10)),
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(32))
},
factory.Markup("Hello World "),
new MarkupTagBlock(
@ -1977,12 +2015,19 @@ namespace Microsoft.AspNet.Razor.TagHelpers
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var dateTimeNow = new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)));
var dateTimeNow = new Func<int, SyntaxTreeNode>(index =>
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(index, 0, index)),
new SourceLocation(index, 0, index)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))));
yield return new object[]
{
@ -1992,7 +2037,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(21)),
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;"))
}))
};
@ -2004,7 +2049,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(21)),
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;"))
},
factory.Markup("Hello World")))
@ -2017,7 +2062,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(21)),
new KeyValuePair<string, SyntaxTreeNode>(
"style",
new MarkupBlock(
@ -2037,7 +2082,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(21))
},
factory.Markup("Hello")),
factory.Markup(" "),
@ -2045,7 +2090,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow))
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(73))
},
factory.Markup("World")))
};
@ -2057,7 +2102,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("foo")),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", new MarkupBlock(dateTimeNow)),
new KeyValuePair<string, SyntaxTreeNode>("dynamic", dateTimeNow(21)),
new KeyValuePair<string, SyntaxTreeNode>("style", factory.Markup("color:red;"))
},
factory.Markup("Hello World "),
@ -2394,15 +2439,27 @@ namespace Microsoft.AspNet.Razor.TagHelpers
var stringType = typeof(string).FullName;
var intType = typeof(int).FullName;
var expressionString = "@DateTime.Now + 1";
var expression = new MarkupBlock(
var expression = new Func<int, SyntaxTreeNode>(index =>
new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
factory.Markup(" +"),
factory.Markup(" 1"));
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(index, 0, index)),
new SourceLocation(index, 0, index)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))),
factory.Markup(" +")
.With(new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(" ", index + 13, 0, index + 13),
value: new LocationTagged<string>("+", index + 14, 0, index + 14))),
factory.Markup(" 1")
.With(new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(" ", index + 15, 0, index + 15),
value: new LocationTagged<string>("1", index + 16, 0, index + 16)))));
// documentContent, expectedOutput, expectedErrors
return new TheoryData<string, MarkupBlock, RazorError[]>
@ -2933,7 +2990,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
selfClosing: true,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>()
{
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(14)),
new KeyValuePair<string, SyntaxTreeNode>("bound-required-int", null),
})),
new[]
@ -2950,7 +3007,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
selfClosing: false,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>()
{
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(10)),
new KeyValuePair<string, SyntaxTreeNode>("bound-int", null),
})),
new[]
@ -2968,9 +3025,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>()
{
new KeyValuePair<string, SyntaxTreeNode>("bound-required-int", null),
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(36)),
new KeyValuePair<string, SyntaxTreeNode>("bound-required-string", null),
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(86)),
new KeyValuePair<string, SyntaxTreeNode>("unbound-required", null),
})),
new[]
@ -2995,9 +3052,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>()
{
new KeyValuePair<string, SyntaxTreeNode>("bound-int", null),
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(23)),
new KeyValuePair<string, SyntaxTreeNode>("bound-string", null),
new KeyValuePair<string, SyntaxTreeNode>("class", expression),
new KeyValuePair<string, SyntaxTreeNode>("class", expression(64)),
new KeyValuePair<string, SyntaxTreeNode>("bound-string", null),
})),
new[]
@ -3029,10 +3086,85 @@ namespace Microsoft.AspNet.Razor.TagHelpers
factory.MetaCode("}").Accepts(AcceptedCharacters.None)),
factory.EmptyHtml());
};
Action<MarkupBlock> updateDynamicChunkGenerators = (block) =>
{
var tagHelperBlock = block.Children.First() as MarkupTagHelperBlock;
for (var i = 0; i < tagHelperBlock.Attributes.Count; i++)
{
var attribute = tagHelperBlock.Attributes[i];
var holderBlock = attribute.Value as Block;
if (holderBlock == null)
{
continue;
}
var valueBlock = holderBlock.Children.FirstOrDefault() as Block;
if (valueBlock != null)
{
var chunkGenerator = valueBlock.ChunkGenerator as DynamicAttributeBlockChunkGenerator;
if (chunkGenerator != null)
{
var blockBuilder = new BlockBuilder(holderBlock);
var expressionBlockBuilder = new BlockBuilder(valueBlock);
var newChunkGenerator = new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
chunkGenerator.Prefix.Value,
new SourceLocation(
chunkGenerator.Prefix.Location.AbsoluteIndex + 2,
chunkGenerator.Prefix.Location.LineIndex,
chunkGenerator.Prefix.Location.CharacterIndex + 2)),
new SourceLocation(
chunkGenerator.ValueStart.AbsoluteIndex + 2,
chunkGenerator.ValueStart.LineIndex,
chunkGenerator.ValueStart.CharacterIndex + 2));
expressionBlockBuilder.ChunkGenerator = newChunkGenerator;
blockBuilder.Children[0] = expressionBlockBuilder.Build();
for (var j = 1; j < blockBuilder.Children.Count; j++)
{
var span = blockBuilder.Children[j] as Span;
if (span != null)
{
var literalChunkGenerator =
span.ChunkGenerator as LiteralAttributeChunkGenerator;
var spanBuilder = new SpanBuilder(span);
spanBuilder.ChunkGenerator = new LiteralAttributeChunkGenerator(
prefix: new LocationTagged<string>(
literalChunkGenerator.Prefix.Value,
new SourceLocation(
literalChunkGenerator.Prefix.Location.AbsoluteIndex + 2,
literalChunkGenerator.Prefix.Location.LineIndex,
literalChunkGenerator.Prefix.Location.CharacterIndex + 2)),
value: new LocationTagged<string>(
literalChunkGenerator.Value.Value,
new SourceLocation(
literalChunkGenerator.Value.Location.AbsoluteIndex + 2,
literalChunkGenerator.Value.Location.LineIndex,
literalChunkGenerator.Value.Location.CharacterIndex + 2)));
blockBuilder.Children[j] = spanBuilder.Build();
}
}
tagHelperBlock.Attributes[i] = new KeyValuePair<string, SyntaxTreeNode>(
attribute.Key,
blockBuilder.Build());
}
}
}
};
foreach (var data in documentData)
{
data[0] = $"@{{{data[0]}}}";
updateDynamicChunkGenerators(data[1] as MarkupBlock);
data[1] = buildStatementBlock(() => data[1] as MarkupBlock);
var errors = data[2] as RazorError[];

View File

@ -23,13 +23,19 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
{
var factory = CreateDefaultSpanFactory();
var blockFactory = new BlockFactory(factory);
var dateTimeNow = new MarkupBlock(
new MarkupBlock(
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace))));
var dateTimeNow = new Func<int, SyntaxTreeNode>(index =>
new MarkupBlock(
new MarkupBlock(
new DynamicAttributeBlockChunkGenerator(
new LocationTagged<string>(
string.Empty,
new SourceLocation(index, 0, index)),
new SourceLocation(index, 0, index)),
new ExpressionBlock(
factory.CodeTransition(),
factory.Code("DateTime.Now")
.AsImplicitExpression(CSharpCodeParser.DefaultKeywords)
.Accepts(AcceptedCharacters.NonWhiteSpace)))));
// documentContent, expectedOutput
return new TheoryData<string, MarkupBlock>
@ -73,7 +79,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
selfClosing: true,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10))
}))
},
{
@ -94,7 +100,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"p",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(10))
},
children: factory.Markup("words and spaces")))
},
@ -135,7 +141,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
selfClosing: true,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow(18))
}))
},
{
@ -156,7 +162,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"strong",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow(18))
},
children: factory.Markup("words and spaces")))
},
@ -217,7 +223,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
selfClosing: true,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("notRequired", dateTimeNow),
new KeyValuePair<string, SyntaxTreeNode>("notRequired", dateTimeNow(16)),
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("btn"))
}))
},
@ -253,7 +259,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
selfClosing: true,
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow),
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(12)),
new KeyValuePair<string, SyntaxTreeNode>("class", factory.Markup("btn"))
}))
},
@ -276,8 +282,8 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"div",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow),
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(12)),
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(34))
},
children: factory.Markup("words and spaces")))
},
@ -376,9 +382,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers
"div",
attributes: new List<KeyValuePair<string, SyntaxTreeNode>>
{
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow),
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow),
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow)
new KeyValuePair<string, SyntaxTreeNode>("style", dateTimeNow(12)),
new KeyValuePair<string, SyntaxTreeNode>("class", dateTimeNow(34)),
new KeyValuePair<string, SyntaxTreeNode>("catchAll", dateTimeNow(59))
},
children: factory.Markup("words and spaces")))
},

View File

@ -239,15 +239,8 @@ if(true) {
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper);
StartTagHelperWritingScope();
WriteLiteral("Current Time: ");
#line 8 "ComplexTagHelpers.cshtml"
Write(DateTime.Now);
#line default
#line hidden
__tagHelperStringValueBuffer = EndTagHelperWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("time", Html.Raw(__tagHelperStringValueBuffer.ToString()));
AddHtmlAttributeValues("time", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 148), Tuple.Create("Current", 148), true), Tuple.Create(Tuple.Create(" ", 155), Tuple.Create("Time:", 156), true),
Tuple.Create(Tuple.Create(" ", 161), Tuple.Create<System.Object, System.Int32>(DateTime.Now, 162), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(139, 531, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);

View File

@ -0,0 +1,206 @@
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using System;
using System.Threading.Tasks;
public class DynamicAttributeTagHelpers
{
private static object @__o;
private void @__RazorDesignTimeHelpers__()
{
#pragma warning disable 219
string __tagHelperDirectiveSyntaxHelper = null;
__tagHelperDirectiveSyntaxHelper =
#line 1 "DynamicAttributeTagHelpers.cshtml"
"something, nice"
#line default
#line hidden
;
#pragma warning restore 219
}
#line hidden
private InputTagHelper __InputTagHelper = null;
#line hidden
public DynamicAttributeTagHelpers()
{
}
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 3 "DynamicAttributeTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 5 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
#line 5 "DynamicAttributeTagHelpers.cshtml"
__o = string.Empty;
#line default
#line hidden
#line 5 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
#line 5 "DynamicAttributeTagHelpers.cshtml"
__o = false;
#line default
#line hidden
#line 5 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 7 "DynamicAttributeTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
__InputTagHelper.Bound = string.Empty;
#line 7 "DynamicAttributeTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 9 "DynamicAttributeTagHelpers.cshtml"
__o = long.MinValue;
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
__o = string.Empty;
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
__o = false;
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
__o = int.MaxValue;
#line default
#line hidden
__InputTagHelper.Bound = string.Empty;
#line 10 "DynamicAttributeTagHelpers.cshtml"
__o = long.MinValue;
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
__o = string.Empty;
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
__o = false;
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
#line 10 "DynamicAttributeTagHelpers.cshtml"
__o = int.MaxValue;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 12 "DynamicAttributeTagHelpers.cshtml"
__o = long.MinValue;
#line default
#line hidden
#line 12 "DynamicAttributeTagHelpers.cshtml"
__o = DateTime.Now;
#line default
#line hidden
#line 12 "DynamicAttributeTagHelpers.cshtml"
__o = int.MaxValue;
#line default
#line hidden
__InputTagHelper = CreateTagHelper<InputTagHelper>();
#line 14 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
#line 14 "DynamicAttributeTagHelpers.cshtml"
__o = string.Empty;
#line default
#line hidden
#line 14 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
#line 14 "DynamicAttributeTagHelpers.cshtml"
__o = false;
#line default
#line hidden
#line 14 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
}
#pragma warning restore 1998
}
}

View File

@ -0,0 +1,281 @@
#pragma checksum "DynamicAttributeTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "782463195265ee647cc2fc63fd5095a80090845b"
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using System;
using System.Threading.Tasks;
public class DynamicAttributeTagHelpers
{
#line hidden
#pragma warning disable 0414
private TagHelperContent __tagHelperStringValueBuffer = null;
#pragma warning restore 0414
private TagHelperExecutionContext __tagHelperExecutionContext = null;
private TagHelperRunner __tagHelperRunner = null;
private TagHelperScopeManager __tagHelperScopeManager = new TagHelperScopeManager();
private InputTagHelper __InputTagHelper = null;
#line hidden
public DynamicAttributeTagHelpers()
{
}
#pragma warning disable 1998
public override async Task ExecuteAsync()
{
__tagHelperRunner = __tagHelperRunner ?? new TagHelperRunner();
Instrumentation.BeginContext(33, 2, true);
WriteLiteral("\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 51), Tuple.Create("prefix", 51), true),
Tuple.Create(Tuple.Create(" ", 57), Tuple.Create<System.Object, System.Int32>(DateTime.Now, 58), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(35, 40, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(75, 4, true);
WriteLiteral("\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 95), Tuple.Create<System.Object, System.Int32>(new Template((__razor_attribute_value_writer) => {
#line 5 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
Instrumentation.BeginContext(109, 12, false);
#line 5 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, string.Empty);
#line default
#line hidden
Instrumentation.EndContext();
#line 5 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
Instrumentation.BeginContext(132, 5, false);
#line 5 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, false);
#line default
#line hidden
Instrumentation.EndContext();
#line 5 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
}
), 95), false), Tuple.Create(Tuple.Create(" ", 139), Tuple.Create("suffix", 140), true));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(79, 71, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(150, 4, true);
WriteLiteral("\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartTagHelperWritingScope();
WriteLiteral("prefix ");
#line 7 "DynamicAttributeTagHelpers.cshtml"
WriteLiteral(DateTime.Now);
#line default
#line hidden
WriteLiteral(" suffix");
__tagHelperStringValueBuffer = EndTagHelperWritingScope();
__InputTagHelper.Bound = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("bound", __InputTagHelper.Bound);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 206), Tuple.Create("prefix", 206), true),
Tuple.Create(Tuple.Create(" ", 212), Tuple.Create<System.Object, System.Int32>(DateTime.Now, 213), false), Tuple.Create(Tuple.Create(" ", 226), Tuple.Create("suffix", 227), true));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(154, 83, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(237, 4, true);
WriteLiteral("\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
StartTagHelperWritingScope();
#line 9 "DynamicAttributeTagHelpers.cshtml"
WriteLiteral(long.MinValue);
#line default
#line hidden
WriteLiteral(" ");
#line 9 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
WriteLiteral(string.Empty);
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
WriteLiteral(false);
#line default
#line hidden
#line 9 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
WriteLiteral(" ");
#line 9 "DynamicAttributeTagHelpers.cshtml"
WriteLiteral(int.MaxValue);
#line default
#line hidden
__tagHelperStringValueBuffer = EndTagHelperWritingScope();
__InputTagHelper.Bound = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("bound", __InputTagHelper.Bound);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 347), Tuple.Create<System.Object, System.Int32>(long.MinValue, 347), false),
Tuple.Create(Tuple.Create(" ", 361), Tuple.Create<System.Object, System.Int32>(new Template((__razor_attribute_value_writer) => {
#line 10 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
Instrumentation.BeginContext(376, 12, false);
#line 10 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, string.Empty);
#line default
#line hidden
Instrumentation.EndContext();
#line 10 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
Instrumentation.BeginContext(399, 5, false);
#line 10 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, false);
#line default
#line hidden
Instrumentation.EndContext();
#line 10 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
}
), 362), false),
Tuple.Create(Tuple.Create(" ", 406), Tuple.Create<System.Object, System.Int32>(int.MaxValue, 407), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(241, 183, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(424, 4, true);
WriteLiteral("\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 444), Tuple.Create<System.Object, System.Int32>(long.MinValue, 444), false),
Tuple.Create(Tuple.Create(" ", 458), Tuple.Create<System.Object, System.Int32>(DateTime.Now, 459), false), Tuple.Create(Tuple.Create(" ", 472), Tuple.Create("static", 473), true), Tuple.Create(Tuple.Create(" ", 479), Tuple.Create("content", 483), true),
Tuple.Create(Tuple.Create(" ", 490), Tuple.Create<System.Object, System.Int32>(int.MaxValue, 491), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(428, 80, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
Instrumentation.BeginContext(508, 4, true);
WriteLiteral("\r\n\r\n");
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", true, "test", async() => {
}
, StartTagHelperWritingScope, EndTagHelperWritingScope);
__InputTagHelper = CreateTagHelper<InputTagHelper>();
__tagHelperExecutionContext.Add(__InputTagHelper);
AddHtmlAttributeValues("unbound", __tagHelperExecutionContext,
Tuple.Create(Tuple.Create("", 528), Tuple.Create<System.Object, System.Int32>(new Template((__razor_attribute_value_writer) => {
#line 14 "DynamicAttributeTagHelpers.cshtml"
if (true) {
#line default
#line hidden
Instrumentation.BeginContext(542, 12, false);
#line 14 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, string.Empty);
#line default
#line hidden
Instrumentation.EndContext();
#line 14 "DynamicAttributeTagHelpers.cshtml"
} else {
#line default
#line hidden
Instrumentation.BeginContext(565, 5, false);
#line 14 "DynamicAttributeTagHelpers.cshtml"
WriteTo(__razor_attribute_value_writer, false);
#line default
#line hidden
Instrumentation.EndContext();
#line 14 "DynamicAttributeTagHelpers.cshtml"
}
#line default
#line hidden
}
), 528), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(512, 64, false);
await WriteTagHelperAsync(__tagHelperExecutionContext);
Instrumentation.EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.End();
}
#pragma warning restore 1998
}
}

View File

@ -83,15 +83,8 @@ WriteLiteral(DateTime.Now);
__tagHelperStringValueBuffer = EndTagHelperWritingScope();
__MyTagHelper.BoundProperty = __tagHelperStringValueBuffer.ToString();
__tagHelperExecutionContext.AddTagHelperAttribute("boundproperty", __MyTagHelper.BoundProperty);
StartTagHelperWritingScope();
WriteLiteral("Current Time: ");
#line 9 "TagHelpersInSection.cshtml"
Write(DateTime.Now);
#line default
#line hidden
__tagHelperStringValueBuffer = EndTagHelperWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", Html.Raw(__tagHelperStringValueBuffer.ToString()));
AddHtmlAttributeValues("unboundproperty", __tagHelperExecutionContext, Tuple.Create(Tuple.Create("", 188), Tuple.Create("Current", 188), true), Tuple.Create(Tuple.Create(" ", 195), Tuple.Create("Time:", 196), true),
Tuple.Create(Tuple.Create(" ", 201), Tuple.Create<System.Object, System.Int32>(DateTime.Now, 202), false));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
Instrumentation.BeginContext(114, 245, false);
await WriteTagHelperToAsync(__razor_template_writer, __tagHelperExecutionContext);

View File

@ -0,0 +1,14 @@
@addTagHelper "something, nice"
<input unbound="prefix @DateTime.Now" />
<input unbound="@if (true) { @string.Empty } else { @false } suffix" />
<input bound="prefix @DateTime.Now suffix" unbound="prefix @DateTime.Now suffix" />
<input bound="@long.MinValue @if (true) { @string.Empty } else { @false } @int.MaxValue"
unbound="@long.MinValue @if (true) { @string.Empty } else { @false } @int.MaxValue" />
<input unbound="@long.MinValue @DateTime.Now static content @int.MaxValue" />
<input unbound="@if (true) { @string.Empty } else { @false }" />