Enforce new invariants around HTML encoding

- #335
- bound `string` attribute values are _not_ encoded
 - rework `CSharpCodeVisitor` and `CSharpTagHelperCodeRenderer` to enable this case
- values in `TagHelperOutput.Attributes` are encoded unless special-cased elsewhere
 - `Dictionary<string, object>` type allows `RazorPage` to use `HtmlString`
- wrap HTML unbound attribute values using `Html.Raw()`
This commit is contained in:
Doug Bunting 2015-03-26 18:53:10 -07:00
parent 80566401f8
commit 33407ef1be
16 changed files with 147 additions and 66 deletions

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
SelfClosing = selfClosing; SelfClosing = selfClosing;
AllAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); AllAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
HTMLAttributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); HTMLAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
TagName = tagName; TagName = tagName;
Items = items; Items = items;
UniqueId = uniqueId; UniqueId = uniqueId;
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary> /// <summary>
/// HTML attributes. /// HTML attributes.
/// </summary> /// </summary>
public IDictionary<string, string> HTMLAttributes { get; } public IDictionary<string, object> HTMLAttributes { get; }
/// <summary> /// <summary>
/// <see cref="ITagHelper"/> bound attributes and HTML attributes. /// <see cref="ITagHelper"/> bound attributes and HTML attributes.
@ -138,7 +138,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary> /// </summary>
/// <param name="name">The HTML attribute name.</param> /// <param name="name">The HTML attribute name.</param>
/// <param name="value">The HTML attribute value.</param> /// <param name="value">The HTML attribute value.</param>
public void AddHtmlAttribute([NotNull] string name, string value) public void AddHtmlAttribute([NotNull] string name, object value)
{ {
HTMLAttributes.Add(name, value); HTMLAttributes.Add(name, value);
AllAttributes.Add(name, value); AllAttributes.Add(name, value);

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Internal for testing // Internal for testing
internal TagHelperOutput(string tagName) internal TagHelperOutput(string tagName)
: this(tagName, new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)) : this(tagName, new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase))
{ {
} }
@ -31,10 +31,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <param name="attributes">The HTML attributes.</param> /// <param name="attributes">The HTML attributes.</param>
public TagHelperOutput( public TagHelperOutput(
string tagName, string tagName,
[NotNull] IDictionary<string, string> attributes) [NotNull] IDictionary<string, object> attributes)
{ {
TagName = tagName; TagName = tagName;
Attributes = new Dictionary<string, string>(attributes, StringComparer.OrdinalIgnoreCase); Attributes = new Dictionary<string, object>(attributes, StringComparer.OrdinalIgnoreCase);
_preContent = new DefaultTagHelperContent(); _preContent = new DefaultTagHelperContent();
_content = new DefaultTagHelperContent(); _content = new DefaultTagHelperContent();
_postContent = new DefaultTagHelperContent(); _postContent = new DefaultTagHelperContent();
@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary> /// <summary>
/// The HTML element's main content. /// The HTML element's main content.
/// </summary> /// </summary>
/// <remarks>Value occurs in the <see cref="ITagHelper"/>'s final output after <see cref="PreContent"/> and /// <remarks>Value occurs in the <see cref="ITagHelper"/>'s final output after <see cref="PreContent"/> and
/// before <see cref="PostContent"/></remarks> /// before <see cref="PostContent"/></remarks>
public TagHelperContent Content public TagHelperContent Content
{ {
@ -104,7 +104,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// <summary> /// <summary>
/// The HTML element's attributes. /// The HTML element's attributes.
/// </summary> /// </summary>
public IDictionary<string, string> Attributes { get; } /// <remarks>
/// MVC will HTML encode <see cref="string"/> values when generating the start tag. It will not HTML encode
/// a <c>Microsoft.AspNet.Mvc.Rendering.HtmlString</c> instance. MVC converts most other types to a
/// <see cref="string"/>, then HTML encodes the result.
/// </remarks>
public IDictionary<string, object> Attributes { get; }
/// <summary> /// <summary>
/// Changes <see cref="TagHelperOutput"/> to generate nothing. /// Changes <see cref="TagHelperOutput"/> to generate nothing.

View File

@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
private readonly CSharpCodeWriter _writer; private readonly CSharpCodeWriter _writer;
private readonly CodeBuilderContext _context; private readonly CodeBuilderContext _context;
private readonly IChunkVisitor _bodyVisitor; private readonly IChunkVisitor _bodyVisitor;
private readonly IChunkVisitor _literalBodyVisitor;
private readonly GeneratedTagHelperContext _tagHelperContext; private readonly GeneratedTagHelperContext _tagHelperContext;
private readonly bool _designTimeMode; private readonly bool _designTimeMode;
@ -35,15 +36,18 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
/// <param name="writer">The <see cref="CSharpCodeWriter"/> used to write code.</param> /// <param name="writer">The <see cref="CSharpCodeWriter"/> used to write code.</param>
/// <param name="context">A <see cref="CodeBuilderContext"/> instance that contains information about /// <param name="context">A <see cref="CodeBuilderContext"/> instance that contains information about
/// the current code generation process.</param> /// the current code generation process.</param>
public CSharpTagHelperCodeRenderer([NotNull] IChunkVisitor bodyVisitor, public CSharpTagHelperCodeRenderer(
[NotNull] CSharpCodeWriter writer, [NotNull] IChunkVisitor bodyVisitor,
[NotNull] CodeBuilderContext context) [NotNull] CSharpCodeWriter writer,
[NotNull] CodeBuilderContext context)
{ {
_bodyVisitor = bodyVisitor; _bodyVisitor = bodyVisitor;
_writer = writer; _writer = writer;
_context = context; _context = context;
_tagHelperContext = context.Host.GeneratedClassContext.GeneratedTagHelperContext; _tagHelperContext = context.Host.GeneratedClassContext.GeneratedTagHelperContext;
_designTimeMode = context.Host.DesignTimeMode; _designTimeMode = context.Host.DesignTimeMode;
_literalBodyVisitor = new CSharpLiteralCodeVisitor(this, writer, context);
AttributeValueCodeRenderer = new TagHelperAttributeValueCodeRenderer(); AttributeValueCodeRenderer = new TagHelperAttributeValueCodeRenderer();
} }
@ -55,7 +59,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
/// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param> /// <param name="chunk">A <see cref="TagHelperChunk"/> to render.</param>
public void RenderTagHelper(TagHelperChunk chunk) public void RenderTagHelper(TagHelperChunk chunk)
{ {
// Remove any duplicate TagHelperDescriptors that referrence the same type name. Duplicates can occur when // Remove any duplicate TagHelperDescriptors that reference the same type name. Duplicates can occur when
// multiple TargetElement attributes are on a TagHelper type and matchs overlap for an HTML element. // multiple TargetElement attributes are on a TagHelper type and matchs overlap for an HTML element.
// Having more than one descriptor with the same TagHelper type results in generated code that runs // Having more than one descriptor with the same TagHelper type results in generated code that runs
// the same TagHelper X many times (instead of once) over a single HTML element. // the same TagHelper X many times (instead of once) over a single HTML element.
@ -214,7 +218,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
// plain text then we need to prepare the value prior to setting it below. // plain text then we need to prepare the value prior to setting it below.
if (!attributeValueRecorded && bufferableAttribute && !isPlainTextValue) if (!attributeValueRecorded && bufferableAttribute && !isPlainTextValue)
{ {
BuildBufferedWritingScope(attributeValueChunk); BuildBufferedWritingScope(attributeValueChunk, htmlEncodeValues: false);
} }
// We capture the tag helpers property value accessor so we can retrieve it later (if we need to). // We capture the tag helpers property value accessor so we can retrieve it later (if we need to).
@ -326,7 +330,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
// C# code, then we need to buffer it. // C# code, then we need to buffer it.
if (!isPlainTextValue) if (!isPlainTextValue)
{ {
BuildBufferedWritingScope(attributeValue); BuildBufferedWritingScope(attributeValue, htmlEncodeValues: true);
} }
// Execution contexts are a runtime feature, therefore no need to add anything to them. // Execution contexts are a runtime feature, therefore no need to add anything to them.
@ -335,11 +339,13 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
continue; continue;
} }
_writer.WriteStartInstanceMethodInvocation( _writer
ExecutionContextVariableName, .WriteStartInstanceMethodInvocation(
_tagHelperContext.ExecutionContextAddHtmlAttributeMethodName); ExecutionContextVariableName,
_writer.WriteStringLiteral(htmlAttribute.Key) _tagHelperContext.ExecutionContextAddHtmlAttributeMethodName)
.WriteParameterSeparator(); .WriteStringLiteral(htmlAttribute.Key)
.WriteParameterSeparator()
.WriteStartMethodInvocation(_tagHelperContext.MarkAsHtmlEncodedMethodName);
// If it's a plain text value then we need to surround the value with quotes. // If it's a plain text value then we need to surround the value with quotes.
if (isPlainTextValue) if (isPlainTextValue)
@ -351,7 +357,9 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
RenderBufferedAttributeValueAccessor(_writer); RenderBufferedAttributeValueAccessor(_writer);
} }
_writer.WriteEndMethodInvocation(); _writer
.WriteEndMethodInvocation(endLine: false)
.WriteEndMethodInvocation();
} }
} }
@ -435,13 +443,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
complexValue: false); complexValue: false);
} }
private void BuildBufferedWritingScope(Chunk htmlAttributeChunk) // Render a buffered writing scope for the HTML attribute value.
{ private void BuildBufferedWritingScope(Chunk htmlAttributeChunk, bool htmlEncodeValues)
// Render a buffered writing scope for the html attribute value.
BuildBufferedWritingScope(new[] { htmlAttributeChunk });
}
private void BuildBufferedWritingScope(IList<Chunk> chunks)
{ {
// We're building a writing scope around the provided chunks which captures everything written from the // We're building a writing scope around the provided chunks which captures everything written from the
// page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to // page. Therefore, we do not want to write to any other buffer since we're using the pages buffer to
@ -463,7 +466,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
_writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName); _writer.WriteMethodInvocation(_tagHelperContext.StartTagHelperWritingScopeMethodName);
} }
_bodyVisitor.Accept(chunks); var visitor = htmlEncodeValues ? _bodyVisitor : _literalBodyVisitor;
visitor.Accept(htmlAttributeChunk);
// Scopes are a runtime feature. // Scopes are a runtime feature.
if (!_designTimeMode) if (!_designTimeMode)
@ -541,6 +545,37 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
return true; return true;
} }
// A CSharpCodeVisitor which does not HTML encode values. Used when rendering bound string attribute values.
private class CSharpLiteralCodeVisitor : CSharpCodeVisitor
{
public CSharpLiteralCodeVisitor(
CSharpTagHelperCodeRenderer tagHelperRenderer,
CSharpCodeWriter writer,
CodeBuilderContext context)
: base(writer, context)
{
// Ensure that no matter how this class is used, we don't create numerous CSharpTagHelperCodeRenderer
// instances.
TagHelperRenderer = tagHelperRenderer;
}
protected override string WriteMethodName
{
get
{
return Context.Host.GeneratedClassContext.WriteLiteralMethodName;
}
}
protected override string WriteToMethodName
{
get
{
return Context.Host.GeneratedClassContext.WriteLiteralToMethodName;
}
}
}
// This class is used to compare tag helper attributes by comparing only the HTML attribute name. // This class is used to compare tag helper attributes by comparing only the HTML attribute name.
private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor> private class TagHelperAttributeDescriptorComparer : IEqualityComparer<TagHelperAttributeDescriptor>
{ {

View File

@ -22,13 +22,17 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
: base(writer, context) : base(writer, context)
{ {
_paddingBuilder = new CSharpPaddingBuilder(context.Host); _paddingBuilder = new CSharpPaddingBuilder(context.Host);
TagHelperRenderer = new CSharpTagHelperCodeRenderer(this, writer, context);
} }
public CSharpTagHelperCodeRenderer TagHelperRenderer public CSharpTagHelperCodeRenderer TagHelperRenderer
{ {
get get
{ {
if (_tagHelperCodeRenderer == null)
{
_tagHelperCodeRenderer = new CSharpTagHelperCodeRenderer(this, Writer, Context);
}
return _tagHelperCodeRenderer; return _tagHelperCodeRenderer;
} }
set set
@ -42,6 +46,30 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
} }
} }
/// <summary>
/// Method used to write an <see cref="object"/> to the current output.
/// </summary>
/// <remarks>Default is to HTML encode all but a few types.</remarks>
protected virtual string WriteMethodName
{
get
{
return Context.Host.GeneratedClassContext.WriteMethodName;
}
}
/// <summary>
/// Method used to write an <see cref="object"/> to a specified <see cref="System.IO.TextWriter"/>.
/// </summary>
/// <remarks>Default is to HTML encode all but a few types.</remarks>
protected virtual string WriteToMethodName
{
get
{
return Context.Host.GeneratedClassContext.WriteToMethodName;
}
}
protected override void Visit(TagHelperChunk chunk) protected override void Visit(TagHelperChunk chunk)
{ {
TagHelperRenderer.RenderTagHelper(chunk); TagHelperRenderer.RenderTagHelper(chunk);
@ -394,13 +422,14 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{ {
if (!string.IsNullOrEmpty(Context.TargetWriterName)) if (!string.IsNullOrEmpty(Context.TargetWriterName))
{ {
Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteToMethodName) Writer
.Write(Context.TargetWriterName) .WriteStartMethodInvocation(WriteToMethodName)
.WriteParameterSeparator(); .Write(Context.TargetWriterName)
.WriteParameterSeparator();
} }
else else
{ {
Writer.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteMethodName); Writer.WriteStartMethodInvocation(WriteMethodName);
} }
Accept(chunk.Children); Accept(chunk.Children);
@ -424,25 +453,30 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
{ {
if (!string.IsNullOrEmpty(Context.TargetWriterName)) if (!string.IsNullOrEmpty(Context.TargetWriterName))
{ {
var generatedStart = Context.Host.GeneratedClassContext.WriteToMethodName.Length + var generatedStart =
Context.TargetWriterName.Length + WriteToMethodName.Length +
3; // 1 for the opening '(' and 2 for ', ' Context.TargetWriterName.Length +
3; // 1 for the opening '(' and 2 for ', '
var padding = _paddingBuilder.BuildExpressionPadding(contentSpan, generatedStart); var padding = _paddingBuilder.BuildExpressionPadding(contentSpan, generatedStart);
Writer.Write(padding) Writer
.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteToMethodName) .Write(padding)
.Write(Context.TargetWriterName) .WriteStartMethodInvocation(WriteToMethodName)
.WriteParameterSeparator(); .Write(Context.TargetWriterName)
.WriteParameterSeparator();
} }
else else
{ {
var generatedStart = Context.Host.GeneratedClassContext.WriteMethodName.Length + var generatedStart =
1; // for the opening '(' WriteMethodName.Length +
1; // for the opening '('
var padding = _paddingBuilder.BuildExpressionPadding(contentSpan, generatedStart); var padding = _paddingBuilder.BuildExpressionPadding(contentSpan, generatedStart);
Writer.Write(padding) Writer
.WriteStartMethodInvocation(Context.Host.GeneratedClassContext.WriteMethodName); .Write(padding)
.WriteStartMethodInvocation(WriteMethodName);
} }
Accept(chunk.Children); Accept(chunk.Children);

View File

@ -21,6 +21,7 @@ namespace Microsoft.AspNet.Razor.Generator
ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute"; ExecutionContextAddTagHelperAttributeMethodName = "AddTagHelperAttribute";
ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute"; ExecutionContextAddHtmlAttributeMethodName = "AddHtmlAttribute";
ExecutionContextOutputPropertyName = "Output"; ExecutionContextOutputPropertyName = "Output";
MarkAsHtmlEncodedMethodName = "Html.Raw";
StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope"; StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope";
EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope"; EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope";
RunnerTypeName = "TagHelperRunner"; RunnerTypeName = "TagHelperRunner";
@ -71,6 +72,12 @@ namespace Microsoft.AspNet.Razor.Generator
/// </summary> /// </summary>
public string ExecutionContextOutputPropertyName { get; set; } public string ExecutionContextOutputPropertyName { get; set; }
/// <summary>
/// The name of the method used to wrap a <see cref="string"/> value and mark it as HTML-encoded.
/// </summary>
/// <remarks>Used together with <see cref="ExecutionContextAddHtmlAttributeMethodName"/>.</remarks>
public string MarkAsHtmlEncodedMethodName { get; set; }
/// <summary> /// <summary>
/// The name of the method used to start a new writing scope. /// The name of the method used to start a new writing scope.
/// </summary> /// </summary>

View File

@ -160,7 +160,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert // Assert
var attribute = Assert.Single(executionContext.HTMLAttributes); var attribute = Assert.Single(executionContext.HTMLAttributes);
Assert.Equal(new KeyValuePair<string, string>(originalName, "something else"), attribute); Assert.Equal(new KeyValuePair<string, object>(originalName, "something else"), attribute);
} }
[MemberData(nameof(DictionaryCaseTestingData))] [MemberData(nameof(DictionaryCaseTestingData))]
@ -183,7 +183,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
// Arrange // Arrange
var executionContext = new TagHelperExecutionContext("p", selfClosing: false); var executionContext = new TagHelperExecutionContext("p", selfClosing: false);
var expectedAttributes = new Dictionary<string, string> var expectedAttributes = new Dictionary<string, object>
{ {
{ "class", "btn" }, { "class", "btn" },
{ "foo", "bar" } { "foo", "bar" }

View File

@ -100,7 +100,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput("p", var tagHelperOutput = new TagHelperOutput("p",
attributes: new Dictionary<string, string> attributes: new Dictionary<string, object>
{ {
{ "class", "btn" }, { "class", "btn" },
{ "something", " spaced " } { "something", " spaced " }
@ -129,7 +129,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{ {
// Arrange // Arrange
var tagHelperOutput = new TagHelperOutput("p", var tagHelperOutput = new TagHelperOutput("p",
attributes: new Dictionary<string, string> attributes: new Dictionary<string, object>
{ {
{ originalName, "btn" }, { originalName, "btn" },
}); });
@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert // Assert
var attribute = Assert.Single(tagHelperOutput.Attributes); var attribute = Assert.Single(tagHelperOutput.Attributes);
Assert.Equal(new KeyValuePair<string, string>(originalName, "super button"), attribute); Assert.Equal(new KeyValuePair<string, object>(originalName, "super button"), attribute);
} }
} }
} }

View File

@ -38,7 +38,7 @@ namespace TestOutput
, StartTagHelperWritingScope, EndTagHelperWritingScope); , StartTagHelperWritingScope, EndTagHelperWritingScope);
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>(); __CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__tagHelperExecutionContext.Add(__CatchAllTagHelper); __tagHelperExecutionContext.Add(__CatchAllTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("catchAll", "hi"); __tagHelperExecutionContext.AddHtmlAttribute("catchAll", Html.Raw("hi"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();
@ -81,7 +81,7 @@ namespace TestOutput
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked); __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>(); __CatchAllTagHelper = CreateTagHelper<CatchAllTagHelper>();
__tagHelperExecutionContext.Add(__CatchAllTagHelper); __tagHelperExecutionContext.Add(__CatchAllTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("catchAll", "hi"); __tagHelperExecutionContext.AddHtmlAttribute("catchAll", Html.Raw("hi"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();
@ -90,7 +90,7 @@ namespace TestOutput
, StartTagHelperWritingScope, EndTagHelperWritingScope); , StartTagHelperWritingScope, EndTagHelperWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "btn"); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("btn"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -77,7 +77,7 @@ namespace TestOutput
, StartTagHelperWritingScope, EndTagHelperWritingScope); , StartTagHelperWritingScope, EndTagHelperWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World"); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("Hello World"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -55,7 +55,7 @@ namespace TestOutput
, StartTagHelperWritingScope, EndTagHelperWritingScope); , StartTagHelperWritingScope, EndTagHelperWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World"); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("Hello World"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -78,7 +78,7 @@ namespace TestOutput
, StartTagHelperWritingScope, EndTagHelperWritingScope); , StartTagHelperWritingScope, EndTagHelperWritingScope);
__PTagHelper = CreateTagHelper<PTagHelper>(); __PTagHelper = CreateTagHelper<PTagHelper>();
__tagHelperExecutionContext.Add(__PTagHelper); __tagHelperExecutionContext.Add(__PTagHelper);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World"); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("Hello World"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -69,8 +69,8 @@ namespace TestOutput
__InputTagHelper2 = CreateTagHelper<InputTagHelper2>(); __InputTagHelper2 = CreateTagHelper<InputTagHelper2>();
__tagHelperExecutionContext.Add(__InputTagHelper2); __tagHelperExecutionContext.Add(__InputTagHelper2);
__InputTagHelper2.Type = __InputTagHelper.Type; __InputTagHelper2.Type = __InputTagHelper.Type;
__tagHelperExecutionContext.AddHtmlAttribute("value", ""); __tagHelperExecutionContext.AddHtmlAttribute("value", Html.Raw(""));
__tagHelperExecutionContext.AddHtmlAttribute("placeholder", "Enter in a new time..."); __tagHelperExecutionContext.AddHtmlAttribute("placeholder", Html.Raw("Enter in a new time..."));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();
@ -100,7 +100,7 @@ namespace TestOutput
__tagHelperExecutionContext.Add(__InputTagHelper); __tagHelperExecutionContext.Add(__InputTagHelper);
StartTagHelperWritingScope(); StartTagHelperWritingScope();
#line 16 "ComplexTagHelpers.cshtml" #line 16 "ComplexTagHelpers.cshtml"
Write(checkbox); WriteLiteral(checkbox);
#line default #line default
#line hidden #line hidden
@ -134,7 +134,7 @@ Write(checkbox);
__tagHelperExecutionContext.Add(__InputTagHelper); __tagHelperExecutionContext.Add(__InputTagHelper);
StartTagHelperWritingScope(); StartTagHelperWritingScope();
#line 17 "ComplexTagHelpers.cshtml" #line 17 "ComplexTagHelpers.cshtml"
Write(true ? "checkbox" : "anything"); WriteLiteral(true ? "checkbox" : "anything");
#line default #line default
#line hidden #line hidden
@ -203,7 +203,7 @@ Write(DateTime.Now);
#line default #line default
#line hidden #line hidden
__tagHelperStringValueBuffer = EndTagHelperWritingScope(); __tagHelperStringValueBuffer = EndTagHelperWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("time", __tagHelperStringValueBuffer.ToString()); __tagHelperExecutionContext.AddHtmlAttribute("time", Html.Raw(__tagHelperStringValueBuffer.ToString()));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -45,7 +45,7 @@ __InputTagHelper2.Checked = ;
#line default #line default
#line hidden #line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked); __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.AddHtmlAttribute("class", ""); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw(""));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();
@ -70,7 +70,7 @@ __InputTagHelper2.Checked = ;
#line default #line default
#line hidden #line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked); __tagHelperExecutionContext.AddTagHelperAttribute("checked", __InputTagHelper2.Checked);
__tagHelperExecutionContext.AddHtmlAttribute("class", ""); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw(""));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -45,7 +45,7 @@ namespace TestOutput
__tagHelperExecutionContext.Add(__InputTagHelper); __tagHelperExecutionContext.Add(__InputTagHelper);
StartTagHelperWritingScope(); StartTagHelperWritingScope();
#line 6 "EscapedTagHelpers.cshtml" #line 6 "EscapedTagHelpers.cshtml"
Write(DateTime.Now); WriteLiteral(DateTime.Now);
#line default #line default
#line hidden #line hidden

