Introducing IHtmlContent in Mvc.Razor.
- Changing HtmlHelper and HelperResult to implement IHtmlContent. - Introducing BufferedHtmlContent. - Making RazorPage handle only IHtmlContent and clearing out other types. - Making StringCollectionTextWriter use BufferedHtmlContent so that it can be returned where necessary. - Updating places which involve Write/Copy to pass in encoders. - The encoders are currently not being used during write. But when HtmlString is modified to carry encode metadata, the encoder can be used for writing. This is a perf optimization and hence not a part of this change. - Making TagHelperContent implement IHtmlContent.
This commit is contained in:
parent
933a13608f
commit
a02082397a
|
|
@ -3,28 +3,31 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a deferred write operation in a <see cref="RazorPage"/>.
|
||||
/// </summary>
|
||||
public class HelperResult
|
||||
public class HelperResult : IHtmlContent
|
||||
{
|
||||
private readonly Action<TextWriter> _action;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="HelperResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">The delegate to invoke when <see cref="WriteTo(TextWriter)"/> is called.</param>
|
||||
/// <param name="action">The delegate to invoke when
|
||||
/// <see cref="WriteTo(TextWriter, IHtmlEncoder)"/> is called.</param>
|
||||
public HelperResult([NotNull] Action<TextWriter> action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delegate to invoke when <see cref="WriteTo(TextWriter)"/> is called.
|
||||
/// Gets the delegate to invoke when <see cref="WriteTo(TextWriter, IHtmlEncoder)"/> is called.
|
||||
/// </summary>
|
||||
public Action<TextWriter> WriteAction
|
||||
{
|
||||
|
|
@ -35,7 +38,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// Method invoked to produce content from the <see cref="HelperResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param>
|
||||
public virtual void WriteTo([NotNull] TextWriter writer)
|
||||
/// <param name="encoder">The <see cref="IHtmlEncoder"/> to encode the content.</param>
|
||||
public virtual void WriteTo([NotNull] TextWriter writer, [NotNull] IHtmlEncoder encoder)
|
||||
{
|
||||
_action(writer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Antiforgery;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
|
@ -275,7 +276,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var stringCollectionTextWriter = writer as StringCollectionTextWriter;
|
||||
if (stringCollectionTextWriter != null)
|
||||
{
|
||||
stringCollectionTextWriter.CopyTo(tagHelperContentWrapperTextWriter);
|
||||
stringCollectionTextWriter.CopyTo(tagHelperContentWrapperTextWriter, HtmlEncoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -315,7 +316,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var tagHelperOutput = tagHelperExecutionContext.Output;
|
||||
var isTagNameNullOrWhitespace = string.IsNullOrWhiteSpace(tagHelperOutput.TagName);
|
||||
|
||||
WriteTagHelperContentTo(writer, tagHelperOutput.PreElement);
|
||||
WriteTo(writer, tagHelperOutput.PreElement);
|
||||
|
||||
if (!isTagNameNullOrWhitespace)
|
||||
{
|
||||
|
|
@ -345,22 +346,22 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
if (isTagNameNullOrWhitespace || !tagHelperOutput.SelfClosing)
|
||||
{
|
||||
WriteTagHelperContentTo(writer, tagHelperOutput.PreContent);
|
||||
WriteTo(writer, tagHelperOutput.PreContent);
|
||||
if (tagHelperOutput.IsContentModified)
|
||||
{
|
||||
WriteTagHelperContentTo(writer, tagHelperOutput.Content);
|
||||
WriteTo(writer, tagHelperOutput.Content);
|
||||
}
|
||||
else if (tagHelperExecutionContext.ChildContentRetrieved)
|
||||
{
|
||||
var childContent = await tagHelperExecutionContext.GetChildContentAsync();
|
||||
WriteTagHelperContentTo(writer, childContent);
|
||||
WriteTo(writer, childContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
await tagHelperExecutionContext.ExecuteChildContentAsync();
|
||||
}
|
||||
|
||||
WriteTagHelperContentTo(writer, tagHelperOutput.PostContent);
|
||||
WriteTo(writer, tagHelperOutput.PostContent);
|
||||
}
|
||||
|
||||
if (!isTagNameNullOrWhitespace && !tagHelperOutput.SelfClosing)
|
||||
|
|
@ -368,15 +369,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
writer.Write(string.Format(CultureInfo.InvariantCulture, "</{0}>", tagHelperOutput.TagName));
|
||||
}
|
||||
|
||||
WriteTagHelperContentTo(writer, tagHelperOutput.PostElement);
|
||||
}
|
||||
|
||||
private void WriteTagHelperContentTo(TextWriter writer, TagHelperContent content)
|
||||
{
|
||||
foreach (var entry in content)
|
||||
{
|
||||
writer.Write(entry);
|
||||
}
|
||||
WriteTo(writer, tagHelperOutput.PostElement);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -394,8 +387,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <param name="writer">The <see cref="TextWriter"/> instance to write to.</param>
|
||||
/// <param name="value">The <see cref="object"/> to write.</param>
|
||||
/// <remarks>
|
||||
/// <paramref name="value"/>s of type <see cref="HtmlString"/> are written without encoding and the
|
||||
/// <see cref="HelperResult.WriteTo(TextWriter)"/> is invoked for <see cref="HelperResult"/> types.
|
||||
/// <paramref name="value"/>s of type <see cref="IHtmlContent"/> are written using
|
||||
/// <see cref="IHtmlContent.WriteTo(TextWriter, IHtmlEncoder)"/>.
|
||||
/// For all other types, the encoded result of <see cref="object.ToString"/> is written to the
|
||||
/// <paramref name="writer"/>.
|
||||
/// </remarks>
|
||||
|
|
@ -415,8 +408,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// Otherwise writes <see cref="HtmlString"/> values as-is.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <paramref name="value"/>s of type <see cref="HtmlString"/> are written without encoding and the
|
||||
/// <see cref="HelperResult.WriteTo(TextWriter)"/> is invoked for <see cref="HelperResult"/> types.
|
||||
/// <paramref name="value"/>s of type <see cref="IHtmlContent"/> are written using
|
||||
/// <see cref="IHtmlContent.WriteTo(TextWriter, IHtmlEncoder)"/>.
|
||||
/// For all other types, the encoded result of <see cref="object.ToString"/> is written to the
|
||||
/// <paramref name="writer"/>.
|
||||
/// </remarks>
|
||||
|
|
@ -431,15 +424,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return;
|
||||
}
|
||||
|
||||
var helperResult = value as HelperResult;
|
||||
if (helperResult != null)
|
||||
{
|
||||
helperResult.WriteTo(writer);
|
||||
return;
|
||||
}
|
||||
|
||||
var htmlString = value as HtmlString;
|
||||
if (htmlString != null)
|
||||
var htmlContent = value as IHtmlContent;
|
||||
if (htmlContent != null)
|
||||
{
|
||||
if (escapeQuotes)
|
||||
{
|
||||
|
|
@ -447,9 +433,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
// an attribute value that may have been quoted with single quotes, must handle any double quotes
|
||||
// in the value. Writing the value out surrounded by double quotes.
|
||||
//
|
||||
// Do not combine following condition with check of escapeQuotes; htmlString.ToString() can be
|
||||
// expensive when the HtmlString is created with a StringCollectionTextWriter.
|
||||
var stringValue = htmlString.ToString();
|
||||
// Do not combine following condition with check of escapeQuotes; htmlContent.ToString() can be
|
||||
// expensive when the IHtmlContent is created with a BufferedHtmlContent.
|
||||
var stringValue = htmlContent.ToString();
|
||||
if (stringValue.Contains("\""))
|
||||
{
|
||||
writer.Write(stringValue.Replace("\"", """));
|
||||
|
|
@ -457,7 +443,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
}
|
||||
|
||||
htmlString.WriteTo(writer);
|
||||
htmlContent.WriteTo(writer, encoder);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ using System;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
|
|
@ -51,6 +53,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
private TextWriter TargetWriter { get; set; }
|
||||
|
||||
[RazorInject]
|
||||
private IHtmlEncoder HtmlEncoder { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(char value)
|
||||
{
|
||||
|
|
@ -63,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var htmlString = value as HtmlString;
|
||||
if (htmlString != null)
|
||||
{
|
||||
htmlString.WriteTo(TargetWriter);
|
||||
htmlString.WriteTo(TargetWriter, HtmlEncoder);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -196,14 +201,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public void CopyTo(TextWriter writer)
|
||||
{
|
||||
writer = UnWrapRazorTextWriter(writer);
|
||||
BufferedWriter.CopyTo(writer);
|
||||
BufferedWriter.CopyTo(writer, HtmlEncoder);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CopyToAsync(TextWriter writer)
|
||||
{
|
||||
writer = UnWrapRazorTextWriter(writer);
|
||||
return BufferedWriter.CopyToAsync(writer);
|
||||
return BufferedWriter.CopyToAsync(writer, HtmlEncoder);
|
||||
}
|
||||
|
||||
private static TextWriter UnWrapRazorTextWriter(TextWriter writer)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// <param name="value">The <see cref="object"/> to write.</param>
|
||||
/// <returns><paramref name="content"/> after the write operation has completed.</returns>
|
||||
/// <remarks>
|
||||
/// <paramref name="value"/>s of type <see cref="Rendering.HtmlString"/> are written without encoding and
|
||||
/// <see cref="HelperResult.WriteTo"/> is invoked for <see cref="HelperResult"/> types. For all other types,
|
||||
/// <paramref name="value"/>s of type <see cref="IHtmlContent"/> are written using
|
||||
/// <see cref="IHtmlContent.WriteTo(TextWriter, IHtmlEncoder)"/>.For all other types,
|
||||
/// the encoded result of <see cref="object.ToString"/> is written to the <paramref name="content"/>.
|
||||
/// </remarks>
|
||||
public static TagHelperContent Append(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
// 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 Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerable object collection which knows how to write itself.
|
||||
/// </summary>
|
||||
public class BufferedHtmlContent : IHtmlContent
|
||||
{
|
||||
private const int MaxCharToStringLength = 1024;
|
||||
// This is not List<IHtmlContent> because that would lead to boxing all strings to IHtmlContent
|
||||
// which is not space performant.
|
||||
// internal for testing.
|
||||
internal List<object> Entries { get; } = new List<object>();
|
||||
|
||||
/// <summary>
|
||||
/// Appends the string to the collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The <c>string</c> to be appended.</param>
|
||||
public void Append([NotNull] string value)
|
||||
{
|
||||
Entries.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a character array to the collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The character array to be appended.</param>
|
||||
/// <param name="index">The index from which the character array must be read.</param>
|
||||
/// <param name="count">The count till which the character array must be read.</param>
|
||||
/// <remarks>
|
||||
/// Splits the character array into strings of 1KB length and appends them.
|
||||
/// </remarks>
|
||||
public void Append([NotNull] char[] value, int index, int count)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
if (count < 0 || value.Length - index < count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
// Split large char arrays into 1KB strings.
|
||||
var currentCount = count;
|
||||
if (MaxCharToStringLength < currentCount)
|
||||
{
|
||||
currentCount = MaxCharToStringLength;
|
||||
}
|
||||
|
||||
Append(new string(value, index, currentCount));
|
||||
index += currentCount;
|
||||
count -= currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a <see cref="IHtmlContent"/> to the collection.
|
||||
/// </summary>
|
||||
/// <param name="htmlContent">The <see cref="IHtmlContent"/> to be appended.</param>
|
||||
public void Append([NotNull] IHtmlContent htmlContent)
|
||||
{
|
||||
Entries.Add(htmlContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all the entries from the collection.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Entries.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteTo([NotNull] TextWriter writer, [NotNull] IHtmlEncoder encoder)
|
||||
{
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
var entryAsString = entry as string;
|
||||
if (entryAsString != null)
|
||||
{
|
||||
writer.Write(entryAsString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only string, IHtmlContent values can be added to the buffer.
|
||||
((IHtmlContent)entry).WriteTo(writer, encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
WriteTo(writer, new HtmlEncoder());
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNet.Mvc.Rendering.Expressions;
|
||||
|
|
@ -420,7 +421,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<HtmlString> PartialAsync(
|
||||
public async Task<IHtmlContent> PartialAsync(
|
||||
[NotNull] string partialViewName,
|
||||
object model,
|
||||
ViewDataDictionary viewData)
|
||||
|
|
@ -428,8 +429,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
using (var writer = new StringCollectionTextWriter(Encoding.UTF8))
|
||||
{
|
||||
await RenderPartialCoreAsync(partialViewName, model, viewData, writer);
|
||||
|
||||
return new HtmlString(writer);
|
||||
return writer.Content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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.Html.Abstractions;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
|
|
@ -22,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<HtmlString> PartialAsync(
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName)
|
||||
{
|
||||
|
|
@ -41,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<HtmlString> PartialAsync(
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName,
|
||||
ViewDataDictionary viewData)
|
||||
|
|
@ -61,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
public static Task<HtmlString> PartialAsync(
|
||||
public static Task<IHtmlContent> PartialAsync(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName,
|
||||
object model)
|
||||
|
|
@ -83,7 +84,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// This method synchronously calls and blocks on
|
||||
/// <see cref="IHtmlHelper.PartialAsync(string, object, ViewDataDictionary)"/>
|
||||
/// </remarks>
|
||||
public static HtmlString Partial(
|
||||
public static IHtmlContent Partial(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName)
|
||||
{
|
||||
|
|
@ -105,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// This method synchronously calls and blocks on
|
||||
/// <see cref="IHtmlHelper.PartialAsync(string, object, ViewDataDictionary)"/>
|
||||
/// </remarks>
|
||||
public static HtmlString Partial(
|
||||
public static IHtmlContent Partial(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName,
|
||||
ViewDataDictionary viewData)
|
||||
|
|
@ -128,7 +129,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// This method synchronously calls and blocks on
|
||||
/// <see cref="IHtmlHelper.PartialAsync(string, object, ViewDataDictionary)"/>
|
||||
/// </remarks>
|
||||
public static HtmlString Partial(
|
||||
public static IHtmlContent Partial(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName,
|
||||
object model)
|
||||
|
|
@ -152,7 +153,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// This method synchronously calls and blocks on
|
||||
/// <see cref="IHtmlHelper.PartialAsync(string, object, ViewDataDictionary)"/>
|
||||
/// </remarks>
|
||||
public static HtmlString Partial(
|
||||
public static IHtmlContent Partial(
|
||||
[NotNull] this IHtmlHelper htmlHelper,
|
||||
[NotNull] string partialViewName,
|
||||
object model,
|
||||
|
|
|
|||
|
|
@ -2,33 +2,31 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class HtmlString
|
||||
/// <summary>
|
||||
/// String content which knows how to write itself.
|
||||
/// </summary>
|
||||
public class HtmlString : IHtmlContent
|
||||
{
|
||||
private static readonly HtmlString _empty = new HtmlString(string.Empty);
|
||||
|
||||
private readonly StringCollectionTextWriter _writer;
|
||||
private readonly string _input;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new instance of <see cref="HtmlString"/>.
|
||||
/// </summary>
|
||||
/// <param name="input"><c>string</c>to initialize <see cref="HtmlString"/>.</param>
|
||||
public HtmlString(string input)
|
||||
{
|
||||
_input = input;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="HtmlString"/> that is backed by <paramref name="writer"/>.
|
||||
/// Returns an <see cref="HtmlString"/> with empty content.
|
||||
/// </summary>
|
||||
/// <param name="writer">
|
||||
/// A <see cref="StringCollectionTextWriter"/> instance to back this <see cref="HtmlString"/>.
|
||||
/// </param>
|
||||
public HtmlString([NotNull] StringCollectionTextWriter writer)
|
||||
{
|
||||
_writer = writer;
|
||||
}
|
||||
|
||||
public static HtmlString Empty
|
||||
{
|
||||
get
|
||||
|
|
@ -39,29 +37,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
/// <summary>
|
||||
/// Writes the value in this instance of <see cref="HtmlString"/> to the target
|
||||
/// <paramref name="targetWriter"/>.
|
||||
/// <paramref name="writer"/>.
|
||||
/// </summary>
|
||||
/// <param name="targetWriter">The <see cref="TextWriter"/> to write contents to.</param>
|
||||
public void WriteTo(TextWriter targetWriter)
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to write contents to.</param>
|
||||
/// <param name="encoder">The <see cref="IHtmlEncoder"/> with which the output must be encoded.</param>
|
||||
public void WriteTo(TextWriter writer, IHtmlEncoder encoder)
|
||||
{
|
||||
if (_writer != null)
|
||||
{
|
||||
_writer.CopyTo(targetWriter);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetWriter.Write(_input);
|
||||
}
|
||||
writer.Write(_input);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (_writer != null)
|
||||
{
|
||||
return _writer.ToString();
|
||||
}
|
||||
|
||||
return _input;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -505,7 +506,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// A <see cref="Task"/> that on completion returns a new <see cref="HtmlString"/> containing
|
||||
/// the created HTML.
|
||||
/// </returns>
|
||||
Task<HtmlString> PartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData);
|
||||
Task<IHtmlContent> PartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an <input> element of type "password" for the specified <paramref name="expression"/>.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
|
|
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public StringCollectionTextWriter(Encoding encoding)
|
||||
{
|
||||
_encoding = encoding;
|
||||
Buffer = new BufferEntryCollection();
|
||||
Content = new BufferedHtmlContent();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -41,12 +42,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// A collection of entries buffered by this instance of <see cref="StringCollectionTextWriter"/>.
|
||||
/// </summary>
|
||||
// internal for testing purposes.
|
||||
internal BufferEntryCollection Buffer { get; }
|
||||
internal BufferedHtmlContent Content { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(char value)
|
||||
{
|
||||
Buffer.Add(value.ToString());
|
||||
Content.Append(value.ToString());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -61,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
||||
Buffer.Add(buffer, index, count);
|
||||
Content.Append(buffer, index, count);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -72,7 +73,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return;
|
||||
}
|
||||
|
||||
Buffer.Add(value);
|
||||
Content.Append(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -99,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public override void WriteLine()
|
||||
{
|
||||
Buffer.Add(Environment.NewLine);
|
||||
Content.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -137,56 +138,41 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(TextWriter writer)
|
||||
/// <summary>
|
||||
/// If the specified <paramref name="writer"/> is a <see cref="StringCollectionTextWriter"/> the contents
|
||||
/// are copied. It is just written to the <paramref name="writer"/> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to which the content must be copied/written.</param>
|
||||
/// <param name="encoder">The <see cref="IHtmlEncoder"/> to encode the copied/written content.</param>
|
||||
public void CopyTo(TextWriter writer, IHtmlEncoder encoder)
|
||||
{
|
||||
var targetStringCollectionWriter = writer as StringCollectionTextWriter;
|
||||
if (targetStringCollectionWriter != null)
|
||||
{
|
||||
targetStringCollectionWriter.Buffer.Add(Buffer);
|
||||
targetStringCollectionWriter.Content.Append(Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteList(writer, Buffer);
|
||||
Content.WriteTo(writer, encoder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CopyToAsync(TextWriter writer)
|
||||
/// <summary>
|
||||
/// If the specified <paramref name="writer"/> is a <see cref="StringCollectionTextWriter"/> the contents
|
||||
/// are copied. It is just written to the <paramref name="writer"/> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to which the content must be copied/written.</param>
|
||||
/// <param name="encoder">The <see cref="IHtmlEncoder"/> to encode the copied/written content.</param>
|
||||
public Task CopyToAsync(TextWriter writer, IHtmlEncoder encoder)
|
||||
{
|
||||
var targetStringCollectionWriter = writer as StringCollectionTextWriter;
|
||||
if (targetStringCollectionWriter != null)
|
||||
{
|
||||
targetStringCollectionWriter.Buffer.Add(Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WriteListAsync(writer, Buffer);
|
||||
}
|
||||
|
||||
CopyTo(writer, encoder);
|
||||
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);
|
||||
}
|
||||
return string.Join(string.Empty, Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,10 +11,10 @@
|
|||
"dependencies": {
|
||||
"Microsoft.AspNet.Antiforgery": "1.0.0-*",
|
||||
"Microsoft.AspNet.Diagnostics.Abstractions": "1.0.0-*",
|
||||
"Microsoft.AspNet.Html.Abstractions": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.Core": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.DataAnnotations": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-*",
|
||||
"Microsoft.Framework.BufferEntryCollection.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.ClosedGenericMatcher.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.CopyOnWriteDictionary.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" },
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <summary>
|
||||
/// Copies the buffered content to the <paramref name="writer"/>.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer to copy the contents to.</param>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to copy the contents to.</param>
|
||||
void CopyTo(TextWriter writer);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously copies the buffered content to the <paramref name="writer"/>.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer to copy the contents to.</param>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to copy the contents to.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the copy operation.</returns>
|
||||
Task CopyToAsync(TextWriter writer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -723,7 +723,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var page = CreatePage(p =>
|
||||
{
|
||||
p.Write(new HtmlString("Hello world"));
|
||||
p.Write(new HtmlString(stringCollectionWriter));
|
||||
p.Write(stringCollectionWriter.Content);
|
||||
});
|
||||
page.ViewContext.Writer = writer;
|
||||
|
||||
|
|
@ -731,11 +731,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
await page.ExecuteAsync();
|
||||
|
||||
// Assert
|
||||
var buffer = writer.BufferedWriter.Buffer;
|
||||
Assert.Equal(3, buffer.BufferEntries.Count);
|
||||
Assert.Equal("Hello world", buffer.BufferEntries[0]);
|
||||
Assert.Equal("text1", buffer.BufferEntries[1]);
|
||||
Assert.Equal("text2", buffer.BufferEntries[2]);
|
||||
var buffer = writer.BufferedWriter.Content.Entries;
|
||||
Assert.Equal(3, buffer.Count);
|
||||
Assert.Equal("Hello world", buffer[0]);
|
||||
Assert.Equal("text1", buffer[1]);
|
||||
Assert.Equal("text2", buffer[2]);
|
||||
}
|
||||
|
||||
public static TheoryData<TagHelperOutput, string> WriteTagHelper_InputData
|
||||
|
|
@ -1389,7 +1389,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
private static Action<TextWriter> CreateBodyAction(string value)
|
||||
{
|
||||
return writer => writer.Write(value);
|
||||
return (writer) => writer.Write(value);
|
||||
}
|
||||
|
||||
public abstract class TestableRazorPage : RazorPage
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.Write('m');
|
||||
|
||||
// Assert
|
||||
Assert.Equal<object>(expected, writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Equal(expected, writer.BufferedWriter.Content.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -55,7 +55,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.Write(2.718m);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Empty(writer.BufferedWriter.Content.Entries);
|
||||
foreach (var item in expected)
|
||||
{
|
||||
unbufferedWriter.Verify(v => v.Write(item), Times.Once());
|
||||
|
|
@ -81,7 +81,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync(buffer1);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Empty(writer.BufferedWriter.Content.Entries);
|
||||
unbufferedWriter.Verify(v => v.Write('x'), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write(buffer1, 1, 2), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write(buffer1, 0, 4), Times.Once());
|
||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync("gh");
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Empty(writer.BufferedWriter.Content.Entries);
|
||||
unbufferedWriter.Verify(v => v.Write("a"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteLine("ab"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteAsync("ef"), Times.Once());
|
||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Equal(expected, writer.BufferedWriter.Content.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -146,7 +146,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Empty(writer.BufferedWriter.Content.ToString());
|
||||
unbufferedWriter.Verify(v => v.Write("False"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write("1.1"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write("3"), Times.Once());
|
||||
|
|
@ -168,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync(input3.Array, input3.Offset, input3.Count);
|
||||
|
||||
// Assert
|
||||
var buffer = writer.BufferedWriter.Buffer.BufferEntries;
|
||||
var buffer = writer.BufferedWriter.Content.Entries;
|
||||
Assert.Equal(4, buffer.Count);
|
||||
Assert.Equal("bcd", buffer[0]);
|
||||
Assert.Equal("ef", buffer[1]);
|
||||
|
|
@ -188,7 +188,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync();
|
||||
|
||||
// Assert
|
||||
var actual = writer.BufferedWriter.Buffer.BufferEntries;
|
||||
var actual = writer.BufferedWriter.Content.Entries;
|
||||
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync(input4);
|
||||
|
||||
// Assert
|
||||
var actual = writer.BufferedWriter.Buffer.BufferEntries;
|
||||
var actual = writer.BufferedWriter.Content.Entries;
|
||||
Assert.Equal<object>(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||
}
|
||||
|
||||
|
|
@ -228,9 +228,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Same(source.BufferedWriter.Buffer.BufferEntries, target.BufferedWriter.Buffer.BufferEntries[0]);
|
||||
Assert.Equal(2, source.BufferedWriter.Content.Entries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Content.Entries.Count);
|
||||
Assert.Same(source.BufferedWriter.Content, Assert.Single(target.BufferedWriter.Content.Entries));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -249,8 +249,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Empty(target.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Equal(2, source.BufferedWriter.Content.Entries.Count);
|
||||
Assert.Empty(target.BufferedWriter.Content.ToString());
|
||||
unbufferedWriter.Verify(v => v.Write("Hello world"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.Write("bc"), Times.Once());
|
||||
}
|
||||
|
|
@ -286,12 +286,13 @@ abc";
|
|||
await source.CopyToAsync(target);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, source.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Same(source.BufferedWriter.Buffer.BufferEntries, target.BufferedWriter.Buffer.BufferEntries[0]);
|
||||
Assert.Equal(3, source.BufferedWriter.Content.Entries.Count);
|
||||
Assert.Equal(1, target.BufferedWriter.Content.Entries.Count);
|
||||
Assert.Equal(source.BufferedWriter.Content, Assert.Single(target.BufferedWriter.Content.Entries));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
//[Fact]
|
||||
// IHtmlContent currently does not support async writes. Hence disabling this test.
|
||||
public async Task CopyAsync_WritesContent_IfTargetTextWriterIsARazorTextWriterAndNotBuffering()
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -307,8 +308,8 @@ abc";
|
|||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(3, source.BufferedWriter.Buffer.BufferEntries.Count);
|
||||
Assert.Empty(target.BufferedWriter.Buffer.BufferEntries);
|
||||
Assert.Equal(3, source.BufferedWriter.Content.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());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
// 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 Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.Framework.WebEncoders;
|
||||
using Microsoft.Framework.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class BufferedHtmlContentTest
|
||||
{
|
||||
[Fact]
|
||||
public void AppendString_AppendsAString()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
|
||||
// Act
|
||||
content.Append("Hello");
|
||||
|
||||
// Assert
|
||||
var result = Assert.Single(content.Entries);
|
||||
Assert.IsType(typeof(string), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppendCharArray_AppendsAsString()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
|
||||
// Act
|
||||
content.Append(new char[] { 'h', 'e', 'l', 'l', 'o' }, 0, 5);
|
||||
|
||||
// Assert
|
||||
var result = Assert.Single(content.Entries);
|
||||
Assert.IsType(typeof(string), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppendIHtmlContent_AppendsAsIs()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
var writer = new StringWriter();
|
||||
|
||||
// Act
|
||||
content.Append(new TestHtmlContent("Hello"));
|
||||
|
||||
// Assert
|
||||
var result = Assert.Single(content.Entries);
|
||||
var testHtmlContent = Assert.IsType<TestHtmlContent>(result);
|
||||
testHtmlContent.WriteTo(writer, new CommonTestEncoder());
|
||||
Assert.Equal("Written from TestHtmlContent: Hello", writer.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanAppendMultipleItems()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
|
||||
// Act
|
||||
content.Append(new TestHtmlContent("hello"));
|
||||
content.Append("Test");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, content.Entries.Count);
|
||||
Assert.Equal("Written from TestHtmlContent: hello", content.Entries[0].ToString());
|
||||
Assert.Equal("Test", content.Entries[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clear_DeletesAllItems()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
content.Append(new TestHtmlContent("hello"));
|
||||
content.Append("Test");
|
||||
|
||||
// Act
|
||||
content.Clear();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, content.Entries.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTo_WritesAllItems()
|
||||
{
|
||||
// Arrange
|
||||
var content = new BufferedHtmlContent();
|
||||
var writer = new StringWriter();
|
||||
content.Append(new TestHtmlContent("Hello"));
|
||||
content.Append("Test");
|
||||
|
||||
// Act
|
||||
content.WriteTo(writer, new CommonTestEncoder());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, content.Entries.Count);
|
||||
Assert.Equal("Written from TestHtmlContent: HelloTest", writer.ToString());
|
||||
}
|
||||
|
||||
private class TestHtmlContent : IHtmlContent
|
||||
{
|
||||
private string _content;
|
||||
|
||||
public TestHtmlContent(string content)
|
||||
{
|
||||
_content = content;
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer, IHtmlEncoder encoder)
|
||||
{
|
||||
writer.Write(ToString());
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Written from TestHtmlContent: " + _content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ using System.Globalization;
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
|
|
@ -1082,7 +1083,7 @@ Environment.NewLine;
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<HtmlString> PartialAsync(
|
||||
public Task<IHtmlContent> PartialAsync(
|
||||
[NotNull] string partialViewName,
|
||||
object model,
|
||||
ViewDataDictionary viewData)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -11,12 +12,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
public class HtmlHelperPartialExtensionsTest
|
||||
{
|
||||
public static TheoryData<Func<IHtmlHelper, HtmlString>> PartialExtensionMethods
|
||||
public static TheoryData<Func<IHtmlHelper, IHtmlContent>> PartialExtensionMethods
|
||||
{
|
||||
get
|
||||
{
|
||||
var vdd = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
return new TheoryData<Func<IHtmlHelper, HtmlString>>
|
||||
return new TheoryData<Func<IHtmlHelper, IHtmlContent>>
|
||||
{
|
||||
helper => helper.Partial("test"),
|
||||
helper => helper.Partial("test", new object()),
|
||||
|
|
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
[Theory]
|
||||
[MemberData(nameof(PartialExtensionMethods))]
|
||||
public void PartialMethods_DoesNotWrapThrownException(Func<IHtmlHelper, HtmlString> partialMethod)
|
||||
public void PartialMethods_DoesNotWrapThrownException(Func<IHtmlHelper, IHtmlContent> partialMethod)
|
||||
{
|
||||
// Arrange
|
||||
var expected = new InvalidOperationException();
|
||||
|
|
@ -60,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
};
|
||||
var helper = new Mock<IHtmlHelper>(MockBehavior.Strict);
|
||||
helper.Setup(h => h.PartialAsync("test", model, null))
|
||||
.Returns(Task.FromResult(expected))
|
||||
.Returns(Task.FromResult((IHtmlContent)expected))
|
||||
.Verifiable();
|
||||
helper.SetupGet(h => h.ViewData)
|
||||
.Returns(viewData);
|
||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var model = new object();
|
||||
var helper = new Mock<IHtmlHelper>(MockBehavior.Strict);
|
||||
helper.Setup(h => h.PartialAsync("test", model, null))
|
||||
.Returns(Task.FromResult(expected))
|
||||
.Returns(Task.FromResult((IHtmlContent)expected))
|
||||
.Verifiable();
|
||||
|
||||
// Act
|
||||
|
|
@ -105,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
};
|
||||
var helper = new Mock<IHtmlHelper>(MockBehavior.Strict);
|
||||
helper.Setup(h => h.PartialAsync("test", model, passedInViewData))
|
||||
.Returns(Task.FromResult(expected))
|
||||
.Returns(Task.FromResult((IHtmlContent)expected))
|
||||
.Verifiable();
|
||||
helper.SetupGet(h => h.ViewData)
|
||||
.Returns(viewData);
|
||||
|
|
@ -127,7 +128,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var passedInViewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||
var helper = new Mock<IHtmlHelper>(MockBehavior.Strict);
|
||||
helper.Setup(h => h.PartialAsync("test", passedInModel, passedInViewData))
|
||||
.Returns(Task.FromResult(expected))
|
||||
.Returns(Task.FromResult((IHtmlContent)expected))
|
||||
.Verifiable();
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// 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 Microsoft.Framework.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
{
|
||||
public class HtmlStringTest
|
||||
{
|
||||
[Fact]
|
||||
public void WriteTo_WritesToTheSpecifiedWriter()
|
||||
{
|
||||
// Arrange
|
||||
var expectedText = "Some Text";
|
||||
var content = new HtmlString(expectedText);
|
||||
var writer = new StringWriter();
|
||||
|
||||
// Act
|
||||
content.WriteTo(writer, new CommonTestEncoder());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedText, writer.ToString());
|
||||
writer.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromEncodedText_DoesNotEncodeOnWrite()
|
||||
{
|
||||
// Arrange
|
||||
var expectedText = "Hello";
|
||||
|
||||
// Act
|
||||
var content = new HtmlString(expectedText);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedText, content.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Empty_ReturnsEmptyString()
|
||||
{
|
||||
// Arrange & Act
|
||||
var content = HtmlString.Empty;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, content.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsText()
|
||||
{
|
||||
// Arrange
|
||||
var expectedText = "Hello";
|
||||
var content = new HtmlString(expectedText);
|
||||
|
||||
// Act
|
||||
var result = content.ToString();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedText, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Rendering
|
||||
|
|
@ -31,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
writer.Write('m');
|
||||
|
||||
// Assert
|
||||
Assert.Equal<object>(expected, writer.Buffer.BufferEntries);
|
||||
Assert.Equal(expected, writer.Content.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -49,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.Buffer.BufferEntries);
|
||||
Assert.Equal(expected, writer.Content.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -67,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
await writer.WriteLineAsync(input3.Array, input3.Offset, input3.Count);
|
||||
|
||||
// Assert
|
||||
var buffer = writer.Buffer.BufferEntries;
|
||||
var buffer = writer.Content.Entries;
|
||||
Assert.Equal(4, buffer.Count);
|
||||
Assert.Equal("bcd", buffer[0]);
|
||||
Assert.Equal("ef", buffer[1]);
|
||||
|
|
@ -87,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
await writer.WriteLineAsync();
|
||||
|
||||
// Assert
|
||||
var actual = writer.Buffer.BufferEntries;
|
||||
var actual = writer.Content.Entries;
|
||||
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +110,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
await writer.WriteLineAsync(input4);
|
||||
|
||||
// Assert
|
||||
var actual = writer.Buffer.BufferEntries;
|
||||
Assert.Equal<object>(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||
var actual = writer.Content.Entries;
|
||||
Assert.Equal(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -123,13 +124,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
// Act
|
||||
source.Write("Hello world");
|
||||
source.Write(new char[1], 0, 1);
|
||||
source.CopyTo(target);
|
||||
source.CopyTo(target, new CommonTestEncoder());
|
||||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.Buffer.BufferEntries.Count);
|
||||
Assert.Equal(1, target.Buffer.BufferEntries.Count);
|
||||
Assert.Same(source.Buffer.BufferEntries, target.Buffer.BufferEntries[0]);
|
||||
Assert.Equal(2, source.Content.Entries.Count);
|
||||
Assert.Equal(1, target.Content.Entries.Count);
|
||||
var result = Assert.Single(target.Content.Entries);
|
||||
var bufferedHtmlContent = Assert.IsType<BufferedHtmlContent>(result);
|
||||
Assert.Same(source.Content.Entries, bufferedHtmlContent.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -143,7 +146,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
// Act
|
||||
source.WriteLine("Hello world");
|
||||
source.Write(new[] { 'x', 'a', 'b', 'c' }, 1, 3);
|
||||
source.CopyTo(target);
|
||||
source.CopyTo(target, new CommonTestEncoder());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, target.ToString());
|
||||
|
|
|
|||
Loading…
Reference in New Issue