Add `HtmlEncoder` parameter to `RazorPage.StartTagHelperWritingScope()`

- aspnet/Razor#643 part 2: react to aspnet/Razor#653
 - change test calls and delegates to include new parameter
 - add tests specifically of the new feature
 - add tag helpers using new feature to `TagHelpersTest` functional test
- note `HtmlEncoder`s used elsewhere e.g. in other `RazorPage` instances are unaffected
 - i.e. changing one `RazorPage.HtmlEncoder` property only affects C# expressions in that page

Also simplify scope management, removing bizarre assertion when user does something odd.

nits:
- correct `// Act` and `//  Act & Assert` content
- remove #YOLO wrapping
This commit is contained in:
Doug Bunting 2016-01-17 22:59:59 -08:00
parent 249673f2bc
commit 2810858905
39 changed files with 617 additions and 184 deletions

View File

@ -30,8 +30,7 @@ namespace Microsoft.AspNet.Mvc.Razor
public abstract class RazorPage : IRazorPage public abstract class RazorPage : IRazorPage
{ {
private readonly HashSet<string> _renderedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _renderedSections = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private readonly Stack<HtmlContentWrapperTextWriter> _writerScopes; private readonly Stack<TagHelperScopeInfo> _tagHelperScopes = new Stack<TagHelperScopeInfo>();
private TextWriter _originalWriter;
private IUrlHelper _urlHelper; private IUrlHelper _urlHelper;
private ITagHelperActivator _tagHelperActivator; private ITagHelperActivator _tagHelperActivator;
private ITypeActivatorCache _typeActivatorCache; private ITypeActivatorCache _typeActivatorCache;
@ -44,7 +43,6 @@ namespace Microsoft.AspNet.Mvc.Razor
public RazorPage() public RazorPage()
{ {
SectionWriters = new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase); SectionWriters = new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase);
_writerScopes = new Stack<HtmlContentWrapperTextWriter>();
} }
/// <summary> /// <summary>
@ -62,7 +60,8 @@ namespace Microsoft.AspNet.Mvc.Razor
public string Layout { get; set; } public string Layout { get; set; }
/// <summary> /// <summary>
/// Gets the <see cref="HtmlEncoder"/> to be used for encoding HTML. /// Gets the <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/>
/// handles non-<see cref="IHtmlContent"/> C# expressions.
/// </summary> /// </summary>
[RazorInject] [RazorInject]
public HtmlEncoder HtmlEncoder { get; set; } public HtmlEncoder HtmlEncoder { get; set; }
@ -116,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Razor
public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; } public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; private set; } public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; }
/// <inheritdoc /> /// <inheritdoc />
public abstract Task ExecuteAsync(); public abstract Task ExecuteAsync();
@ -201,28 +200,31 @@ namespace Microsoft.AspNet.Mvc.Razor
} }
/// <summary> /// <summary>
/// Starts a new writing scope. /// Starts a new writing scope and optionally overrides <see cref="HtmlEncoder"/> within that scope.
/// </summary> /// </summary>
/// <param name="encoder">
/// The <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when this <see cref="RazorPage"/> handles
/// non-<see cref="IHtmlContent"/> C# expressions. If <c>null</c>, does not change <see cref="HtmlEncoder"/>.
/// </param>
/// <remarks> /// <remarks>
/// All writes to the <see cref="Output"/> or <see cref="ViewContext.Writer"/> after calling this method will /// All writes to the <see cref="Output"/> or <see cref="ViewContext.Writer"/> after calling this method will
/// be buffered until <see cref="EndTagHelperWritingScope"/> is called. /// be buffered until <see cref="EndTagHelperWritingScope"/> is called.
/// </remarks> /// </remarks>
public void StartTagHelperWritingScope() public void StartTagHelperWritingScope(HtmlEncoder encoder)
{ {
// If there isn't a base writer take the ViewContext.Writer _tagHelperScopes.Push(new TagHelperScopeInfo(HtmlEncoder, ViewContext.Writer));
if (_originalWriter == null)
{
_originalWriter = ViewContext.Writer;
}
var buffer = new ViewBuffer(BufferScope, Path); // If passed an HtmlEncoder, override the property.
var writer = new HtmlContentWrapperTextWriter(buffer, _originalWriter.Encoding); if (encoder != null)
{
HtmlEncoder = encoder;
}
// We need to replace the ViewContext's Writer to ensure that all content (including content written // We need to replace the ViewContext's Writer to ensure that all content (including content written
// from HTML helpers) is redirected. // from HTML helpers) is redirected.
var buffer = new ViewBuffer(BufferScope, Path);
var writer = new HtmlContentWrapperTextWriter(buffer, ViewContext.Writer.Encoding);
ViewContext.Writer = writer; ViewContext.Writer = writer;
_writerScopes.Push(writer);
} }
/// <summary> /// <summary>
@ -231,28 +233,21 @@ namespace Microsoft.AspNet.Mvc.Razor
/// <returns>The buffered <see cref="TagHelperContent"/>.</returns> /// <returns>The buffered <see cref="TagHelperContent"/>.</returns>
public TagHelperContent EndTagHelperWritingScope() public TagHelperContent EndTagHelperWritingScope()
{ {
if (_writerScopes.Count == 0) if (_tagHelperScopes.Count == 0)
{ {
throw new InvalidOperationException(Resources.RazorPage_ThereIsNoActiveWritingScopeToEnd); throw new InvalidOperationException(Resources.RazorPage_ThereIsNoActiveWritingScopeToEnd);
} }
var writer = _writerScopes.Pop(); // Get the content written during the current scope.
Debug.Assert(writer == ViewContext.Writer); var writer = ViewContext.Writer as HtmlContentWrapperTextWriter;
if (_writerScopes.Count > 0)
{
ViewContext.Writer = _writerScopes.Peek();
}
else
{
ViewContext.Writer = _originalWriter;
// No longer a base writer
_originalWriter = null;
}
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.AppendHtml(writer.ContentBuilder); tagHelperContent.AppendHtml(writer?.ContentBuilder);
// Restore previous scope.
var scopeInfo = _tagHelperScopes.Pop();
HtmlEncoder = scopeInfo.Encoder;
ViewContext.Writer = scopeInfo.Writer;
return tagHelperContent; return tagHelperContent;
} }
@ -290,7 +285,9 @@ namespace Microsoft.AspNet.Mvc.Razor
/// Writes the specified <paramref name="value"/> with HTML encoding to given <paramref name="writer"/>. /// Writes the specified <paramref name="value"/> with HTML encoding to given <paramref name="writer"/>.
/// </summary> /// </summary>
/// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param> /// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param>
/// <param name="encoder">The <see cref="HtmlEncoder"/> to use when encoding <paramref name="value"/>.</param> /// <param name="encoder">
/// The <see cref="System.Text.Encodings.Web.HtmlEncoder"/> to use when encoding <paramref name="value"/>.
/// </param>
/// <param name="value">The <see cref="object"/> to write.</param> /// <param name="value">The <see cref="object"/> to write.</param>
/// <remarks> /// <remarks>
/// <paramref name="value"/>s of type <see cref="IHtmlContent"/> are written using /// <paramref name="value"/>s of type <see cref="IHtmlContent"/> are written using
@ -825,9 +822,8 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </remarks> /// </remarks>
public async Task<HtmlString> FlushAsync() public async Task<HtmlString> FlushAsync()
{ {
// If there are active writing scopes then we should throw. Cannot flush content that has the potential to // If there are active scopes, then we should throw. Cannot flush content that has the potential to change.
// change. if (_tagHelperScopes.Count > 0)
if (_writerScopes.Count > 0)
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
Resources.FormatRazorPage_CannotFlushWhileInAWritingScope(nameof(FlushAsync), Path)); Resources.FormatRazorPage_CannotFlushWhileInAWritingScope(nameof(FlushAsync), Path));
@ -1000,5 +996,18 @@ namespace Microsoft.AspNet.Mvc.Razor
public bool Suppressed { get; set; } public bool Suppressed { get; set; }
} }
private struct TagHelperScopeInfo
{
public TagHelperScopeInfo(HtmlEncoder encoder, TextWriter writer)
{
Encoder = encoder;
Writer = writer;
}
public HtmlEncoder Encoder { get; }
public TextWriter Writer { get; }
}
} }
} }

View File

@ -253,6 +253,33 @@ page:<root>root-content</root>"
PlatformNormalizer.NormalizeContent(expectedContent), PlatformNormalizer.NormalizeContent(expectedContent),
responseContent, responseContent,
ignoreLineEndingDifferences: true); ignoreLineEndingDifferences: true);
#endif
}
[Theory]
[InlineData("Index")]
[InlineData("CustomEncoder")]
[InlineData("NullEncoder")]
[InlineData("TwoEncoders")]
[InlineData("ThreeEncoders")]
public async Task EncodersPages_ReturnExpectedContent(string actionName)
{
// Arrange
var outputFile = $"compiler/resources/TagHelpersWebSite.Encoders.{ actionName }.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
// Act
var response = await Client.GetAsync($"/Encoders/{ actionName }");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var responseContent = await response.Content.ReadAsStringAsync();
#if GENERATE_BASELINES
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
#else
Assert.Equal(expectedContent, responseContent, ignoreLineEndingDifferences: true);
#endif #endif
} }
} }

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Using a custom HTML encoder - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - Using a custom HTML encoder</h1>
<div>
<pre>Custom encoder: Custom[[Outer knows <b>1 < 4</b>]]
<inner>Custom[[Inner knows <b>1 < 4</b>]]</inner><br />Outer knows &lt;b&gt;2 &lt; 4&lt;/b&gt;
<inner>Inner knows &lt;b&gt;2 &lt; 4&lt;/b&gt;</inner></pre>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Using the default HTML encoder - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - Using the default HTML encoder</h1>
<div>
<pre>Default encoder: Outer knows &lt;b&gt;1 &lt; 4&lt;/b&gt;
<pre>Default encoder: Inner knows &lt;b&gt;1 &lt; 4&lt;/b&gt;</pre></pre>
</div>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>Using the null HTML encoder - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - Using the null HTML encoder</h1>
<div>
<pre>Outer knows &lt;b&gt;2 &lt; 4&lt;/b&gt;
<inner>Inner knows &lt;b&gt;2 &lt; 4&lt;/b&gt;</inner><br />Null encoder: Outer knows <b>1 < 4</b>
<inner>Inner knows <b>1 < 4</b></inner></pre>
</div>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Using three HTML encoders - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - Using three HTML encoders</h1>
<div>
<pre>Custom encoder: Custom[[Outer knows <b>1 < 4</b>]]
<pre>Default encoder: Custom[[Inner knows <b>1 < 4</b>]]</pre><br />Default encoder: Outer knows &lt;b&gt;2 &lt; 4&lt;/b&gt;
<pre>Default encoder: Inner knows &lt;b&gt;2 &lt; 4&lt;/b&gt;</pre><br />Null encoder: Outer knows <b>3 < 4</b>
<pre>Default encoder: Inner knows <b>3 < 4</b></pre></pre>
</div>
</body>
</html>

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Using two HTML encoders - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - Using two HTML encoders</h1>
<div>
<pre>Custom encoder: Custom[[Outer knows <b>1 < 4</b>]]
<inner>Custom[[Inner knows <b>1 < 4</b>]]</inner><br />Outer knows &lt;b&gt;3 &lt; 4&lt;/b&gt;
<inner>Inner knows &lt;b&gt;3 &lt; 4&lt;/b&gt;</inner><br />Null encoder: Outer knows <b>2 < 4</b>
<inner>Inner knows <b>2 < 4</b></inner></pre>
</div>
</body>
</html>

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text.Encodings.Web;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Html; using Microsoft.AspNet.Html;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
@ -41,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
v.HtmlEncoder = new HtmlTestEncoder(); v.HtmlEncoder = new HtmlTestEncoder();
v.Write("Hello Prefix"); v.Write("Hello Prefix");
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
v.Write("Hello from Output"); v.Write("Hello from Output");
v.ViewContext.Writer.Write("Hello from view context writer"); v.ViewContext.Writer.Write("Hello from view context writer");
var scopeValue = v.EndTagHelperWritingScope(); var scopeValue = v.EndTagHelperWritingScope();
@ -54,8 +55,10 @@ namespace Microsoft.AspNet.Mvc.Razor
var pageOutput = page.Output.ToString(); var pageOutput = page.Output.ToString();
// Assert // Assert
Assert.Equal("HtmlEncode[[Hello Prefix]]HtmlEncode[[From Scope: ]]HtmlEncode[[Hello from Output]]" + Assert.Equal(
"Hello from view context writer", pageOutput); "HtmlEncode[[Hello Prefix]]HtmlEncode[[From Scope: ]]HtmlEncode[[Hello from Output]]" +
"Hello from view context writer",
pageOutput);
} }
[Fact] [Fact]
@ -67,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
v.HtmlEncoder = new HtmlTestEncoder(); v.HtmlEncoder = new HtmlTestEncoder();
v.Write("Hello Prefix"); v.Write("Hello Prefix");
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
v.Write("Hello In Scope"); v.Write("Hello In Scope");
var scopeValue = v.EndTagHelperWritingScope(); var scopeValue = v.EndTagHelperWritingScope();
v.Write("From Scope: "); v.Write("From Scope: ");
@ -91,10 +94,10 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
v.HtmlEncoder = new HtmlTestEncoder(); v.HtmlEncoder = new HtmlTestEncoder();
v.Write("Hello Prefix"); v.Write("Hello Prefix");
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
v.Write("Hello In Scope Pre Nest"); v.Write("Hello In Scope Pre Nest");
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
v.Write("Hello In Nested Scope"); v.Write("Hello In Nested Scope");
var scopeValue1 = v.EndTagHelperWritingScope(); var scopeValue1 = v.EndTagHelperWritingScope();
@ -108,36 +111,85 @@ namespace Microsoft.AspNet.Mvc.Razor
// Act // Act
await page.ExecuteAsync(); await page.ExecuteAsync();
var pageOutput = page.Output.ToString();
// Assert // Assert
Assert.Equal("HtmlEncode[[Hello Prefix]]HtmlEncode[[From Scopes: ]]HtmlEncode[[Hello In Scope Pre Nest]]" + var pageOutput = page.Output.ToString();
"HtmlEncode[[Hello In Scope Post Nest]]HtmlEncode[[Hello In Nested Scope]]", pageOutput); Assert.Equal(
"HtmlEncode[[Hello Prefix]]HtmlEncode[[From Scopes: ]]HtmlEncode[[Hello In Scope Pre Nest]]" +
"HtmlEncode[[Hello In Scope Post Nest]]HtmlEncode[[Hello In Nested Scope]]",
pageOutput);
} }
[Fact] [Fact]
public async Task StartNewWritingScope_CannotFlushInWritingScope() public async Task StartTagHelperWritingScope_CannotFlushInWritingScope()
{ {
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
var page = CreatePage(async v => var page = CreatePage(async v =>
{ {
v.Path = "/Views/TestPath/Test.cshtml"; v.Path = "/Views/TestPath/Test.cshtml";
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
await v.FlushAsync(); await v.FlushAsync();
}); });
// Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync());
Assert.Equal(
"The FlushAsync operation cannot be performed while " +
"inside a writing scope in '/Views/TestPath/Test.cshtml'.",
ex.Message);
}
public static TheoryData<HtmlEncoder> HtmlEncoderData
{
get
{
return new TheoryData<HtmlEncoder>
{
HtmlEncoder.Default,
NullHtmlEncoder.Default,
new HtmlTestEncoder(),
};
}
}
[Theory]
[MemberData(nameof(HtmlEncoderData))]
public async Task StartTagHelperWritingScope_SetsHtmlEncoder(HtmlEncoder encoder)
{
// Arrange
var page = CreatePage(v =>
{
v.StartTagHelperWritingScope(encoder);
});
// Act // Act
var ex = await Assert.ThrowsAsync<InvalidOperationException>( await page.ExecuteAsync();
() => page.ExecuteAsync());
// Assert // Assert
Assert.Equal("The FlushAsync operation cannot be performed while " + Assert.Same(encoder, page.HtmlEncoder);
"inside a writing scope in '/Views/TestPath/Test.cshtml'.", ex.Message);
} }
[Fact] [Fact]
public async Task StartNewWritingScope_CannotEndWritingScopeWhenNoWritingScope() public async Task StartTagHelperWritingScope_DoesNotSetHtmlEncoderToNull()
{
// Arrange
var page = CreatePage(v =>
{
v.StartTagHelperWritingScope(encoder: null);
});
var originalEncoder = page.HtmlEncoder;
// Act
await page.ExecuteAsync();
// Assert
Assert.NotNull(originalEncoder);
Assert.Same(originalEncoder, page.HtmlEncoder);
}
[Fact]
public async Task EndTagHelperWritingScope_CannotEndWritingScopeWhenNoWritingScope()
{ {
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
@ -146,11 +198,8 @@ namespace Microsoft.AspNet.Mvc.Razor
v.EndTagHelperWritingScope(); v.EndTagHelperWritingScope();
}); });
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>( var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync());
() => page.ExecuteAsync());
// Assert
Assert.Equal("There is no active writing scope to end.", ex.Message); Assert.Equal("There is no active writing scope to end.", ex.Message);
} }
@ -159,12 +208,10 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
// Arrange // Arrange
var viewContext = CreateViewContext(); var viewContext = CreateViewContext();
// Act
var page = CreatePage(v => var page = CreatePage(v =>
{ {
v.HtmlEncoder = new HtmlTestEncoder(); v.HtmlEncoder = new HtmlTestEncoder();
v.StartTagHelperWritingScope(); v.StartTagHelperWritingScope(encoder: null);
v.Write("Hello World!"); v.Write("Hello World!");
var returnValue = v.EndTagHelperWritingScope(); var returnValue = v.EndTagHelperWritingScope();
@ -172,6 +219,8 @@ namespace Microsoft.AspNet.Mvc.Razor
var content = Assert.IsType<DefaultTagHelperContent>(returnValue); var content = Assert.IsType<DefaultTagHelperContent>(returnValue);
Assert.Equal("HtmlEncode[[Hello World!]]", content.GetContent()); Assert.Equal("HtmlEncode[[Hello World!]]", content.GetContent());
}); });
// Act & Assert
await page.ExecuteAsync(); await page.ExecuteAsync();
} }
@ -186,11 +235,8 @@ namespace Microsoft.AspNet.Mvc.Razor
v.DefineSection("qux", _nullRenderAsyncDelegate); v.DefineSection("qux", _nullRenderAsyncDelegate);
}); });
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>( var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync());
() => page.ExecuteAsync());
// Assert
Assert.Equal("Section 'qux' is already defined.", ex.Message); Assert.Equal("Section 'qux' is already defined.", ex.Message);
} }
@ -227,10 +273,8 @@ namespace Microsoft.AspNet.Mvc.Razor
ex = Assert.Throws<InvalidOperationException>(() => v.RenderSection("bar")); ex = Assert.Throws<InvalidOperationException>(() => v.RenderSection("bar"));
}); });
// Act // Act & Assert
await page.ExecuteAsync(); await page.ExecuteAsync();
// Assert
Assert.Equal("RenderSection invocation in '/Views/TestPath/Test.cshtml' is invalid. " + Assert.Equal("RenderSection invocation in '/Views/TestPath/Test.cshtml' is invalid. " +
"RenderSection can only be called from a layout page.", "RenderSection can only be called from a layout page.",
ex.Message); ex.Message);
@ -250,10 +294,8 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "baz", _nullRenderAsyncDelegate } { "baz", _nullRenderAsyncDelegate }
}; };
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync()); var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync());
// Assert
Assert.Equal("Section 'bar' is not defined in path '/Views/TestPath/Test.cshtml'.", ex.Message); Assert.Equal("Section 'bar' is not defined in path '/Views/TestPath/Test.cshtml'.", ex.Message);
} }
@ -265,9 +307,9 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
v.Path = "/Views/TestPath/Test.cshtml"; v.Path = "/Views/TestPath/Test.cshtml";
}); });
// Act and Assert
page.ExecuteAsync(); page.ExecuteAsync();
// Act & Assert
ExceptionAssert.Throws<InvalidOperationException>(() => page.IsSectionDefined("foo"), ExceptionAssert.Throws<InvalidOperationException>(() => page.IsSectionDefined("foo"),
"IsSectionDefined invocation in '/Views/TestPath/Test.cshtml' is invalid." + "IsSectionDefined invocation in '/Views/TestPath/Test.cshtml' is invalid." +
" IsSectionDefined can only be called from a layout page."); " IsSectionDefined can only be called from a layout page.");
@ -337,12 +379,12 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "header", _nullRenderAsyncDelegate } { "header", _nullRenderAsyncDelegate }
}; };
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync); var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
Assert.Equal(
// Assert "RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." +
Assert.Equal("RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." + " The section 'header' has already been rendered.",
" The section 'header' has already been rendered.", ex.Message); ex.Message);
} }
[Fact] [Fact]
@ -361,12 +403,12 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "header", _nullRenderAsyncDelegate } { "header", _nullRenderAsyncDelegate }
}; };
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync); var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
Assert.Equal(
// Assert "RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." +
Assert.Equal("RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." + " The section 'header' has already been rendered.",
" The section 'header' has already been rendered.", ex.Message); ex.Message);
} }
[Fact] [Fact]
@ -385,12 +427,12 @@ namespace Microsoft.AspNet.Mvc.Razor
{ "header", _nullRenderAsyncDelegate } { "header", _nullRenderAsyncDelegate }
}; };
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync); var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
Assert.Equal(
// Assert "RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." +
Assert.Equal("RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid." + " The section 'header' has already been rendered.",
" The section 'header' has already been rendered.", ex.Message); ex.Message);
} }
[Fact] [Fact]
@ -404,12 +446,12 @@ namespace Microsoft.AspNet.Mvc.Razor
await v.RenderSectionAsync("header"); await v.RenderSectionAsync("header");
}); });
// Act // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync); var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
Assert.Equal(
// Assert "RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid. " +
Assert.Equal("RenderSectionAsync invocation in '/Views/TestPath/Test.cshtml' is invalid. " + "RenderSectionAsync can only be called from a layout page.",
"RenderSectionAsync can only be called from a layout page.", ex.Message); ex.Message);
} }
[Fact] [Fact]
@ -422,12 +464,10 @@ namespace Microsoft.AspNet.Mvc.Razor
}); });
page.Path = path; page.Path = path;
page.BodyContent = new HtmlString("some content"); page.BodyContent = new HtmlString("some content");
// Act
await page.ExecuteAsync(); await page.ExecuteAsync();
var ex = Assert.Throws<InvalidOperationException>(() => page.EnsureRenderedBodyOrSections());
// Assert // Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => page.EnsureRenderedBodyOrSections());
Assert.Equal($"RenderBody has not been called for the page at '{path}'.", ex.Message); Assert.Equal($"RenderBody has not been called for the page at '{path}'.", ex.Message);
} }
@ -446,14 +486,14 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
{ sectionName, _nullRenderAsyncDelegate } { sectionName, _nullRenderAsyncDelegate }
}; };
// Act
await page.ExecuteAsync(); await page.ExecuteAsync();
var ex = Assert.Throws<InvalidOperationException>(() => page.EnsureRenderedBodyOrSections());
// Assert // Act & Assert
Assert.Equal("The following sections have been defined but have not been rendered by the page at " + var ex = Assert.Throws<InvalidOperationException>(() => page.EnsureRenderedBodyOrSections());
$"'{path}': '{sectionName}'.", ex.Message); Assert.Equal(
"The following sections have been defined but have not been rendered by the page at " +
$"'{path}': '{sectionName}'.",
ex.Message);
} }
[Fact] [Fact]
@ -474,7 +514,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ sectionB, _nullRenderAsyncDelegate }, { sectionB, _nullRenderAsyncDelegate },
}; };
// Act and Assert // Act & Assert (does not throw)
await page.ExecuteAsync(); await page.ExecuteAsync();
page.EnsureRenderedBodyOrSections(); page.EnsureRenderedBodyOrSections();
} }
@ -593,7 +633,7 @@ namespace Microsoft.AspNet.Mvc.Razor
await p.FlushAsync(); await p.FlushAsync();
}, context); }, context);
// Act and Assert // Act & Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync()); var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => page.ExecuteAsync());
Assert.Equal(expected, ex.Message); Assert.Equal(expected, ex.Message);
} }
@ -923,7 +963,7 @@ namespace Microsoft.AspNet.Mvc.Razor
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: string.Empty, uniqueId: string.Empty,
executeChildContentAsync: () => Task.FromResult(result: true), executeChildContentAsync: () => Task.FromResult(result: true),
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () => new DefaultTagHelperContent()); endTagHelperWritingScope: () => new DefaultTagHelperContent());
// Act // Act
@ -964,7 +1004,7 @@ namespace Microsoft.AspNet.Mvc.Razor
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: string.Empty, uniqueId: string.Empty,
executeChildContentAsync: () => Task.FromResult(result: true), executeChildContentAsync: () => Task.FromResult(result: true),
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () => new DefaultTagHelperContent()); endTagHelperWritingScope: () => new DefaultTagHelperContent());
// Act // Act
@ -992,7 +1032,7 @@ namespace Microsoft.AspNet.Mvc.Razor
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
uniqueId: string.Empty, uniqueId: string.Empty,
executeChildContentAsync: () => Task.FromResult(result: true), executeChildContentAsync: () => Task.FromResult(result: true),
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () => new DefaultTagHelperContent()); endTagHelperWritingScope: () => new DefaultTagHelperContent());
// Act // Act

View File

@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", url } { "href", url }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var urlHelperMock = new Mock<IUrlHelper>(); var urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>())) .Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", url } { "href", url }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var urlHelperMock = new Mock<IUrlHelper>(); var urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>())) .Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
@ -158,7 +158,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", url } { "href", url }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var urlHelperMock = new Mock<IUrlHelper>(); var urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>())) .Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
@ -213,7 +213,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", url } { "href", url }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var urlHelperMock = new Mock<IUrlHelper>(); var urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>())) .Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
@ -251,7 +251,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", true } { "href", true }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory: null, htmlEncoder: null); var tagHelper = new UrlResolutionTagHelper(urlHelperFactory: null, htmlEncoder: null);
var context = new TagHelperContext( var context = new TagHelperContext(
@ -288,7 +288,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ {
{ "href", new HtmlString(relativeUrl) } { "href", new HtmlString(relativeUrl) }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var urlHelperMock = new Mock<IUrlHelper>(); var urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>())) .Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "id", "myanchor" }, { "id", "myanchor" },
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something Else"); tagHelperContent.SetContent("Something Else");
@ -99,7 +99,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -148,7 +148,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -209,7 +209,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "href", "http://www.contoso.com" } { "href", "http://www.contoso.com" }
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
if (propertyName == "asp-route-") if (propertyName == "asp-route-")
{ {
anchorTagHelper.RouteValues.Add("name", "value"); anchorTagHelper.RouteValues.Add("name", "value");
@ -255,7 +255,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"a", "a",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var expectedErrorMessage = "Cannot determine an 'href' attribute for <a>. An <a> with a specified " + var expectedErrorMessage = "Cannot determine an 'href' attribute for <a>. An <a> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";

View File

@ -740,7 +740,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"cache", "cache",
new TagHelperAttributeList { { "attr", "value" } }, new TagHelperAttributeList { { "attr", "value" } },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
TagHelperContent tagHelperContent; TagHelperContent tagHelperContent;
if (!cache.TryGetValue("key1", out tagHelperContent)) if (!cache.TryGetValue("key1", out tagHelperContent))
@ -806,7 +806,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return new TagHelperOutput( return new TagHelperOutput(
tagName, tagName,
attributes, attributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetHtmlContent(childContent); tagHelperContent.SetHtmlContent(childContent);

View File

@ -143,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Test
return new TagHelperOutput( return new TagHelperOutput(
tagName, tagName,
attributes, attributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent(childContent); tagHelperContent.SetContent(childContent);

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "id", "myform" }, { "id", "myform" },
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something Else"); tagHelperContent.SetContent("Something Else");
@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -168,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -239,7 +239,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -290,7 +290,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -357,7 +357,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "aCTiON", "my-action" }, { "aCTiON", "my-action" },
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -397,7 +397,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "action", "my-action" }, { "action", "my-action" },
}, },
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
if (propertyName == "asp-route-") if (propertyName == "asp-route-")
{ {
formTagHelper.RouteValues.Add("name", "value"); formTagHelper.RouteValues.Add("name", "value");
@ -438,7 +438,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"form", "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null)); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " + var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " +
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute."; "'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";

View File

@ -54,7 +54,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"img", "img",
outputAttributes, outputAttributes,
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
var urlHelper = new Mock<IUrlHelper>(); var urlHelper = new Mock<IUrlHelper>();
@ -294,7 +295,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return new TagHelperOutput( return new TagHelperOutput(
"img", "img",
attributes, attributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent(default(string)); tagHelperContent.SetContent(default(string));

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
originalTagName, originalTagName,
outputAttributes, outputAttributes,
getChildContentAsync: useCachedResult => Task.FromResult<TagHelperContent>(result: null)) getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(result: null))
{ {
TagMode = TagMode.SelfClosing, TagMode = TagMode.SelfClosing,
}; };
@ -204,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -268,7 +268,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
originalTagName, originalTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -367,7 +367,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -468,7 +468,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -566,7 +566,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -675,7 +675,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -792,7 +792,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())) getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()))
{ {
TagMode = TagMode.SelfClosing, TagMode = TagMode.SelfClosing,
}; };
@ -875,7 +876,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())) getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()))
{ {
TagMode = TagMode.SelfClosing, TagMode = TagMode.SelfClosing,
}; };