View File

@ -39,7 +39,7 @@ namespace TestOutput
#line default #line default
#line hidden #line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age); __tagHelperExecutionContext.AddTagHelperAttribute("age", __PTagHelper.Age);
__tagHelperExecutionContext.AddHtmlAttribute("class", "Hello World"); __tagHelperExecutionContext.AddHtmlAttribute("class", Html.Raw("Hello World"));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperAsync(__tagHelperExecutionContext); await WriteTagHelperAsync(__tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();

View File

@ -64,7 +64,7 @@ namespace TestOutput
StartTagHelperWritingScope(); StartTagHelperWritingScope();
WriteLiteral("Current Time: "); WriteLiteral("Current Time: ");
#line 9 "TagHelpersInSection.cshtml" #line 9 "TagHelpersInSection.cshtml"
Write(DateTime.Now); WriteLiteral(DateTime.Now);
#line default #line default
#line hidden #line hidden
@ -79,7 +79,7 @@ Write(DateTime.Now);
#line default #line default
#line hidden #line hidden
__tagHelperStringValueBuffer = EndTagHelperWritingScope(); __tagHelperStringValueBuffer = EndTagHelperWritingScope();
__tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", __tagHelperStringValueBuffer.ToString()); __tagHelperExecutionContext.AddHtmlAttribute("unboundproperty", Html.Raw(__tagHelperStringValueBuffer.ToString()));
__tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);
await WriteTagHelperToAsync(__razor_template_writer, __tagHelperExecutionContext); await WriteTagHelperToAsync(__razor_template_writer, __tagHelperExecutionContext);
__tagHelperExecutionContext = __tagHelperScopeManager.End(); __tagHelperExecutionContext = __tagHelperScopeManager.End();