Removing CopyTo from RazorTextWriter
This commit is contained in:
parent
7e1a6222aa
commit
70bdb6eb3e
|
|
@ -1,10 +1,9 @@
|
|||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
|
|
@ -20,9 +19,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
ViewContext ViewContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the action invoked to render the body.
|
||||
/// Gets or sets the body content.
|
||||
/// </summary>
|
||||
Func<TextWriter, Task> RenderBodyDelegateAsync { get; set; }
|
||||
IHtmlContent BodyContent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag that determines if the layout of this page is being rendered.
|
||||
|
|
@ -64,7 +63,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// Verifies that all sections defined in <see cref="PreviousSectionWriters"/> were rendered, or
|
||||
/// the body was rendered if no sections were defined.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">if one or more sections were not rendered or if no sections were
|
||||
/// <exception cref="System.InvalidOperationException">if one or more sections were not rendered or if no sections were
|
||||
/// defined and the body was not rendered.</exception>
|
||||
void EnsureRenderedBodyOrSections();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public ITempDataDictionary TempData => ViewContext?.TempData;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Func<TextWriter, Task> RenderBodyDelegateAsync { get; set; }
|
||||
public IHtmlContent BodyContent { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLayoutBeingRendered { get; set; }
|
||||
|
|
@ -249,26 +249,26 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
_originalWriter = null;
|
||||
}
|
||||
|
||||
var tagHelperContentWrapperTextWriter = new TagHelperContentWrapperTextWriter(Output.Encoding);
|
||||
var tagHelperContent = new DefaultTagHelperContent();
|
||||
var razorWriter = writer as RazorTextWriter;
|
||||
if (razorWriter != null)
|
||||
{
|
||||
razorWriter.CopyTo(tagHelperContentWrapperTextWriter);
|
||||
tagHelperContent.Append(razorWriter.Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var stringCollectionTextWriter = writer as StringCollectionTextWriter;
|
||||
if (stringCollectionTextWriter != null)
|
||||
{
|
||||
stringCollectionTextWriter.CopyTo(tagHelperContentWrapperTextWriter, HtmlEncoder);
|
||||
tagHelperContent.Append(stringCollectionTextWriter.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
tagHelperContentWrapperTextWriter.Write(writer.ToString());
|
||||
tagHelperContent.AppendHtml(writer.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return tagHelperContentWrapperTextWriter.Content;
|
||||
return tagHelperContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -669,16 +669,16 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// In a Razor layout page, renders the portion of a content page that is not within a named section.
|
||||
/// </summary>
|
||||
/// <returns>The HTML content to render.</returns>
|
||||
protected virtual HelperResult RenderBody()
|
||||
protected virtual IHtmlContent RenderBody()
|
||||
{
|
||||
if (RenderBodyDelegateAsync == null)
|
||||
if (BodyContent == null)
|
||||
{
|
||||
var message = Resources.FormatRazorPage_MethodCannotBeCalled(nameof(RenderBody), Path);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
_renderedBody = true;
|
||||
return new HelperResult(RenderBodyDelegateAsync);
|
||||
return BodyContent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -886,7 +886,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
throw new InvalidOperationException(Resources.FormatSectionsNotRendered(Path, sectionNames));
|
||||
}
|
||||
}
|
||||
else if (RenderBodyDelegateAsync != null && !_renderedBody)
|
||||
else if (BodyContent != null && !_renderedBody)
|
||||
{
|
||||
// There are no sections defined, but RenderBody was NOT called.
|
||||
// If a body was defined, then RenderBody should have been called.
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <inheritdoc />
|
||||
public bool IsBuffering { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffered content.
|
||||
/// </summary>
|
||||
public IHtmlContent Buffer => BufferedWriter.Content;
|
||||
|
||||
// Internal for unit testing
|
||||
internal StringCollectionTextWriter BufferedWriter { get; }
|
||||
|
||||
|
|
@ -185,7 +190,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
IsBuffering = false;
|
||||
TargetWriter = UnbufferedWriter;
|
||||
CopyTo(UnbufferedWriter);
|
||||
Buffer.WriteTo(UnbufferedWriter, HtmlEncoder);
|
||||
}
|
||||
|
||||
UnbufferedWriter.Flush();
|
||||
|
|
@ -197,43 +202,16 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// to the unbuffered writer.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> that represents the asynchronous copy and flush operations.</returns>
|
||||
public override async Task FlushAsync()
|
||||
public override Task FlushAsync()
|
||||
{
|
||||
if (IsBuffering)
|
||||
{
|
||||
IsBuffering = false;
|
||||
TargetWriter = UnbufferedWriter;
|
||||
await CopyToAsync(UnbufferedWriter);
|
||||
Buffer.WriteTo(UnbufferedWriter, HtmlEncoder);
|
||||
}
|
||||
|
||||
await UnbufferedWriter.FlushAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(TextWriter writer)
|
||||
{
|
||||
writer = UnWrapRazorTextWriter(writer);
|
||||
BufferedWriter.CopyTo(writer, HtmlEncoder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CopyToAsync(TextWriter writer)
|
||||
{
|
||||
writer = UnWrapRazorTextWriter(writer);
|
||||
return BufferedWriter.CopyToAsync(writer, HtmlEncoder);
|
||||
}
|
||||
|
||||
private static TextWriter UnWrapRazorTextWriter(TextWriter writer)
|
||||
{
|
||||
var targetRazorTextWriter = writer as RazorTextWriter;
|
||||
if (targetRazorTextWriter != null)
|
||||
{
|
||||
writer = targetRazorTextWriter.IsBuffering ?
|
||||
targetRazorTextWriter.BufferedWriter :
|
||||
targetRazorTextWriter.UnbufferedWriter;
|
||||
}
|
||||
|
||||
return writer;
|
||||
return UnbufferedWriter.FlushAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -203,7 +203,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
// in the layout.
|
||||
previousPage.IsLayoutBeingRendered = true;
|
||||
layoutPage.PreviousSectionWriters = previousPage.SectionWriters;
|
||||
layoutPage.RenderBodyDelegateAsync = bodyWriter.CopyToAsync;
|
||||
layoutPage.BodyContent = bodyWriter.Buffer;
|
||||
bodyWriter = await RenderPageAsync(layoutPage, context, viewStartPages: null);
|
||||
|
||||
renderedLayouts.Add(layoutPage);
|
||||
|
|
@ -219,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
if (bodyWriter.IsBuffering)
|
||||
{
|
||||
// Only copy buffered content to the Output if we're currently buffering.
|
||||
await bodyWriter.CopyToAsync(context.Writer);
|
||||
bodyWriter.Buffer.WriteTo(context.Writer, _htmlEncoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public class RazorPageTest
|
||||
{
|
||||
private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = writer => Task.FromResult(0);
|
||||
private readonly Func<TextWriter, Task> NullAsyncWrite = CreateAsyncWriteDelegate(string.Empty);
|
||||
private readonly Func<TextWriter, Task> NullAsyncWrite = writer => writer.WriteAsync(string.Empty);
|
||||
|
||||
[Fact]
|
||||
public async Task WritingScopesRedirectContentWrittenToViewContextWriter()
|
||||
|
|
@ -311,7 +311,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
{ "baz", _nullRenderAsyncDelegate }
|
||||
};
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("body-content");
|
||||
page.BodyContent = new HtmlString("body-content");
|
||||
|
||||
// Act
|
||||
await page.ExecuteAsync();
|
||||
|
|
@ -335,7 +335,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
{ "baz", _nullRenderAsyncDelegate }
|
||||
};
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("body-content");
|
||||
page.BodyContent = new HtmlString("body-content");
|
||||
|
||||
// Act
|
||||
await page.ExecuteAsync();
|
||||
|
|
@ -444,7 +444,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
});
|
||||
page.Path = path;
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("some content");
|
||||
page.BodyContent = new HtmlString("some content");
|
||||
|
||||
// Act
|
||||
await page.ExecuteAsync();
|
||||
|
|
@ -464,7 +464,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
});
|
||||
page.Path = path;
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("some content");
|
||||
page.BodyContent = new HtmlString("some content");
|
||||
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||
{
|
||||
{ sectionName, _nullRenderAsyncDelegate }
|
||||
|
|
@ -490,7 +490,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
v.RenderSection(sectionA);
|
||||
v.RenderSection(sectionB);
|
||||
});
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("some content");
|
||||
page.BodyContent = new HtmlString("some content");
|
||||
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||
{
|
||||
{ sectionA, _nullRenderAsyncDelegate },
|
||||
|
|
@ -524,7 +524,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
v.Write(v.RenderSection("footer"));
|
||||
v.WriteLiteral("Layout end");
|
||||
});
|
||||
page.RenderBodyDelegateAsync = CreateAsyncWriteDelegate("body content" + Environment.NewLine);
|
||||
page.BodyContent = new HtmlString("body content" + Environment.NewLine);
|
||||
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||
{
|
||||
{
|
||||
|
|
@ -1181,11 +1181,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
new HtmlHelperOptions());
|
||||
}
|
||||
|
||||
private static Func<TextWriter, Task> CreateAsyncWriteDelegate(string value)
|
||||
{
|
||||
return async (writer) => await writer.WriteAsync(value);
|
||||
}
|
||||
|
||||
public abstract class TestableRazorPage : RazorPage
|
||||
{
|
||||
public TestableRazorPage()
|
||||
|
|
@ -1202,7 +1197,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
}
|
||||
|
||||
public HelperResult RenderBodyPublic()
|
||||
public IHtmlContent RenderBodyPublic()
|
||||
{
|
||||
return base.RenderBody();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,123 +283,6 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
Assert.Equal("Hello, world!", stringWriter.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy_CopiesContent_IfTargetTextWriterIsARazorTextWriterAndBuffering()
|
||||
{
|
||||
// Arrange
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
source.Write("Hello world");
|
||||
source.Write(new char[1], 0, 1);
|
||||
source.CopyTo(target);
|
||||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.BufferedWriter.Entries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Entries.Count);
|
||||
Assert.Same(source.BufferedWriter.Content, Assert.Single(target.BufferedWriter.Entries));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy_CopiesContent_IfTargetTextWriterIsARazorTextWriterAndNotBuffering()
|
||||
{
|
||||
// Arrange
|
||||
var unbufferedWriter = new Mock<TextWriter>();
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
target.Flush();
|
||||
source.Write("Hello world");
|
||||
source.Write(new[] { 'a', 'b', 'c', 'd' }, 1, 2);
|
||||
source.CopyTo(target);
|
||||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.BufferedWriter.Entries.Count);
|
||||
Assert.Empty(target.BufferedWriter.Entries);
|
||||
unbufferedWriter.Verify(v => v.Write("Hello world"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write("bc"), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy_WritesContent_IfTargetTextWriterIsNotARazorTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new StringWriter();
|
||||
var expected = "Hello world" + Environment.NewLine + "abc";
|
||||
|
||||
// Act
|
||||
source.WriteLine("Hello world");
|
||||
source.Write(new[] { 'x', 'a', 'b', 'c' }, 1, 3);
|
||||
source.CopyTo(target);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, target.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CopyAsync_WritesContent_IfTargetTextWriterIsARazorTextWriterAndBuffering()
|
||||
{
|
||||
// Arrange
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
source.WriteLine("Hello world");
|
||||
source.Write(new[] { 'x', 'a', 'b', 'c' }, 1, 3);
|
||||
await source.CopyToAsync(target);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, source.BufferedWriter.Entries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Entries.Count);
|
||||
Assert.Equal(source.BufferedWriter.Content, Assert.Single(target.BufferedWriter.Entries));
|
||||
}
|
||||
|
||||
//[Fact]
|
||||
// IHtmlContent currently does not support async writes. Hence disabling this test.
|
||||
public async Task CopyAsync_WritesContent_IfTargetTextWriterIsARazorTextWriterAndNotBuffering()
|
||||
{
|
||||
// Arrange
|
||||
var unbufferedWriter = new Mock<TextWriter>();
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
await target.FlushAsync();
|
||||
source.WriteLine("Hello from Asp.Net");
|
||||
await source.WriteAsync(new[] { 'x', 'y', 'z', 'u' }, 0, 3);
|
||||
await source.CopyToAsync(target);
|
||||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(3, source.BufferedWriter.Entries.Count);
|
||||
Assert.Empty(target.BufferedWriter.Content.ToString());
|
||||
unbufferedWriter.Verify(v => v.WriteAsync("Hello from Asp.Net"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteAsync(Environment.NewLine), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteAsync("xyz"), Times.Once());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CopyAsync_WritesContent_IfTargetTextWriterIsNotARazorTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var source = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var target = new StringWriter();
|
||||
var expected = "Hello world" + Environment.NewLine;
|
||||
|
||||
// Act
|
||||
source.Write("Hello ");
|
||||
await source.WriteLineAsync(new[] { 'w', 'o', 'r', 'l', 'd' });
|
||||
await source.CopyToAsync(target);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, target.ToString());
|
||||
}
|
||||
|
||||
private class TestClass
|
||||
{
|
||||
public override string ToString()
|
||||
|
|
|
|||
Loading…
Reference in New Issue