View File

@ -201,7 +201,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
htmlAttributes, htmlAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.AppendHtml(tagHelperOutputContent.OriginalChildContent); tagHelperContent.AppendHtml(tagHelperOutputContent.OriginalChildContent);

View File

@ -844,7 +844,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return new TagHelperOutput( return new TagHelperOutput(
tagName, tagName,
attributes, attributes,
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
} }
private static IHostingEnvironment MakeHostingEnvironment() private static IHostingEnvironment MakeHostingEnvironment()

View File

@ -408,7 +408,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagHelperOutput.TagName, expectedTagHelperOutput.TagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
// GetChildContentAsync should not be invoked since we are setting the content below. // GetChildContentAsync should not be invoked since we are setting the content below.
Assert.True(false); Assert.True(false);
@ -478,7 +478,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
originalTagName, originalTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent(originalContent); tagHelperContent.SetContent(originalContent);
@ -542,7 +542,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
originalTagName, originalTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent(originalContent); tagHelperContent.SetContent(originalContent);
@ -574,7 +574,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName, tagName,
attributes, attributes,
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
tagHelperOutput.Content.SetContent(content); tagHelperOutput.Content.SetContent(content);
return tagHelperOutput; return tagHelperOutput;

View File

@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "form", tagName: "form",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (useCachedResult) => getChildContentAsync: (useCachedResult, encoder) =>
{ {
Assert.True(viewContext.FormContext.CanRenderAtEndOfForm); Assert.True(viewContext.FormContext.CanRenderAtEndOfForm);
foreach (var item in tagBuilderList) foreach (var item in tagBuilderList)
@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return Task.FromResult(true); return Task.FromResult(true);
}, },
startTagHelperWritingScope: () => { }, startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () => new DefaultTagHelperContent()); endTagHelperWritingScope: () => new DefaultTagHelperContent());
// This TagHelper will pre-execute the child content forcing the body to be cached. // This TagHelper will pre-execute the child content forcing the body to be cached.

