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:
parent
80566401f8
commit
33407ef1be
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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" }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue