Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Commit

Permalink
DecorateWriter does not get called for partial views rendered via
Browse files Browse the repository at this point in the history
Html.PartialAsync

* Introducing StringCollectionTextWriter to buffer the contents of
  PartialAsync
* Ensure DecorateWriter is called for partial views

Fixes #1266
  • Loading branch information
pranavkm committed Oct 12, 2014
1 parent 20eadb9 commit 18e11f5
Show file tree
Hide file tree
Showing 16 changed files with 647 additions and 235 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Collections.Generic;
using System.Diagnostics;

namespace Microsoft.AspNet.Mvc.Razor
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// Represents a hierarchy of strings and provides an enumerator that iterates over it as a sequence.
Expand Down
4 changes: 2 additions & 2 deletions src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,11 +330,11 @@ public string Name(string name)
public async Task<HtmlString> PartialAsync([NotNull] string partialViewName, object model,
ViewDataDictionary viewData)
{
using (var writer = new StringWriter(CultureInfo.CurrentCulture))
using (var writer = new StringCollectionTextWriter(Encoding.UTF8))
{
await RenderPartialCoreAsync(partialViewName, model, viewData, writer);

return new HtmlString(writer.ToString());
return new HtmlString(writer);
}
}

Expand Down
34 changes: 34 additions & 0 deletions src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlString.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.IO;

namespace Microsoft.AspNet.Mvc.Rendering
{
public class HtmlString
{
private static readonly HtmlString _empty = new HtmlString(string.Empty);

private readonly StringCollectionTextWriter _writer;
private readonly string _input;

public HtmlString(string input)
{
_input = input;
}

/// <summary>
/// Initializes a new instance of <see cref="HtmlString"/> that is backed by <paramref name="writer"/>.
/// </summary>
/// <param name="writer"></param>
public HtmlString([NotNull] StringCollectionTextWriter writer)
{
_writer = writer;
}

public static HtmlString Empty
{
get
Expand All @@ -22,8 +34,30 @@ public static HtmlString Empty
}
}

/// <summary>
/// Writes the value in this instance of <see cref="HtmlString"/> to the target <paramref name="targetWriter"/>.
/// </summary>
/// <param name="targetWriter">The <see cref="TextWriter"/> to write contents to.</param>
public void WriteTo(TextWriter targetWriter)
{
if (_writer != null)
{
_writer.CopyTo(targetWriter);
}
else
{
targetWriter.Write(_input);
}
}

/// <inheritdoc />
public override string ToString()
{
if (_writer != null)
{
return _writer.ToString();
}

return _input;
}
}
Expand Down
190 changes: 190 additions & 0 deletions src/Microsoft.AspNet.Mvc.Core/Rendering/StringCollectionTextWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.IO;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// A <see cref="TextWriter"/> that represents individual write operations as a sequence of strings.
/// </summary>
/// <remarks>
/// This is primarily designed to avoid creating large in-memory strings.
/// Refer to https://aspnetwebstack.codeplex.com/workitem/585 for more details.
/// </remarks>
public class StringCollectionTextWriter : TextWriter
{
private static readonly Task _completedTask = Task.FromResult(0);
private readonly Encoding _encoding;

/// <summary>
/// Creates a new instance of <see cref="StringCollectionTextWriter"/>.
/// </summary>
/// <param name="encoding">The character <see cref="Encoding"/> in which the output is written.</param>
public StringCollectionTextWriter(Encoding encoding)
{
_encoding = encoding;
Buffer = new BufferEntryCollection();
}

/// <inheritdoc />
public override Encoding Encoding
{
get { return _encoding; }
}

/// <summary>
/// A collection of entries buffered by this instance of <see cref="StringCollectionTextWriter"/>.
/// </summary>
public BufferEntryCollection Buffer { get; private set; }

/// <inheritdoc />
public override void Write(char value)
{
Buffer.Add(value.ToString());
}

/// <inheritdoc />
public override void Write([NotNull] char[] buffer, int index, int count)
{
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
if (count < 0 || (buffer.Length - index < count))
{
throw new ArgumentOutOfRangeException(nameof(count));
}

Buffer.Add(buffer, index, count);
}

/// <inheritdoc />
public override void Write(string value)
{
if (string.IsNullOrEmpty(value))
{
return;
}

Buffer.Add(value);
}

/// <inheritdoc />
public override Task WriteAsync(char value)
{
Write(value);
return _completedTask;
}

/// <inheritdoc />
public override Task WriteAsync([NotNull] char[] buffer, int index, int count)
{
Write(buffer, index, count);
return _completedTask;
}

/// <inheritdoc />
public override Task WriteAsync(string value)
{
Write(value);
return _completedTask;
}

/// <inheritdoc />
public override void WriteLine()
{
Buffer.Add(Environment.NewLine);
}

/// <inheritdoc />
public override void WriteLine(string value)
{
Write(value);
WriteLine();
}

/// <inheritdoc />
public override Task WriteLineAsync(char value)
{
WriteLine(value);
return _completedTask;
}

/// <inheritdoc />
public override Task WriteLineAsync(char[] value, int start, int offset)
{
WriteLine(value, start, offset);
return _completedTask;
}

/// <inheritdoc />
public override Task WriteLineAsync(string value)
{
WriteLine(value);
return _completedTask;
}

/// <inheritdoc />
public override Task WriteLineAsync()
{
WriteLine();
return _completedTask;
}

/// <inheritdoc />
public void CopyTo(TextWriter writer)
{
var targetStringCollectionWriter = writer as StringCollectionTextWriter;
if (targetStringCollectionWriter != null)
{
targetStringCollectionWriter.Buffer.Add(Buffer);
}
else
{
WriteList(writer, Buffer);
}
}

/// <inheritdoc />
public Task CopyToAsync(TextWriter writer)
{
var targetStringCollectionWriter = writer as StringCollectionTextWriter;
if (targetStringCollectionWriter != null)
{
targetStringCollectionWriter.Buffer.Add(Buffer);
}
else
{
return WriteListAsync(writer, Buffer);
}

return _completedTask;
}

/// <inheritdoc />
public override string ToString()
{
return string.Join(string.Empty, Buffer);
}

private static void WriteList(TextWriter writer, BufferEntryCollection values)
{
foreach (var value in values)
{
writer.Write(value);
}
}

private static async Task WriteListAsync(TextWriter writer, BufferEntryCollection values)
{
foreach (var value in values)
{
await writer.WriteAsync(value);
}
}
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public virtual void WriteTo(TextWriter writer, object value)
var htmlString = value as HtmlString;
if (htmlString != null)
{
writer.Write(htmlString.ToString());
writer.Write(htmlString);
}
else
{
Expand Down
Loading

0 comments on commit 18e11f5

Please sign in to comment.