View File

@ -847,7 +847,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return new TagHelperOutput( return new TagHelperOutput(
tagName, tagName,
attributes, attributes,
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
} }
private static IHostingEnvironment MakeHostingEnvironment() private static IHostingEnvironment MakeHostingEnvironment()

View File

@ -208,7 +208,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -297,7 +297,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.AppendHtml("Something"); tagHelperContent.AppendHtml("Something");
@ -401,7 +401,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.AppendHtml("Something"); tagHelperContent.AppendHtml("Something");
@ -489,7 +489,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -570,7 +570,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName, tagName,
originalAttributes, originalAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");

View File

@ -336,7 +336,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(outputAttributes), attributes: new TagHelperAttributeList(outputAttributes),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes, allAttributes,
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
@ -436,7 +437,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var context = new TagHelperContext( var context = new TagHelperContext(
allAttributes, allAttributes,
items: new Dictionary<object, object>(), items: new Dictionary<object, object>(),
@ -458,7 +460,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.Append("Something"); tagHelperContent.Append("Something");
@ -492,7 +494,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ attributeName, "world2" } { attributeName, "world2" }
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.Append("Something Else"); tagHelperContent.Append("Something Else");
@ -523,7 +525,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.Append("Something"); tagHelperContent.Append("Something");
@ -555,7 +557,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ "route-Hello", "World" }, { "route-Hello", "World" },
{ "Route-I", "Am" } { "Route-I", "Am" }
}, },
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedAttribute = new TagHelperAttribute("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
@ -582,7 +585,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ "route-Hello", "World" }, { "route-Hello", "World" },
{ "Route-I", "Am" } { "Route-I", "Am" }
}, },
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedAttribute = new TagHelperAttribute("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
var attributes = tagHelperOutput.Attributes var attributes = tagHelperOutput.Attributes
@ -607,7 +611,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ "route-Hello", "World" }, { "route-Hello", "World" },
{ "Route-I", "Am" } { "Route-I", "Am" }
}, },
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedAttribute = new TagHelperAttribute("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
@ -765,7 +770,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
"p", "p",
outputAttributes, outputAttributes,
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var tagBuilder = new TagBuilder("p"); var tagBuilder = new TagBuilder("p");
foreach (var attr in tagBuilderAttributes) foreach (var attr in tagBuilderAttributes)
@ -790,7 +796,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedAttribute = new TagHelperAttribute("type", "btn"); var expectedAttribute = new TagHelperAttribute("type", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
@ -812,7 +819,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
tagHelperOutput.Attributes.Add("class", "Hello"); tagHelperOutput.Attributes.Add("class", "Hello");
var tagBuilder = new TagBuilder("p"); var tagBuilder = new TagBuilder("p");
@ -839,7 +847,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
tagHelperOutput.Attributes.Add(originalName, "Hello"); tagHelperOutput.Attributes.Add(originalName, "Hello");
var tagBuilder = new TagBuilder("p"); var tagBuilder = new TagBuilder("p");
@ -860,7 +869,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var tagBuilder = new TagBuilder("p"); var tagBuilder = new TagBuilder("p");
var expectedAttribute = new TagHelperAttribute("visible", "val < 3"); var expectedAttribute = new TagHelperAttribute("visible", "val < 3");
@ -881,7 +891,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var tagBuilder = new TagBuilder("p"); var tagBuilder = new TagBuilder("p");
var expectedAttribute1 = new TagHelperAttribute("class", "btn"); var expectedAttribute1 = new TagHelperAttribute("class", "btn");
@ -907,7 +918,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedAttribute = new TagHelperAttribute("class", "btn"); var expectedAttribute = new TagHelperAttribute("class", "btn");
tagHelperOutput.Attributes.Add(expectedAttribute); tagHelperOutput.Attributes.Add(expectedAttribute);
@ -928,7 +940,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var tagHelperOutput = new TagHelperOutput( var tagHelperOutput = new TagHelperOutput(
tagName: "p", tagName: "p",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
var expectedOutputAttribute = new TagHelperAttribute("class", "btn"); var expectedOutputAttribute = new TagHelperAttribute("class", "btn");
tagHelperOutput.Attributes.Add(expectedOutputAttribute); tagHelperOutput.Attributes.Add(expectedOutputAttribute);

View File

@ -135,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
expectedTagName, expectedTagName,
htmlAttributes, htmlAttributes,
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "id", "myvalidationmessage" } { "id", "myvalidationmessage" }
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -168,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.AppendHtml(childContent); tagHelperContent.AppendHtml(childContent);
@ -227,7 +227,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
"span", "span",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent(childContent); tagHelperContent.SetContent(childContent);
@ -268,7 +268,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "span", tagName: "span",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
{ "class", "form-control" } { "class", "form-control" }
}, },
getChildContentAsync: useCachedResult => getChildContentAsync: (useCachedResult, encoder) =>
{ {
var tagHelperContent = new DefaultTagHelperContent(); var tagHelperContent = new DefaultTagHelperContent();
tagHelperContent.SetContent("Something"); tagHelperContent.SetContent("Something");
@ -111,7 +111,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "div", tagName: "div",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);
@ -165,7 +166,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "div", tagName: "div",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent("Content of validation summary"); output.PostContent.SetContent("Content of validation summary");
@ -213,7 +215,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "div", tagName: "div",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent(expectedPostContent); output.PostContent.SetContent(expectedPostContent);
@ -268,7 +271,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var output = new TagHelperOutput( var output = new TagHelperOutput(
tagName: "div", tagName: "div",
attributes: new TagHelperAttributeList(), attributes: new TagHelperAttributeList(),
getChildContentAsync: (_) => Task.FromResult<TagHelperContent>(new DefaultTagHelperContent())); getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
new DefaultTagHelperContent()));
output.PreContent.SetContent(expectedPreContent); output.PreContent.SetContent(expectedPreContent);
output.Content.SetContent(expectedContent); output.Content.SetContent(expectedContent);
output.PostContent.SetContent("Content of validation message"); output.PostContent.SetContent("Content of validation message");

View File

@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc;
namespace TagHelpersWebSite.Controllers
{
public class EncodersController : Controller
{
public IActionResult Index()
{
ViewData["Title"] = "Using the default HTML encoder";
return View();
}
public IActionResult CustomEncoder()
{
ViewData["Title"] = "Using a custom HTML encoder";
return View();
}
public IActionResult NullEncoder()
{
ViewData["Title"] = "Using the null HTML encoder";
return View();
}
// We've defined the behavior when multiple tag helpers target the same element. But this is an extreme corner
// case since one tag helper even using anything but the default HTML encoder is not going to be common.
public IActionResult TwoEncoders()
{
ViewData["Title"] = "Using two HTML encoders";
return View();
}
// We've defined the behavior when multiple tag helpers target the same element. But this is an extreme corner
// case since one tag helper even using anything but the default HTML encoder is not going to be common.
public IActionResult ThreeEncoders()
{
ViewData["Title"] = "Using three HTML encoders";
return View();
}
}
}

View File

@ -0,0 +1,81 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace TagHelpersWebSite.TagHelpers
{
[HtmlTargetElement("pre")]
public class CustomEncoderTagHelper : TagHelper
{
public override int Order => 1;
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var encoder = new CustomEncoder();
var customContent = await output.GetChildContentAsync(encoder);
// Note this is very unsafe. Should always post-process content that may not be fully HTML encoded before
// writing it into a response. Here for example, could pass SetContent() a string and that would be
// HTML encoded later.
output.PreContent
.SetHtmlContent("Custom encoder: ")
.AppendHtml(customContent)
.AppendHtml("<br />");
}
// Simple encoder that just wraps "string" as "Custom[[string]]". Note: Lacks all parameter checks.
private class CustomEncoder : HtmlEncoder
{
public CustomEncoder()
{
}
public override int MaxOutputCharactersPerInputCharacter => 1;
public override string Encode(string value) => $"Custom[[{ value }]]";
public override void Encode(TextWriter output, char[] value, int startIndex, int characterCount)
{
if (characterCount == 0)
{
return;
}
output.Write("Custom[[");
output.Write(value, startIndex, characterCount);
output.Write("]]");
}
public override void Encode(TextWriter output, string value, int startIndex, int characterCount)
{
if (characterCount == 0)
{
return;
}
output.Write("Custom[[");
output.Write(value.Substring(startIndex, characterCount));
output.Write("]]");
}
public override unsafe int FindFirstCharacterToEncode(char* text, int textLength) => -1;
public override unsafe bool TryEncodeUnicodeScalar(
int unicodeScalar,
char* buffer,
int bufferLength,
out int numberOfCharactersWritten)
{
numberOfCharactersWritten = 0;
return false;
}
public override bool WillEncode(int unicodeScalar) => false;
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace TagHelpersWebSite.TagHelpers
{
[HtmlTargetElement("pre")]
[HtmlTargetElement("inner")]
[OutputElementHint("pre")]
public class DefaultEncoderTagHelper : TagHelper
{
public override int Order => 2;
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var defaultContent = await output.GetChildContentAsync();
output.Content
.SetHtmlContent("Default encoder: ")
.AppendHtml(defaultContent);
output.TagName = "pre";
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace TagHelpersWebSite.TagHelpers
{
[HtmlTargetElement("pre")]
public class NullEncoderTagHelper : TagHelper
{
public override int Order => 3;
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var nullContent = await output.GetChildContentAsync(NullHtmlEncoder.Default);
// Note this is very unsafe. Should always post-process content that may not be fully HTML encoded before
// writing it into a response. Here for example, could pass SetContent() a string and that would be
// HTML encoded later.
output.PostContent
.SetHtmlContent("<br />Null encoder: ")
.AppendHtml(nullContent);
}
}
}

View File

@ -0,0 +1,9 @@
@addTagHelper TagHelpersWebSite.TagHelpers.CustomEncoderTagHelper, TagHelpersWebSite
@{
var count = 0;
var innerCount = 0;
}
<pre>@($"Outer knows <b>{ ++count } < 4</b>")
<inner>@($"Inner knows <b>{ ++innerCount } < 4</b>")</inner></pre>

View File

@ -0,0 +1,9 @@
@addTagHelper TagHelpersWebSite.TagHelpers.DefaultEncoderTagHelper, TagHelpersWebSite
@{
var count = 0;
var innerCount = 0;
}
<pre>@($"Outer knows <b>{ ++count } < 4</b>")
<inner>@($"Inner knows <b>{ ++innerCount } < 4</b>")</inner></pre>

View File

@ -0,0 +1,9 @@
@addTagHelper TagHelpersWebSite.TagHelpers.NullEncoderTagHelper, TagHelpersWebSite
@{
var count = 0;
var innerCount = 0;
}
<pre>@($"Outer knows <b>{ ++count } < 4</b>")
<inner>@($"Inner knows <b>{ ++innerCount } < 4</b>")</inner></pre>

View File

@ -0,0 +1,11 @@
@addTagHelper TagHelpersWebSite.TagHelpers.CustomEncoderTagHelper, TagHelpersWebSite
@addTagHelper TagHelpersWebSite.TagHelpers.DefaultEncoderTagHelper, TagHelpersWebSite
@addTagHelper TagHelpersWebSite.TagHelpers.NullEncoderTagHelper, TagHelpersWebSite
@{
var count = 0;
var innerCount = 0;
}
<pre>@($"Outer knows <b>{ ++count } < 4</b>")
<inner>@($"Inner knows <b>{ ++innerCount } < 4</b>")</inner></pre>

View File

@ -0,0 +1,10 @@
@addTagHelper TagHelpersWebSite.TagHelpers.CustomEncoderTagHelper, TagHelpersWebSite
@addTagHelper TagHelpersWebSite.TagHelpers.NullEncoderTagHelper, TagHelpersWebSite
@{
var count = 0;
var innerCount = 0;
}
<pre>@($"Outer knows <b>{ ++count } < 4</b>")
<inner>@($"Inner knows <b>{ ++innerCount } < 4</b>")</inner></pre>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>@ViewData["Title"] - My MVC 6 Application</title>
</head>
<body>
<h1>MVC 6 - @ViewData["Title"]</h1>
<div>
@RenderBody()
</div>
</body>
</html>

View File

@ -0,0 +1 @@
@removeTagHelper "TagHelpersWebSite.TagHelpers.RootViewStartTagHelper, TagHelpersWebSite"

View File

@ -0,0 +1,3 @@
@{
Layout = "_Layout.cshtml";
}

View File

@ -1,6 +1,8 @@
{ {
"compilationOptions": { "compilationOptions": {
"emitEntryPoint": true "allowUnsafe": true,
"emitEntryPoint": true,
"warningsAsErrors": true
}, },
"commands": { "commands": {
"web": "TagHelpersWebSite" "web": "TagHelpersWebSite"

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
</system.webServer>
</configuration>