From 70bdb6eb3ee2eb49c04b4bed509fa5bbec95767e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 30 Nov 2015 11:24:25 -0800 Subject: [PATCH] Removing CopyTo from RazorTextWriter --- src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs | 9 +- src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs | 20 +-- .../RazorTextWriter.cs | 40 ++---- src/Microsoft.AspNet.Mvc.Razor/RazorView.cs | 4 +- .../RazorPageTest.cs | 21 ++-- .../RazorTextWriterTest.cs | 117 ------------------ 6 files changed, 33 insertions(+), 178 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs index 57e57b3166..a647e22641 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/IRazorPage.cs @@ -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; } /// - /// Gets or sets the action invoked to render the body. + /// Gets or sets the body content. /// - Func RenderBodyDelegateAsync { get; set; } + IHtmlContent BodyContent { get; set; } /// /// 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 were rendered, or /// the body was rendered if no sections were defined. /// - /// if one or more sections were not rendered or if no sections were + /// if one or more sections were not rendered or if no sections were /// defined and the body was not rendered. void EnsureRenderedBodyOrSections(); } diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs index 27b0c8b620..f730a171c8 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs @@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Mvc.Razor public ITempDataDictionary TempData => ViewContext?.TempData; /// - public Func RenderBodyDelegateAsync { get; set; } + public IHtmlContent BodyContent { get; set; } /// 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; } /// @@ -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. /// /// The HTML content to render. - 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; } /// @@ -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. diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorTextWriter.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorTextWriter.cs index 6cae8bb1ae..87a2fd57bc 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorTextWriter.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorTextWriter.cs @@ -48,6 +48,11 @@ namespace Microsoft.AspNet.Mvc.Razor /// public bool IsBuffering { get; private set; } = true; + /// + /// Gets the buffered content. + /// + 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. /// /// A that represents the asynchronous copy and flush operations. - 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(); - } - - /// - public void CopyTo(TextWriter writer) - { - writer = UnWrapRazorTextWriter(writer); - BufferedWriter.CopyTo(writer, HtmlEncoder); - } - - /// - 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(); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs index 46f2950740..6975a45b83 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs @@ -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); } } diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs index c1bde016d8..90361d1a56 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.Razor public class RazorPageTest { private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = writer => Task.FromResult(0); - private readonly Func NullAsyncWrite = CreateAsyncWriteDelegate(string.Empty); + private readonly Func 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 { { 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 { { 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 { { @@ -1181,11 +1181,6 @@ namespace Microsoft.AspNet.Mvc.Razor new HtmlHelperOptions()); } - private static Func 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(); } diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorTextWriterTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorTextWriterTest.cs index ded9882149..21c9be6ff2 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorTextWriterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorTextWriterTest.cs @@ -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(); - 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(); - 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()