From de4cafa8cdbe357ca3c4a34b084e3cf09c0db231 Mon Sep 17 00:00:00 2001
From: Doug Bunting
Date: Wed, 14 Jan 2015 00:18:33 -0800
Subject: [PATCH] Handle complex expressions for bound non-string tag helper
attributes - #129 and support aspnet/Mvc#1253 - add new
`CSharpTagHelperAttributeValueVisitor` that writes the raw expression - add
tests of embedded `@(...)` and mix that with normal expressions - add new
resources for errors in `CSharpTagHelperAttributeValueVisitor` - write
errors using `ParserErrorSink` - update baselines to match new code
generation
nits:
- cleanup long lines in `CSharpTagHelperCodeRenderer`
- remove a few unused resources
---
.../CSharp/CSharpTagHelperCodeRenderer.cs | 123 ++++++-----
.../CSharpTagHelperAttributeValueVisitor.cs | 179 ++++++++++++++++
.../Generator/TagHelperCodeGenerator.cs | 1 +
.../Properties/RazorResources.Designer.cs | 196 ++++++------------
.../RazorResources.resx | 39 ++--
.../TagHelperAttributeValueCodeRenderer.cs | 16 +-
.../Generator/CSharpTagHelperRenderingTest.cs | 42 ++--
...TagHelperAttributeValueCodeRendererTest.cs | 5 +-
...TagHelpers.CustomAttributeCodeGenerator.cs | 4 +
.../CS/Output/BasicTagHelpers.DesignTime.cs | 4 +
.../CS/Output/BasicTagHelpers.cs | 4 +
.../CS/Output/ComplexTagHelpers.DesignTime.cs | 70 ++++++-
.../CS/Output/ComplexTagHelpers.cs | 175 +++++++++++++++-
.../CS/Output/SingleTagHelper.DesignTime.cs | 6 +-
.../CS/Output/SingleTagHelper.cs | 6 +-
.../CS/Source/ComplexTagHelpers.cshtml | 13 ++
16 files changed, 654 insertions(+), 229 deletions(-)
create mode 100644 src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTagHelperAttributeValueVisitor.cs
diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
index 0e1c3fd23d..e313abf3bb 100644
--- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
+++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
@@ -5,8 +5,8 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Microsoft.AspNet.Razor.Parser.SyntaxTree;
using Microsoft.AspNet.Razor.TagHelpers;
-using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{
@@ -230,48 +230,67 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
tagHelperVariableName,
attributeDescriptor.PropertyName);
- _writer.WriteStartAssignment(valueAccessor);
-
// If we haven't recorded this attribute value before then we need to record its value.
if (!attributeValueRecorded)
{
// We only need to create attribute values once per HTML element (not once per tag helper).
- // We're saving the value accessor so we can retrieve it later if there are more tag helpers that
- // need the value.
+ // We're saving the value accessor so we can retrieve it later if there are more tag
+ // helpers that need the value.
htmlAttributeValues.Add(attributeDescriptor.Name, valueAccessor);
if (bufferableAttribute)
{
- // If the attribute is bufferable but has a plain text value that means the value
- // is a string which needs to be surrounded in quotes.
+ _writer.WriteStartAssignment(valueAccessor);
+
if (isPlainTextValue)
{
+ // If the attribute is bufferable but has a plain text value that means the value
+ // is a string which needs to be surrounded in quotes.
RenderQuotedAttributeValue(textValue, attributeDescriptor);
}
else
{
- // The value contains more than plain text. e.g. someAttribute="Time: @DateTime.Now"
+ // The value contains more than plain text e.g.
+ // stringAttribute ="Time: @DateTime.Now"
RenderBufferedAttributeValue(attributeDescriptor);
}
+
+ _writer.WriteLine(";");
}
else
{
- // TODO: Make complex types in non-bufferable attributes work in
- // https://github.com/aspnet/Razor/issues/129
- if (!isPlainTextValue)
+ // Write out simple assignment for non-string property value. Try to keep the whole
+ // statement together and the #line pragma correct to make debugging possible.
+ using (var lineMapper = new CSharpLineMappingWriter(
+ _writer,
+ attributeValueChunk.Association.Start,
+ _context.SourceFile))
{
+ // Place the assignment LHS to align RHS with original attribute value's indentation.
+ // Unfortunately originalIndent is incorrect if original line contains tabs. Unable to
+ // use a CSharpPaddingBuilder because the Association has no Previous node; lost the
+ // original Span sequence when the parse tree was rewritten.
+ var originalIndent = attributeValueChunk.Start.CharacterIndex;
+ var generatedLength = valueAccessor.Length + " = ".Length;
+ var newIndent = originalIndent - generatedLength;
+ if (newIndent > 0)
+ {
+ _writer.Indent(newIndent);
+ }
+
+ _writer.WriteStartAssignment(valueAccessor);
+ lineMapper.MarkLineMappingStart();
+
+ // Write out bare expression for this attribute value. Property is not a string.
+ // So quoting or buffering are not helpful.
+ RenderRawAttributeValue(attributeValueChunk, attributeDescriptor, isPlainTextValue);
+
+ // End the assignment to the attribute.
+ lineMapper.MarkLineMappingEnd();
_writer.WriteLine(";");
- return;
}
-
- // We aren't a bufferable attribute which means we have no Razor code in our value.
- // Therefore we can just use the "textValue" as the attribute value.
- RenderRawAttributeValue(textValue, attributeValueChunk.Start, attributeDescriptor);
}
- // End the assignment to the attribute.
- _writer.WriteLine(";");
-
// Execution contexts are a runtime feature.
if (_designTimeMode)
{
@@ -279,20 +298,23 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
// We need to inform the context of the attribute value.
- _writer.WriteStartInstanceMethodInvocation(
- ExecutionContextVariableName,
- _tagHelperContext.ExecutionContextAddTagHelperAttributeMethodName);
-
- _writer.WriteStringLiteral(attributeDescriptor.Name)
- .WriteParameterSeparator()
- .Write(valueAccessor)
- .WriteEndMethodInvocation();
+ _writer
+ .WriteStartInstanceMethodInvocation(
+ ExecutionContextVariableName,
+ _tagHelperContext.ExecutionContextAddTagHelperAttributeMethodName)
+ .WriteStringLiteral(attributeDescriptor.Name)
+ .WriteParameterSeparator()
+ .Write(valueAccessor)
+ .WriteEndMethodInvocation();
}
else
{
- // The attribute value has already been recorded, lets retrieve it from the stored value accessors.
- _writer.Write(htmlAttributeValues[attributeDescriptor.Name])
- .WriteLine(";");
+ // The attribute value has already been recorded, lets retrieve it from the stored value
+ // accessors.
+ _writer
+ .WriteStartAssignment(valueAccessor)
+ .Write(htmlAttributeValues[attributeDescriptor.Name])
+ .WriteLine(";");
}
}
}
@@ -414,34 +436,30 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
private void RenderBufferedAttributeValue(TagHelperAttributeDescriptor attributeDescriptor)
{
+ // Pass complexValue: false because variable.ToString() replaces any original complexity in the expression.
RenderAttributeValue(
attributeDescriptor,
valueRenderer: (writer) =>
{
RenderBufferedAttributeValueAccessor(writer);
- });
+ },
+ complexValue: false);
}
- private void RenderRawAttributeValue(string value,
- SourceLocation documentLocation,
- TagHelperAttributeDescriptor attributeDescriptor)
+ private void RenderRawAttributeValue(
+ Chunk attributeValueChunk,
+ TagHelperAttributeDescriptor attributeDescriptor,
+ bool isPlainTextValue)
{
RenderAttributeValue(
attributeDescriptor,
valueRenderer: (writer) =>
{
- if (_context.Host.DesignTimeMode)
- {
- using (new CSharpLineMappingWriter(writer, documentLocation, value.Length))
- {
- writer.Write(value);
- }
- }
- else
- {
- writer.Write(value);
- }
- });
+ var visitor =
+ new CSharpTagHelperAttributeValueVisitor(writer, _context, attributeDescriptor.TypeName);
+ visitor.Accept(attributeValueChunk);
+ },
+ complexValue: !isPlainTextValue);
}
private void RenderQuotedAttributeValue(string value, TagHelperAttributeDescriptor attributeDescriptor)
@@ -451,7 +469,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
valueRenderer: (writer) =>
{
writer.WriteStringLiteral(value);
- });
+ },
+ complexValue: false);
}
private void BuildBufferedWritingScope(Chunk htmlAttributeChunk)
@@ -502,9 +521,15 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
}
private void RenderAttributeValue(TagHelperAttributeDescriptor attributeDescriptor,
- Action valueRenderer)
+ Action valueRenderer,
+ bool complexValue)
{
- AttributeValueCodeRenderer.RenderAttributeValue(attributeDescriptor, _writer, _context, valueRenderer);
+ AttributeValueCodeRenderer.RenderAttributeValue(
+ attributeDescriptor,
+ _writer,
+ _context,
+ valueRenderer,
+ complexValue);
}
private void RenderBufferedAttributeValueAccessor(CSharpCodeWriter writer)
diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTagHelperAttributeValueVisitor.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTagHelperAttributeValueVisitor.cs
new file mode 100644
index 0000000000..ec6172aa8f
--- /dev/null
+++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/Visitors/CSharpTagHelperAttributeValueVisitor.cs
@@ -0,0 +1,179 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNet.Razor.Parser;
+using Microsoft.AspNet.Razor.Parser.SyntaxTree;
+
+namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
+{
+ ///
+ /// that writes code for a non- tag helper
+ /// bound attribute value.
+ ///
+ ///
+ /// Since attribute value is not written out as HTML, does not emit instrumentation. Further this
+ /// writes identical code at design- and runtime.
+ ///
+ public class CSharpTagHelperAttributeValueVisitor : CodeVisitor
+ {
+ private string _attributeTypeName;
+ private bool _firstChild;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The used to write code.
+ ///
+ /// A instance that contains information about the current code generation
+ /// process.
+ ///
+ ///
+ /// Full name of the property for which this
+ /// is writing the value.
+ ///
+ public CSharpTagHelperAttributeValueVisitor(
+ CSharpCodeWriter writer,
+ CodeBuilderContext context,
+ string attributeTypeName)
+ : base(writer, context)
+ {
+ _attributeTypeName = attributeTypeName;
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Tracks code mappings for all children while writing.
+ ///
+ protected override void Visit(ChunkBlock chunk)
+ {
+ // Line mappings are captured in RenderCode(), not this method.
+ _firstChild = true;
+ Accept(chunk.Children);
+
+ if (_firstChild)
+ {
+ // Attribute value was empty.
+ Context.ErrorSink.OnError(
+ chunk.Association.Start,
+ RazorResources.TagHelpers_AttributeExpressionRequired,
+ chunk.Association.Length);
+ }
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ protected override void Visit(ExpressionBlockChunk chunk)
+ {
+ Accept(chunk.Children);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ protected override void Visit(ExpressionChunk chunk)
+ {
+ RenderCode(chunk.Code, (Span)chunk.Association);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ protected override void Visit(LiteralChunk chunk)
+ {
+ RenderCode(chunk.Text, (Span)chunk.Association);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Allowed to support future C# extensions. Likely "~/..." will lead to a C# compilation error but that is up
+ /// to the compiler.
+ ///
+ protected override void Visit(ResolveUrlChunk chunk)
+ {
+ RenderCode(chunk.Url, (Span)chunk.Association);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Unconditionally adds a to inform user of unexpected @section directive.
+ ///
+ protected override void Visit(SectionChunk chunk)
+ {
+ Context.ErrorSink.OnError(
+ chunk.Association.Start,
+ RazorResources.FormatTagHelpers_Directives_NotSupported_InAttributes(
+ SyntaxConstants.CSharp.SectionKeyword),
+ chunk.Association.Length);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Unconditionally adds a to inform user of unexpected @layout directive.
+ ///
+ protected override void Visit(SetLayoutChunk chunk)
+ {
+ Context.ErrorSink.OnError(
+ chunk.Association.Start,
+ RazorResources.FormatTagHelpers_Directives_NotSupported_InAttributes(
+ SyntaxConstants.CSharp.LayoutKeyword),
+ chunk.Association.Length);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Unconditionally adds a to inform user of unexpected code block.
+ ///
+ protected override void Visit(StatementChunk chunk)
+ {
+ Context.ErrorSink.OnError(
+ chunk.Association.Start,
+ RazorResources.TagHelpers_CodeBlocks_NotSupported_InAttributes,
+ chunk.Association.Length);
+ }
+
+ ///
+ /// Writes code for the given .
+ ///
+ /// The to render.
+ ///
+ /// Unconditionally adds a to inform user of unexpected template e.g.
+ /// @<p>paragraph@</p>.
+ ///
+ protected override void Visit(TemplateChunk chunk)
+ {
+ Context.ErrorSink.OnError(
+ chunk.Association.Start,
+ RazorResources.FormatTagHelpers_InlineMarkupBlocks_NotSupported_InAttributes(_attributeTypeName),
+ chunk.Association.Length);
+ }
+
+ // Tracks the code mapping and writes code for a leaf node in the attribute value Chunk tree.
+ private void RenderCode(string code, Span association)
+ {
+ _firstChild = false;
+ using (new CSharpLineMappingWriter(Writer, association.Start, code.Length))
+ {
+ Writer.Write(code);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs b/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs
index 2a1fcf7593..d09b718051 100644
--- a/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs
+++ b/src/Microsoft.AspNet.Razor/Generator/TagHelperCodeGenerator.cs
@@ -66,6 +66,7 @@ namespace Microsoft.AspNet.Razor.Generator
attributes[attribute.Key] = new ChunkBlock
{
+ Association = first?.Association,
Children = chunks,
Start = first == null ? SourceLocation.Zero : first.Start
};
diff --git a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
index fe382a5223..a238ee5343 100644
--- a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
@@ -390,38 +390,6 @@ namespace Microsoft.AspNet.Razor
return GetString("ParseError_Unterminated_String_Literal");
}
- ///
- /// Unknown option: "{0}".
- ///
- internal static string ParseError_UnknownOption
- {
- get { return GetString("ParseError_UnknownOption"); }
- }
-
- ///
- /// Unknown option: "{0}".
- ///
- internal static string FormatParseError_UnknownOption(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_UnknownOption"), p0);
- }
-
- ///
- /// The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".
- ///
- internal static string ParseError_BlockNotTerminated
- {
- get { return GetString("ParseError_BlockNotTerminated"); }
- }
-
- ///
- /// The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".
- ///
- internal static string FormatParseError_BlockNotTerminated(object p0, object p1)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_BlockNotTerminated"), p0, p1);
- }
-
///
/// @section Header { ... }
///
@@ -454,22 +422,6 @@ namespace Microsoft.AspNet.Razor
return GetString("ParseError_TextTagCannotContainAttributes");
}
- ///
- /// The "Imports" keyword must be followed by a namespace or a type alias on the same line.
- ///
- internal static string ParseError_NamespaceOrTypeAliasExpected
- {
- get { return GetString("ParseError_NamespaceOrTypeAliasExpected"); }
- }
-
- ///
- /// The "Imports" keyword must be followed by a namespace or a type alias on the same line.
- ///
- internal static string FormatParseError_NamespaceOrTypeAliasExpected()
- {
- return GetString("ParseError_NamespaceOrTypeAliasExpected");
- }
-
///
/// A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.
///
@@ -998,22 +950,6 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("TokenizerView_CannotPutBack"), p0, p1);
}
- ///
- /// Unexpected "{0}"
- ///
- internal static string ParseError_Unexpected
- {
- get { return GetString("ParseError_Unexpected"); }
- }
-
- ///
- /// Unexpected "{0}"
- ///
- internal static string FormatParseError_Unexpected(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("ParseError_Unexpected"), p0);
- }
-
///
/// Unexpected "{" after "@" character. Once inside the body of a code block (@if {}, @{}, etc.) you do not need to use "@{" to switch to code.
///
@@ -1142,38 +1078,6 @@ namespace Microsoft.AspNet.Razor
return GetString("Language_Does_Not_Support_RazorComment");
}
- ///
- /// Missing value for session state directive.
- ///
- internal static string ParserEror_SessionDirectiveMissingValue
- {
- get { return GetString("ParserEror_SessionDirectiveMissingValue"); }
- }
-
- ///
- /// Missing value for session state directive.
- ///
- internal static string FormatParserEror_SessionDirectiveMissingValue()
- {
- return GetString("ParserEror_SessionDirectiveMissingValue");
- }
-
- ///
- /// Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method
- ///
- internal static string CreateCodeWriter_NoCodeWriter
- {
- get { return GetString("CreateCodeWriter_NoCodeWriter"); }
- }
-
- ///
- /// Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method
- ///
- internal static string FormatCreateCodeWriter_NoCodeWriter()
- {
- return GetString("CreateCodeWriter_NoCodeWriter");
- }
-
///
/// [BG][{0}] Shutdown
///
@@ -1478,22 +1382,6 @@ namespace Microsoft.AspNet.Razor
return GetString("TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock");
}
- ///
- /// TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.
- ///
- internal static string TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols
- {
- get { return GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"); }
- }
-
- ///
- /// TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.
- ///
- internal static string FormatTagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols"), p0);
- }
-
///
/// Directive '{0}' must have a value.
///
@@ -1542,22 +1430,6 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpersParseTreeRewriter_FoundMalformedTagHelper"), p0);
}
- ///
- /// Missing '{0}' from '{1}' tag helper.
- ///
- internal static string TagHelpersParseTreeRewriter_MissingValueFromTagHelper
- {
- get { return GetString("TagHelpersParseTreeRewriter_MissingValueFromTagHelper"); }
- }
-
- ///
- /// Missing '{0}' from '{1}' tag helper.
- ///
- internal static string FormatTagHelpersParseTreeRewriter_MissingValueFromTagHelper(object p0, object p1)
- {
- return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpersParseTreeRewriter_MissingValueFromTagHelper"), p0, p1);
- }
-
///
/// Missing close angle for tag helper '{0}'.
///
@@ -1590,6 +1462,74 @@ namespace Microsoft.AspNet.Razor
return GetString("TagHelperBlockRewriter_TagHelperAttributesMustBeWelformed");
}
+ ///
+ /// Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.
+ ///
+ internal static string TagHelpers_AttributeExpressionRequired
+ {
+ get { return GetString("TagHelpers_AttributeExpressionRequired"); }
+ }
+
+ ///
+ /// Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.
+ ///
+ internal static string FormatTagHelpers_AttributeExpressionRequired()
+ {
+ return GetString("TagHelpers_AttributeExpressionRequired");
+ }
+
+ ///
+ /// Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
+ /// Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.
+ ///
+ internal static string TagHelpers_CodeBlocks_NotSupported_InAttributes
+ {
+ get { return GetString("TagHelpers_CodeBlocks_NotSupported_InAttributes"); }
+ }
+
+ ///
+ /// Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
+ /// Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.
+ ///
+ internal static string FormatTagHelpers_CodeBlocks_NotSupported_InAttributes()
+ {
+ return GetString("TagHelpers_CodeBlocks_NotSupported_InAttributes");
+ }
+
+ ///
+ /// @'{0}' directives must not appear in non-string tag helper attribute values.
+ ///
+ internal static string TagHelpers_Directives_NotSupported_InAttributes
+ {
+ get { return GetString("TagHelpers_Directives_NotSupported_InAttributes"); }
+ }
+
+ ///
+ /// @'{0}' directives must not appear in non-string tag helper attribute values.
+ ///
+ internal static string FormatTagHelpers_Directives_NotSupported_InAttributes(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_Directives_NotSupported_InAttributes"), p0);
+ }
+
+ ///
+ /// Inline markup blocks (e.g. @<p>content</p>) must not appear in non-string tag helper attribute values.
+ /// Expected a '{0}' attribute value, not a string.
+ ///
+ internal static string TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes
+ {
+ get { return GetString("TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes"); }
+ }
+
+ ///
+ /// Inline markup blocks (e.g. @<p>content</p>) must not appear in non-string tag helper attribute values.
+ /// Expected a '{0}' attribute value, not a string.
+ ///
+ internal static string FormatTagHelpers_InlineMarkupBlocks_NotSupported_InAttributes(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_InlineMarkupBlocks_NotSupported_InAttributes"), p0);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNet.Razor/RazorResources.resx b/src/Microsoft.AspNet.Razor/RazorResources.resx
index 3f62c0eb90..748e14ef5d 100644
--- a/src/Microsoft.AspNet.Razor/RazorResources.resx
+++ b/src/Microsoft.AspNet.Razor/RazorResources.resx
@@ -206,12 +206,6 @@ Instead, wrap the contents of the block in "{{}}":
Unterminated string literal. Strings that start with a quotation mark (") must be terminated before the end of the line. However, strings that start with @ and a quotation mark (@") can span multiple lines.
-
- Unknown option: "{0}".
-
-
- The "{0}" block was not terminated. All "{0}" statements must be terminated with a matching "{1}".
-
@section Header { ... }
In CSHTML, the @section keyword is case-sensitive and lowercase (as with all C# keywords)
@@ -219,9 +213,6 @@ Instead, wrap the contents of the block in "{{}}":
"<text>" and "</text>" tags cannot contain attributes.
-
- The "Imports" keyword must be followed by a namespace or a type alias on the same line.
-
A space or line break was encountered after the "@" character. Only valid identifiers, keywords, comments, "(" and "{" are valid at the start of a code block and they must occur immediately following "@" with no space in between.
@@ -321,9 +312,6 @@ Instead, wrap the contents of the block in "{{}}":
In order to put a symbol back, it must have been the symbol which ended at the current position. The specified symbol ends at {0}, but the current position is {1}
-
- Unexpected "{0}"
-
Unexpected "{" after "@" character. Once inside the body of a code block (@if {}, @{}, etc.) you do not need to use "@{" to switch to code.
@@ -348,13 +336,6 @@ Instead, wrap the contents of the block in "{{}}":
Cannot use built-in RazorComment handler, language characteristics does not define the CommentStart, CommentStar and CommentBody known symbol types or parser does not override TokenizerBackedParser.OutputSpanBeforeRazorComment
-
- Missing value for session state directive.
-
-
- Cannot call CreateCodeWriter, a CodeWriter was not provided to the Create method
- This error should not be seen by users, it should only appear to internal developers, but I'm putting it in resources just in case
-
[BG][{0}] Shutdown
@@ -412,9 +393,6 @@ Instead, wrap the contents of the block in "{{}}":
A TagHelperCodeGenerator must only be used with TagHelperBlocks.
-
- TagHelper attributes that do not expect strings must not have @ symbols within them. Found attribute '{0}' with an invalid value.
-
Directive '{0}' must have a value.
@@ -424,13 +402,24 @@ Instead, wrap the contents of the block in "{{}}":
Found a malformed '{0}' tag helper. Tag helpers must have a start and end tag or be self closing.
-
- Missing '{0}' from '{1}' tag helper.
-
Missing close angle for tag helper '{0}'.
TagHelper attributes must be welformed.
+
+ Non-string tag helper attribute values must not be empty. Add an expression to this attribute value.
+
+
+ Code blocks (e.g. @{{var variable = 23;}}) must not appear in non-string tag helper attribute values.
+ Already in an expression (code) context. If necessary an explicit expression (e.g. @(@readonly)) may be used.
+
+
+ @'{0}' directives must not appear in non-string tag helper attribute values.
+
+
+ Inline markup blocks (e.g. @<p>content</p>) must not appear in non-string tag helper attribute values.
+ Expected a '{0}' attribute value, not a string.
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeValueCodeRenderer.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeValueCodeRenderer.cs
index 25e7f69f46..332583ce3a 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeValueCodeRenderer.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeValueCodeRenderer.cs
@@ -16,15 +16,25 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// Called during Razor's code generation process to generate code that instantiates the value of the tag
/// helper's property. Last value written should not be or end with a semicolon.
///
- /// The to generate code for.
+ ///
+ /// The to generate code for.
+ ///
/// The that's used to write code.
/// A instance that contains information about
/// the current code generation process.
- /// that renders the raw value of the HTML attribute.
+ ///
+ /// that renders the raw value of the HTML attribute.
+ ///
+ ///
+ /// Indicates whether or not the source attribute value contains more than simple text. false for plain
+ /// C# expressions e.g. "PropertyName". true if the attribute value contain at least one in-line
+ /// Razor construct e.g. "@(@readonly)".
+ ///
public virtual void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeDescriptor,
[NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context,
- [NotNull] Action renderAttributeValue)
+ [NotNull] Action renderAttributeValue,
+ bool complexValue)
{
renderAttributeValue(writer);
}
diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingTest.cs b/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingTest.cs
index 46c1d63f32..566a458e62 100644
--- a/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingTest.cs
+++ b/test/Microsoft.AspNet.Razor.Test/Generator/CSharpTagHelperRenderingTest.cs
@@ -177,10 +177,9 @@ namespace Microsoft.AspNet.Razor.Test.Generator
contentLength: 11),
BuildLineMapping(documentAbsoluteIndex: 57,
documentLineIndex: 2,
- documentCharacterOffsetIndex: 28,
- generatedAbsoluteIndex: 927,
- generatedLineIndex: 33,
- generatedCharacterOffsetIndex: 31,
+ generatedAbsoluteIndex: 958,
+ generatedLineIndex: 34,
+ characterOffsetIndex: 28,
contentLength: 4)
}
},
@@ -198,10 +197,9 @@ namespace Microsoft.AspNet.Razor.Test.Generator
contentLength: 11),
BuildLineMapping(documentAbsoluteIndex: 189,
documentLineIndex: 6,
- documentCharacterOffsetIndex: 40,
- generatedAbsoluteIndex: 1599,
- generatedLineIndex: 44,
- generatedCharacterOffsetIndex: 40,
+ generatedAbsoluteIndex: 1633,
+ generatedLineIndex: 45,
+ characterOffsetIndex: 40,
contentLength: 4)
}
},
@@ -232,13 +230,27 @@ namespace Microsoft.AspNet.Razor.Test.Generator
BuildLineMapping(218, 9, 13, 1356, 56, 12, 27),
BuildLineMapping(346, 12, 1754, 68, 0, 48),
BuildLineMapping(440, 15, 46, 2004, 78, 6, 8),
- BuildLineMapping(457, 15, 63, 2267, 85, 40, 4),
- BuildLineMapping(501, 16, 31, 2384, 88, 6, 30),
- BuildLineMapping(568, 17, 30, 2733, 97, 0, 10),
- BuildLineMapping(601, 17, 63, 2815, 103, 0, 8),
- BuildLineMapping(632, 17, 94, 2895, 109, 0, 1),
- BuildLineMapping(639, 18, 3149, 118, 0, 15),
- BuildLineMapping(680, 21, 3234, 124, 0, 1)
+ BuildLineMapping(457, 15, 2327, 86, 63, 4),
+ BuildLineMapping(501, 16, 31, 2475, 92, 6, 30),
+ BuildLineMapping(568, 17, 30, 2824, 101, 0, 10),
+ BuildLineMapping(601, 17, 63, 2906, 107, 0, 8),
+ BuildLineMapping(632, 17, 94, 2986, 113, 0, 1),
+ BuildLineMapping(639, 18, 3240, 122, 0, 15),
+ BuildLineMapping(685, 20, 17, 3403, 129, 19, 23),
+ BuildLineMapping(708, 20, 40, 3426, 129, 42, 7),
+ BuildLineMapping(719, 21, 3504, 134, 0, 12),
+ BuildLineMapping(733, 21, 3602, 140, 14, 21),
+ BuildLineMapping(787, 22, 30, 3859, 148, 28, 7),
+ BuildLineMapping(831, 24, 16, 4015, 154, 19, 8),
+ BuildLineMapping(840, 24, 25, 4023, 154, 27, 23),
+ BuildLineMapping(897, 25, 30, 4281, 161, 28, 30),
+ BuildLineMapping(964, 27, 16, 4460, 167, 19, 30),
+ BuildLineMapping(1026, 28, 4725, 174, 28, 30),
+ BuildLineMapping(1094, 30, 18, 4904, 180, 19, 29),
+ BuildLineMapping(1156, 31, 5168, 187, 28, 3),
+ BuildLineMapping(1161, 31, 33, 5171, 187, 31, 27),
+ BuildLineMapping(1189, 31, 61, 5198, 187, 58, 10),
+ BuildLineMapping(1231, 34, 5279, 192, 0, 1),
}
}
};
diff --git a/test/Microsoft.AspNet.Razor.Test/Generator/TagHelperAttributeValueCodeRendererTest.cs b/test/Microsoft.AspNet.Razor.Test/Generator/TagHelperAttributeValueCodeRendererTest.cs
index d94f405033..01f795831d 100644
--- a/test/Microsoft.AspNet.Razor.Test/Generator/TagHelperAttributeValueCodeRendererTest.cs
+++ b/test/Microsoft.AspNet.Razor.Test/Generator/TagHelperAttributeValueCodeRendererTest.cs
@@ -88,11 +88,12 @@ namespace Microsoft.AspNet.Razor.Test.Generator
public override void RenderAttributeValue([NotNull] TagHelperAttributeDescriptor attributeInfo,
[NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context,
- [NotNull] Action renderAttributeValue)
+ [NotNull] Action renderAttributeValue,
+ bool complexValue)
{
writer.Write("**From custom attribute code renderer**: ");
- base.RenderAttributeValue(attributeInfo, writer, context, renderAttributeValue);
+ base.RenderAttributeValue(attributeInfo, writer, context, renderAttributeValue, complexValue);
}
}
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs
index 9480b4d550..006b0e3410 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.CustomAttributeCodeGenerator.cs
@@ -69,7 +69,11 @@ namespace TestOutput
__InputTagHelper2 = CreateTagHelper();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
+#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = **From custom attribute code renderer**: true;
+
+#line default
+#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.DesignTime.cs
index 2e64d06da7..9f057ded04 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.DesignTime.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.DesignTime.cs
@@ -42,7 +42,11 @@ namespace TestOutput
__InputTagHelper.Type = "checkbox";
__InputTagHelper2 = CreateTagHelper();
__InputTagHelper2.Type = __InputTagHelper.Type;
+#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
+
+#line default
+#line hidden
}
#pragma warning restore 1998
}
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs
index 23c8d1cc14..5acb09e775 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/BasicTagHelpers.cs
@@ -70,7 +70,11 @@ namespace TestOutput
__InputTagHelper2 = CreateTagHelper();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
+#line 7 "BasicTagHelpers.cshtml"
__InputTagHelper2.Checked = true;
+
+#line default
+#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.DesignTime.cs
index 28c9ac70b7..2dc8547ca5 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.DesignTime.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.DesignTime.cs
@@ -83,7 +83,11 @@ __o = checkbox;
__InputTagHelper.Type = string.Empty;
__InputTagHelper2 = CreateTagHelper();
__InputTagHelper2.Type = __InputTagHelper.Type;
- __InputTagHelper2.Checked = true;
+#line 16 "ComplexTagHelpers.cshtml"
+ __InputTagHelper2.Checked = true;
+
+#line default
+#line hidden
__InputTagHelper = CreateTagHelper();
#line 17 "ComplexTagHelpers.cshtml"
__o = true ? "checkbox" : "anything";
@@ -121,7 +125,71 @@ if(true) {
#line default
#line hidden
+ __PTagHelper = CreateTagHelper();
+#line 21 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
+
+#line default
+#line hidden
#line 22 "ComplexTagHelpers.cshtml"
+
+
+#line default
+#line hidden
+
+#line 22 "ComplexTagHelpers.cshtml"
+ var @object = false;
+
+#line default
+#line hidden
+
+ __InputTagHelper = CreateTagHelper();
+ __InputTagHelper2 = CreateTagHelper();
+#line 23 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = @object;
+
+#line default
+#line hidden
+ __PTagHelper = CreateTagHelper();
+#line 25 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year;
+
+#line default
+#line hidden
+ __InputTagHelper = CreateTagHelper();
+ __InputTagHelper2 = CreateTagHelper();
+#line 26 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
+
+#line default
+#line hidden
+ __PTagHelper = CreateTagHelper();
+#line 28 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
+
+#line default
+#line hidden
+ __InputTagHelper = CreateTagHelper();
+ __InputTagHelper2 = CreateTagHelper();
+#line 29 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
+
+#line default
+#line hidden
+ __PTagHelper = CreateTagHelper();
+#line 31 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = "My age is this long.".Length;
+
+#line default
+#line hidden
+ __InputTagHelper = CreateTagHelper();
+ __InputTagHelper2 = CreateTagHelper();
+#line 32 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ;
+
+#line default
+#line hidden
+#line 35 "ComplexTagHelpers.cshtml"
}
#line default
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs
index 3b4087d2f4..799b71571c 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/ComplexTagHelpers.cs
@@ -1,4 +1,4 @@
-#pragma checksum "ComplexTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "cce31144cd1c3c35d241b49e41c4fc04ff044565"
+#pragma checksum "ComplexTagHelpers.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "7158abc69d261099393d49d82670ec64a94d9770"
namespace TestOutput
{
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@@ -134,7 +134,11 @@ Write(checkbox);
__InputTagHelper2 = CreateTagHelper();
__tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type;
- __InputTagHelper2.Checked = true;
+#line 16 "ComplexTagHelpers.cshtml"
+ __InputTagHelper2.Checked = true;
+
+#line default
+#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
@@ -215,10 +219,173 @@ if(true) {
Instrumentation.EndContext();
WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
__tagHelperExecutionContext = __tagHelperScopeManager.End();
- Instrumentation.BeginContext(666, 14, true);
- WriteLiteral("\r\n \r\n");
+ Instrumentation.BeginContext(666, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test");
+ __PTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__PTagHelper);
+#line 21 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ Instrumentation.BeginContext(717, 2, true);
+ WriteLiteral("\r\n");
Instrumentation.EndContext();
#line 22 "ComplexTagHelpers.cshtml"
+
+
+#line default
+#line hidden
+
+#line 22 "ComplexTagHelpers.cshtml"
+ var @object = false;
+
+#line default
+#line hidden
+
+ Instrumentation.BeginContext(755, 14, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test");
+ __InputTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper);
+ __InputTagHelper2 = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper2);
+#line 23 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = @object;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(799, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(813, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test");
+ __PTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__PTagHelper);
+#line 25 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = -1970 + DateTimeOffset.Now.Year;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ Instrumentation.BeginContext(865, 14, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test");
+ __InputTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper);
+ __InputTagHelper2 = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper2);
+#line 26 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(932, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(946, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test");
+ __PTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__PTagHelper);
+#line 28 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = DateTimeOffset.Now.Year - 1970;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ Instrumentation.BeginContext(996, 14, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test");
+ __InputTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper);
+ __InputTagHelper2 = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper2);
+#line 29 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(1060, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(1074, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test");
+ __PTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__PTagHelper);
+#line 31 "ComplexTagHelpers.cshtml"
+__PTagHelper.Age = "My age is this long.".Length;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ Instrumentation.BeginContext(1126, 14, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ __tagHelperExecutionContext = __tagHelperScopeManager.Begin("input", "test");
+ __InputTagHelper = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper);
+ __InputTagHelper2 = CreateTagHelper();
+ __tagHelperExecutionContext.Add(__InputTagHelper2);
+#line 32 "ComplexTagHelpers.cshtml"
+__InputTagHelper2.Checked = DateTimeOffset.Now.Year > 2014 ;
+
+#line default
+#line hidden
+ __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
+ __tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateStartTag());
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(1203, 10, true);
+ WriteLiteral("\r\n ");
+ Instrumentation.EndContext();
+ WriteLiteral(__tagHelperExecutionContext.Output.GenerateEndTag());
+ __tagHelperExecutionContext = __tagHelperScopeManager.End();
+ Instrumentation.BeginContext(1217, 14, true);
+ WriteLiteral("\r\n \r\n");
+ Instrumentation.EndContext();
+#line 35 "ComplexTagHelpers.cshtml"
}
#line default
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.DesignTime.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.DesignTime.cs
index 16fb5c4ed4..b2797a754d 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.DesignTime.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.DesignTime.cs
@@ -31,7 +31,11 @@ namespace TestOutput
public override async Task ExecuteAsync()
{
__PTagHelper = CreateTagHelper();
- __PTagHelper.Age = 1337;
+#line 3 "SingleTagHelper.cshtml"
+ __PTagHelper.Age = 1337;
+
+#line default
+#line hidden
}
#pragma warning restore 1998
}
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs
index bf355d24bb..cb4fa34851 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Output/SingleTagHelper.cs
@@ -29,7 +29,11 @@ namespace TestOutput
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("p", "test");
__PTagHelper = CreateTagHelper();
__tagHelperExecutionContext.Add(__PTagHelper);
- __PTagHelper.Age = 1337;
+#line 3 "SingleTagHelper.cshtml"
+ __PTagHelper.Age = 1337;
+
+#line default
+#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World");
__tagHelperExecutionContext.Output = __tagHelperRunner.RunAsync(__tagHelperExecutionContext).Result;
diff --git a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Source/ComplexTagHelpers.cshtml b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Source/ComplexTagHelpers.cshtml
index 7ba3c6db48..2053f692d1 100644
--- a/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Source/ComplexTagHelpers.cshtml
+++ b/test/Microsoft.AspNet.Razor.Test/TestFiles/CodeGenerator/CS/Source/ComplexTagHelpers.cshtml
@@ -18,5 +18,18 @@
}
+
+ @{ var @object = false;}
+
+
+
+
+
+
+
+
+
+
+
}
\ No newline at end of file