parent
1f76b3c7b7
commit
ff34c5404a
|
|
@ -0,0 +1,17 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates and manages the lifetime of <see cref="RazorBufferSegment"/> instances.
|
||||||
|
/// </summary>
|
||||||
|
public interface IRazorBufferScope
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="RazorBufferSegment"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The <see cref="RazorBufferSegment"/>.</returns>
|
||||||
|
RazorBufferSegment GetSegment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
// 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 Microsoft.Extensions.MemoryPool;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="IRazorBufferScope"/> that uses pooled memory.
|
||||||
|
/// </summary>
|
||||||
|
public class MemoryPoolRazorBufferScope : IRazorBufferScope, IDisposable
|
||||||
|
{
|
||||||
|
private const int SegmentSize = 1024;
|
||||||
|
private readonly IArraySegmentPool<RazorValue> _pool;
|
||||||
|
private List<LeasedArraySegment<RazorValue>> _leased;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="MemoryPoolRazorBufferScope"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pool">The <see cref="IArraySegmentPool{RazorValue}"/> for creating
|
||||||
|
/// <see cref="RazorValue"/> instances.</param>
|
||||||
|
public MemoryPoolRazorBufferScope(IArraySegmentPool<RazorValue> pool)
|
||||||
|
{
|
||||||
|
_pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public RazorBufferSegment GetSegment()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(typeof(MemoryPoolRazorBufferScope).FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_leased == null)
|
||||||
|
{
|
||||||
|
_leased = new List<LeasedArraySegment<RazorValue>>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeasedArraySegment<RazorValue> segment = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
segment = _pool.Lease(SegmentSize);
|
||||||
|
_leased.Add(segment);
|
||||||
|
}
|
||||||
|
catch when (segment != null)
|
||||||
|
{
|
||||||
|
segment.Owner.Return(segment);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RazorBufferSegment(segment.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
if (_leased == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < _leased.Count; i++)
|
||||||
|
{
|
||||||
|
var segment = _leased[i];
|
||||||
|
Array.Clear(segment.Data.Array, segment.Data.Offset, segment.Data.Count);
|
||||||
|
segment.Owner.Return(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_leased.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IHtmlContentBuilder"/> that is backed by a buffer provided by <see cref="IRazorBufferScope"/>.
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerDisplay("{DebuggerToString()}")]
|
||||||
|
public class RazorBuffer : IHtmlContentBuilder
|
||||||
|
{
|
||||||
|
private readonly IRazorBufferScope _bufferScope;
|
||||||
|
private readonly string _name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorBuffer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bufferScope">The <see cref="IRazorBufferScope"/>.</param>
|
||||||
|
/// <param name="name">A name to identify this instance.</param>
|
||||||
|
public RazorBuffer(IRazorBufferScope bufferScope, string name)
|
||||||
|
{
|
||||||
|
if (bufferScope == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(bufferScope));
|
||||||
|
}
|
||||||
|
|
||||||
|
_bufferScope = bufferScope;
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the backing buffer.
|
||||||
|
/// </summary>
|
||||||
|
public IList<RazorBufferSegment> BufferSegments { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the count of entries in the last element of <see cref="BufferSegments"/>.
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentCount { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IHtmlContentBuilder Append(string unencoded)
|
||||||
|
{
|
||||||
|
if (unencoded == null)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendValue(new RazorValue(unencoded));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IHtmlContentBuilder Append(IHtmlContent content)
|
||||||
|
{
|
||||||
|
if (content == null)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendValue(new RazorValue(content));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IHtmlContentBuilder AppendHtml(string encoded)
|
||||||
|
{
|
||||||
|
if (encoded == null)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = new HtmlString(encoded);
|
||||||
|
AppendValue(new RazorValue(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppendValue(RazorValue value)
|
||||||
|
{
|
||||||
|
RazorBufferSegment segment;
|
||||||
|
if (BufferSegments == null)
|
||||||
|
{
|
||||||
|
BufferSegments = new List<RazorBufferSegment>(1);
|
||||||
|
segment = _bufferScope.GetSegment();
|
||||||
|
BufferSegments.Add(segment);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segment = BufferSegments[BufferSegments.Count - 1];
|
||||||
|
if (CurrentCount == segment.Data.Count)
|
||||||
|
{
|
||||||
|
segment = _bufferScope.GetSegment();
|
||||||
|
BufferSegments.Add(segment);
|
||||||
|
CurrentCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
segment.Data.Array[segment.Data.Offset + CurrentCount] = value;
|
||||||
|
CurrentCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IHtmlContentBuilder Clear()
|
||||||
|
{
|
||||||
|
if (BufferSegments != null)
|
||||||
|
{
|
||||||
|
CurrentCount = 0;
|
||||||
|
BufferSegments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
if (BufferSegments == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var htmlTextWriter = writer as HtmlTextWriter;
|
||||||
|
if (htmlTextWriter != null)
|
||||||
|
{
|
||||||
|
htmlTextWriter.Write(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < BufferSegments.Count; i++)
|
||||||
|
{
|
||||||
|
var segment = BufferSegments[i];
|
||||||
|
var count = i == BufferSegments.Count - 1 ? CurrentCount : segment.Data.Count;
|
||||||
|
|
||||||
|
for (var j = 0; j < count; j++)
|
||||||
|
{
|
||||||
|
var value = segment.Data.Array[segment.Data.Offset + j];
|
||||||
|
value.WriteTo(writer, encoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DebuggerToString() => _name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulates a <see cref="ArraySegment{RazorValue}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public struct RazorBufferSegment
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorBufferSegment"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The <see cref="ArraySegment{RazorValue}"/> to encapsulate.</param>
|
||||||
|
public RazorBufferSegment(ArraySegment<RazorValue> data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="ArraySegment{RazorValue}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public ArraySegment<RazorValue> Data { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encapsulates a string or <see cref="IHtmlContent"/> value.
|
||||||
|
/// </summary>
|
||||||
|
public struct RazorValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorValue"/> with a <c>string</c> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
public RazorValue(string value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="RazorValue"/> with a <see cref="IHtmlContent"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The <see cref="IHtmlContent"/>.</param>
|
||||||
|
public RazorValue(IHtmlContent content)
|
||||||
|
{
|
||||||
|
Value = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value.
|
||||||
|
/// </summary>
|
||||||
|
public object Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the <see cref="Value"/> by encoding it with the specified <paramref name="encoder"/> to the
|
||||||
|
/// specified <paramref name="writer"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="TextWriter"/> to write the value to.</param>
|
||||||
|
/// <param name="encoder">The <see cref="HtmlEncoder"/> which encodes the content to be written.</param>
|
||||||
|
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
if (Value == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringValue = Value as string;
|
||||||
|
if (stringValue != null)
|
||||||
|
{
|
||||||
|
writer.Write(stringValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Assert(Value is IHtmlContent);
|
||||||
|
var htmlContentValue = (IHtmlContent)Value;
|
||||||
|
htmlContentValue.WriteTo(writer, encoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.Razor;
|
using Microsoft.AspNet.Mvc.Razor;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Directives;
|
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||||
|
|
@ -14,6 +15,7 @@ using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.CompilationAbstractions;
|
using Microsoft.Extensions.CompilationAbstractions;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.MemoryPool;
|
||||||
using Microsoft.Extensions.OptionsModel;
|
using Microsoft.Extensions.OptionsModel;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
@ -157,6 +159,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
||||||
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
||||||
|
|
||||||
|
services.TryAddSingleton<IArraySegmentPool<RazorValue>, DefaultArraySegmentPool<RazorValue>>();
|
||||||
|
services.TryAddScoped<IRazorBufferScope, MemoryPoolRazorBufferScope>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,176 @@
|
||||||
|
// 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.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="HtmlTextWriter"/> implementation which writes to an <see cref="IHtmlContentBuilder"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public class HtmlContentWrapperTextWriter : HtmlTextWriter
|
||||||
|
{
|
||||||
|
private const int MaxCharToStringLength = 1024;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HtmlContentWrapperTextWriter"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="contentBuilder">The <see cref="IHtmlContentBuilder"/> to write to.</param>
|
||||||
|
/// <param name="encoding">The <see cref="Encoding"/> in which output is written.</param>
|
||||||
|
public HtmlContentWrapperTextWriter(IHtmlContentBuilder contentBuilder, Encoding encoding)
|
||||||
|
{
|
||||||
|
if (contentBuilder == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(contentBuilder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBuilder = contentBuilder;
|
||||||
|
Encoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="IHtmlContentBuilder"/> this <see cref="HtmlContentWrapperTextWriter"/> writes to.
|
||||||
|
/// </summary>
|
||||||
|
public IHtmlContentBuilder ContentBuilder { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Encoding Encoding { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Write(char value)
|
||||||
|
{
|
||||||
|
Write(value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Write(char[] buffer, int index, int count)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0 || (index + count > buffer.Length))
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
// Split large char arrays into 1KB strings.
|
||||||
|
var currentCount = count;
|
||||||
|
if (MaxCharToStringLength < currentCount)
|
||||||
|
{
|
||||||
|
currentCount = MaxCharToStringLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(new string(buffer, index, currentCount));
|
||||||
|
index += currentCount;
|
||||||
|
count -= currentCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Write(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBuilder.Append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Write(IHtmlContent value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentBuilder.Append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteAsync(char value)
|
||||||
|
{
|
||||||
|
Write(value.ToString());
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteAsync(char[] buffer, int index, int count)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(buffer, index, count);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteAsync(string value)
|
||||||
|
{
|
||||||
|
Write(value);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteLine()
|
||||||
|
{
|
||||||
|
Write(Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteLine(string value)
|
||||||
|
{
|
||||||
|
Write(value);
|
||||||
|
WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteLineAsync(char value)
|
||||||
|
{
|
||||||
|
WriteLine(value);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteLineAsync(char[] value, int start, int offset)
|
||||||
|
{
|
||||||
|
WriteLine(value, start, offset);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteLineAsync(string value)
|
||||||
|
{
|
||||||
|
WriteLine(value);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task WriteLineAsync()
|
||||||
|
{
|
||||||
|
WriteLine();
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,20 +7,15 @@ using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Html;
|
using Microsoft.AspNet.Html;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="HtmlTextWriter"/> that is backed by a unbuffered writer (over the Response stream) and a buffered
|
/// An <see cref="HtmlTextWriter"/> that is backed by a unbuffered writer (over the Response stream) and a buffered
|
||||||
/// <see cref="StringCollectionTextWriter"/>. When <c>Flush</c> or <c>FlushAsync</c> is invoked, the writer
|
/// <see cref="IHtmlContentBuilder"/>. When <c>Flush</c> or <c>FlushAsync</c> is invoked, the writer
|
||||||
/// copies all content from the buffered writer to the unbuffered one and switches to writing to the unbuffered
|
/// copies all content from the buffered writer to the unbuffered one and switches to writing to the unbuffered
|
||||||
/// writer for all further write operations.
|
/// writer for all further write operations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// This type is designed to avoid creating large in-memory strings when buffering and supporting the contract that
|
|
||||||
/// <see cref="RazorPage.FlushAsync"/> expects.
|
|
||||||
/// </remarks>
|
|
||||||
public class RazorTextWriter : HtmlTextWriter
|
public class RazorTextWriter : HtmlTextWriter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -28,14 +23,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="unbufferedWriter">The <see cref="TextWriter"/> to write output to when this instance
|
/// <param name="unbufferedWriter">The <see cref="TextWriter"/> to write output to when this instance
|
||||||
/// is no longer buffering.</param>
|
/// is no longer buffering.</param>
|
||||||
/// <param name="encoding">The character <see cref="Encoding"/> in which the output is written.</param>
|
/// <param name="buffer">The <see cref="IHtmlContentBuilder"/> to buffer output to.</param>
|
||||||
/// <param name="encoder">The HTML encoder.</param>
|
/// <param name="encoder">The HTML encoder.</param>
|
||||||
public RazorTextWriter(TextWriter unbufferedWriter, Encoding encoding, HtmlEncoder encoder)
|
public RazorTextWriter(TextWriter unbufferedWriter, IHtmlContentBuilder buffer, HtmlEncoder encoder)
|
||||||
{
|
{
|
||||||
UnbufferedWriter = unbufferedWriter;
|
UnbufferedWriter = unbufferedWriter;
|
||||||
HtmlEncoder = encoder;
|
HtmlEncoder = encoder;
|
||||||
|
|
||||||
BufferedWriter = new StringCollectionTextWriter(encoding);
|
BufferedWriter = new HtmlContentWrapperTextWriter(buffer, unbufferedWriter.Encoding);
|
||||||
TargetWriter = BufferedWriter;
|
TargetWriter = BufferedWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,10 +46,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the buffered content.
|
/// Gets the buffered content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IHtmlContent Buffer => BufferedWriter.Content;
|
public IHtmlContent Buffer => BufferedWriter.ContentBuilder;
|
||||||
|
|
||||||
// Internal for unit testing
|
// Internal for unit testing
|
||||||
internal StringCollectionTextWriter BufferedWriter { get; }
|
internal HtmlContentWrapperTextWriter BufferedWriter { get; }
|
||||||
|
|
||||||
private TextWriter UnbufferedWriter { get; }
|
private TextWriter UnbufferedWriter { get; }
|
||||||
|
|
||||||
|
|
@ -80,7 +75,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
}
|
}
|
||||||
if (count < 0 || (buffer.Length - index < count))
|
|
||||||
|
if (count < 0 || (index + count > buffer.Length))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,14 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -20,6 +23,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
private readonly IRazorViewEngine _viewEngine;
|
private readonly IRazorViewEngine _viewEngine;
|
||||||
private readonly IRazorPageActivator _pageActivator;
|
private readonly IRazorPageActivator _pageActivator;
|
||||||
private readonly HtmlEncoder _htmlEncoder;
|
private readonly HtmlEncoder _htmlEncoder;
|
||||||
|
private IRazorBufferScope _bufferScope;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="RazorView"/>
|
/// Initializes a new instance of <see cref="RazorView"/>
|
||||||
|
|
@ -93,6 +97,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_bufferScope = context.HttpContext.RequestServices.GetRequiredService<IRazorBufferScope>();
|
||||||
var bodyWriter = await RenderPageAsync(RazorPage, context, ViewStartPages);
|
var bodyWriter = await RenderPageAsync(RazorPage, context, ViewStartPages);
|
||||||
await RenderLayoutAsync(context, bodyWriter);
|
await RenderLayoutAsync(context, bodyWriter);
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +107,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
ViewContext context,
|
ViewContext context,
|
||||||
IReadOnlyList<IRazorPage> viewStartPages)
|
IReadOnlyList<IRazorPage> viewStartPages)
|
||||||
{
|
{
|
||||||
var razorTextWriter = new RazorTextWriter(context.Writer, context.Writer.Encoding, _htmlEncoder);
|
Debug.Assert(_bufferScope != null);
|
||||||
|
var buffer = new RazorBuffer(_bufferScope, page.Path);
|
||||||
|
var razorTextWriter = new RazorTextWriter(context.Writer, buffer, _htmlEncoder);
|
||||||
|
|
||||||
// The writer for the body is passed through the ViewContext, allowing things like HtmlHelpers
|
// The writer for the body is passed through the ViewContext, allowing things like HtmlHelpers
|
||||||
// and ViewComponents to reference it.
|
// and ViewComponents to reference it.
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,12 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNet.Razor.TagHelpers;
|
using Microsoft.AspNet.Razor.TagHelpers;
|
||||||
|
|
@ -41,9 +44,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
/// Creates a new <see cref="CacheTagHelper"/>.
|
/// Creates a new <see cref="CacheTagHelper"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="memoryCache">The <see cref="IMemoryCache"/>.</param>
|
/// <param name="memoryCache">The <see cref="IMemoryCache"/>.</param>
|
||||||
public CacheTagHelper(IMemoryCache memoryCache)
|
public CacheTagHelper(IMemoryCache memoryCache, HtmlEncoder htmlEncoder)
|
||||||
{
|
{
|
||||||
MemoryCache = memoryCache;
|
MemoryCache = memoryCache;
|
||||||
|
HtmlEncoder = htmlEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -60,6 +64,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IMemoryCache MemoryCache { get; }
|
protected IMemoryCache MemoryCache { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="System.Text.Encodings.Web.HtmlEncoder"/> which encodes the content to be cached.
|
||||||
|
/// </summary>
|
||||||
|
protected HtmlEncoder HtmlEncoder { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="ViewContext"/> for the current executing View.
|
/// Gets or sets the <see cref="ViewContext"/> for the current executing View.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -147,7 +156,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
throw new ArgumentNullException(nameof(output));
|
throw new ArgumentNullException(nameof(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
TagHelperContent result = null;
|
IHtmlContent result = null;
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
{
|
{
|
||||||
var key = GenerateKey(context);
|
var key = GenerateKey(context);
|
||||||
|
|
@ -157,8 +166,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// created within this scope get copied to this scope.
|
// created within this scope get copied to this scope.
|
||||||
using (var link = MemoryCache.CreateLinkingScope())
|
using (var link = MemoryCache.CreateLinkingScope())
|
||||||
{
|
{
|
||||||
result = await output.GetChildContentAsync();
|
var content = await output.GetChildContentAsync();
|
||||||
|
|
||||||
|
var stringBuilder = new StringBuilder();
|
||||||
|
using (var writer = new StringWriter(stringBuilder))
|
||||||
|
{
|
||||||
|
content.WriteTo(writer, HtmlEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = new StringBuilderHtmlContent(stringBuilder);
|
||||||
MemoryCache.Set(key, result, GetMemoryCacheEntryOptions(link));
|
MemoryCache.Set(key, result, GetMemoryCacheEntryOptions(link));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -371,5 +387,30 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
|
|
||||||
return trimmedValues;
|
return trimmedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class StringBuilderHtmlContent : IHtmlContent
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _builder;
|
||||||
|
|
||||||
|
public StringBuilderHtmlContent(StringBuilder builder)
|
||||||
|
{
|
||||||
|
_builder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||||
|
{
|
||||||
|
var htmlTextWriter = writer as HtmlTextWriter;
|
||||||
|
if (htmlTextWriter != null)
|
||||||
|
{
|
||||||
|
htmlTextWriter.Write(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < _builder.Length; i++)
|
||||||
|
{
|
||||||
|
writer.Write(_builder[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
public class RazorBufferTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Append_AddsStringRazorValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.Append("Hello world");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var segment = Assert.Single(buffer.BufferSegments);
|
||||||
|
Assert.Equal(1, buffer.CurrentCount);
|
||||||
|
Assert.Equal("Hello world", segment.Data.Array[0].Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Append_AddsHtmlContentRazorValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var content = new HtmlString("hello-world");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.Append(content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var segment = Assert.Single(buffer.BufferSegments);
|
||||||
|
Assert.Equal(1, buffer.CurrentCount);
|
||||||
|
Assert.Same(content, segment.Data.Array[0].Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AppendHtml_AddsHtmlStringValues()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var value = "Hello world";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.AppendHtml(value);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var segment = Assert.Single(buffer.BufferSegments);
|
||||||
|
Assert.Equal(1, buffer.CurrentCount);
|
||||||
|
var htmlString = Assert.IsType<HtmlString>(segment.Data.Array[0].Value);
|
||||||
|
Assert.Equal("Hello world", htmlString.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Append_CreatesNewSegments_WhenCurrentSegmentIsFull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var expected = Enumerable.Range(0, TestRazorBufferScope.BufferSize).Select(i => i.ToString());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
foreach (var item in expected)
|
||||||
|
{
|
||||||
|
buffer.Append(item);
|
||||||
|
}
|
||||||
|
buffer.Append("Hello");
|
||||||
|
buffer.Append("world");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, buffer.CurrentCount);
|
||||||
|
Assert.Collection(buffer.BufferSegments,
|
||||||
|
segment => Assert.Equal(expected, segment.Data.Array.Select(v => v.Value)),
|
||||||
|
segment =>
|
||||||
|
{
|
||||||
|
var array = segment.Data.Array;
|
||||||
|
Assert.Equal("Hello", array[0].Value);
|
||||||
|
Assert.Equal("world", array[1].Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Append_CreatesNewSegments_WhenCurrentSegmentIsFull_ForBuffersWithNonZeroOffsets()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(3, 2), "some-name");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.Append("1");
|
||||||
|
buffer.Append("2");
|
||||||
|
buffer.Append("3");
|
||||||
|
buffer.Append("4");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, buffer.CurrentCount);
|
||||||
|
Assert.Collection(buffer.BufferSegments,
|
||||||
|
segment =>
|
||||||
|
{
|
||||||
|
var array = segment.Data.Array;
|
||||||
|
Assert.Equal("1", array[3].Value);
|
||||||
|
Assert.Equal("2", array[4].Value);
|
||||||
|
},
|
||||||
|
segment =>
|
||||||
|
{
|
||||||
|
var array = segment.Data.Array;
|
||||||
|
Assert.Equal("3", array[3].Value);
|
||||||
|
Assert.Equal("4", array[4].Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(TestRazorBufferScope.BufferSize + 3)]
|
||||||
|
public void Clear_ResetsBackingBufferAndIndex(int valuesToWrite)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
for (var i = 0; i < valuesToWrite; i++)
|
||||||
|
{
|
||||||
|
buffer.Append("Hello");
|
||||||
|
}
|
||||||
|
buffer.Clear();
|
||||||
|
buffer.Append("world");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var segment = Assert.Single(buffer.BufferSegments);
|
||||||
|
Assert.Equal(1, buffer.CurrentCount);
|
||||||
|
Assert.Equal("world", segment.Data.Array[0].Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WriteTo_WritesSelf_WhenWriterIsHtmlTextWriter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var htmlWriter = new Mock<HtmlTextWriter>();
|
||||||
|
htmlWriter.Setup(w => w.Write(buffer)).Verifiable();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.Append("Hello world");
|
||||||
|
buffer.WriteTo(htmlWriter.Object, new HtmlTestEncoder());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
htmlWriter.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WriteTo_WritesRazorValues_ToTextWriter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new StringWriter();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
buffer.Append("Hello");
|
||||||
|
buffer.Append(new HtmlString(" world"));
|
||||||
|
buffer.AppendHtml(" 123");
|
||||||
|
buffer.WriteTo(writer, new HtmlTestEncoder());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("Hello world 123", writer.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(9)]
|
||||||
|
[InlineData(10)]
|
||||||
|
[InlineData(11)]
|
||||||
|
[InlineData(23)]
|
||||||
|
public void WriteTo_WritesRazorValuesFromAllBuffers(int valuesToWrite)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(1, 5), "some-name");
|
||||||
|
var writer = new StringWriter();
|
||||||
|
var expected = string.Join("", Enumerable.Range(0, valuesToWrite).Select(_ => "abc"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
for (var i = 0; i < valuesToWrite; i++)
|
||||||
|
{
|
||||||
|
buffer.AppendHtml("abc");
|
||||||
|
}
|
||||||
|
buffer.WriteTo(writer, new HtmlTestEncoder());
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, writer.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
public class HtmlContentWrapperTextWriterTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Write_WritesCharBuffer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var input1 = new ArraySegment<char>(new char[] { 'a', 'b', 'c', 'd' }, 1, 3);
|
||||||
|
var input2 = new ArraySegment<char>(new char[] { 'e', 'f' }, 0, 2);
|
||||||
|
var input3 = new ArraySegment<char>(new char[] { 'g', 'h', 'i', 'j' }, 3, 1);
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write(input1.Array, input1.Offset, input1.Count);
|
||||||
|
await writer.WriteAsync(input2.Array, input2.Offset, input2.Count);
|
||||||
|
await writer.WriteLineAsync(input3.Array, input3.Offset, input3.Count);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var bufferValues = GetValues(buffer);
|
||||||
|
Assert.Equal(4, bufferValues.Length);
|
||||||
|
Assert.Equal("bcd", bufferValues[0]);
|
||||||
|
Assert.Equal("ef", bufferValues[1]);
|
||||||
|
Assert.Equal("j", bufferValues[2]);
|
||||||
|
Assert.Equal(Environment.NewLine, bufferValues[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Write_SplitsCharBuffer_Into1kbStrings()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var charArray = Enumerable.Range(0, 2050).Select(_ => 'a').ToArray();
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write(charArray);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(GetValues(buffer),
|
||||||
|
value => Assert.Equal(new string('a', 1024), value),
|
||||||
|
value => Assert.Equal(new string('a', 1024), value),
|
||||||
|
value => Assert.Equal("aa", value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Write_HtmlContent_AddsToEntries()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
var content = new HtmlString("Hello, world!");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write(content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
GetValues(buffer),
|
||||||
|
item => Assert.Same(content, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Write_Object_HtmlContent_AddsToEntries()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
var content = new HtmlString("Hello, world!");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write((object)content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
GetValues(buffer),
|
||||||
|
item => Assert.Same(content, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WriteLine_Object_HtmlContent_AddsToEntries()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
var content = new HtmlString("Hello, world!");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.WriteLine(content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
GetValues(buffer),
|
||||||
|
item => Assert.Same(content, item),
|
||||||
|
item => Assert.Equal(Environment.NewLine, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Write_WritesStringBuffer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var newLine = Environment.NewLine;
|
||||||
|
var input1 = "Hello";
|
||||||
|
var input2 = "from";
|
||||||
|
var input3 = "ASP";
|
||||||
|
var input4 = ".Net";
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write(input1);
|
||||||
|
writer.WriteLine(input2);
|
||||||
|
await writer.WriteAsync(input3);
|
||||||
|
await writer.WriteLineAsync(input4);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = GetValues(buffer);
|
||||||
|
Assert.Equal(new object[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Write_HtmlContent_WritesToBuffer()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||||
|
var content = new HtmlString("Hello, world!");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
writer.Write(content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Collection(
|
||||||
|
GetValues(buffer),
|
||||||
|
item => Assert.Same(content, item));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object[] GetValues(RazorBuffer buffer)
|
||||||
|
{
|
||||||
|
return buffer.BufferSegments
|
||||||
|
.SelectMany(c => c.Data)
|
||||||
|
.Select(d => d.Value)
|
||||||
|
.TakeWhile(d => d != null)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNet.Html;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.Routing;
|
using Microsoft.AspNet.Mvc.Routing;
|
||||||
using Microsoft.AspNet.Mvc.TestCommon;
|
using Microsoft.AspNet.Mvc.TestCommon;
|
||||||
|
|
@ -184,7 +185,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var page = CreatePage(v =>
|
var page = CreatePage(v =>
|
||||||
{
|
{
|
||||||
v.HtmlEncoder = new HtmlTestEncoder();
|
v.HtmlEncoder = new HtmlTestEncoder();
|
||||||
v.StartTagHelperWritingScope(new RazorTextWriter(TextWriter.Null, Encoding.UTF8, v.HtmlEncoder));
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), v.Path);
|
||||||
|
v.StartTagHelperWritingScope(new RazorTextWriter(TextWriter.Null, buffer, v.HtmlEncoder));
|
||||||
v.Write("Hello ");
|
v.Write("Hello ");
|
||||||
v.Write("World!");
|
v.Write("World!");
|
||||||
var returnValue = v.EndTagHelperWritingScope();
|
var returnValue = v.EndTagHelperWritingScope();
|
||||||
|
|
@ -1125,7 +1127,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public async Task Write_WithHtmlString_WritesValueWithoutEncoding()
|
public async Task Write_WithHtmlString_WritesValueWithoutEncoding()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), string.Empty);
|
||||||
|
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
var page = CreatePage(p =>
|
var page = CreatePage(p =>
|
||||||
{
|
{
|
||||||
|
|
@ -1137,9 +1140,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await page.ExecuteAsync();
|
await page.ExecuteAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var buffer = writer.BufferedWriter.Entries;
|
Assert.Equal("Hello world", HtmlContentUtilities.HtmlContentToString(writer.Buffer));
|
||||||
Assert.Equal(1, buffer.Count);
|
|
||||||
Assert.Equal("Hello world", HtmlContentUtilities.HtmlContentToString(((IHtmlContent)buffer[0])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TestableRazorPage CreatePage(
|
private static TestableRazorPage CreatePage(
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
|
|
@ -21,8 +23,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
public void Write_WritesDataTypes_ToBuffer()
|
public void Write_WritesDataTypes_ToBuffer()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
var expected = new object[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
writer.Write(true);
|
writer.Write(true);
|
||||||
|
|
@ -34,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
writer.Write('m');
|
writer.Write('m');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expected, writer.BufferedWriter.Entries);
|
Assert.Equal(expected, GetValues(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -44,7 +47,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718" };
|
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718" };
|
||||||
var unbufferedWriter = new Mock<TextWriter>();
|
var unbufferedWriter = new Mock<TextWriter>();
|
||||||
var writer = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||||
var testClass = new TestClass();
|
var testClass = new TestClass();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -57,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
writer.Write(2.718m);
|
writer.Write(2.718m);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(writer.BufferedWriter.Entries);
|
Assert.Null(buffer.BufferSegments);
|
||||||
foreach (var item in expected)
|
foreach (var item in expected)
|
||||||
{
|
{
|
||||||
unbufferedWriter.Verify(v => v.Write(item), Times.Once());
|
unbufferedWriter.Verify(v => v.Write(item), Times.Once());
|
||||||
|
|
@ -70,7 +75,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var unbufferedWriter = new Mock<TextWriter> { CallBase = true };
|
var unbufferedWriter = new Mock<TextWriter> { CallBase = true };
|
||||||
var writer = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||||
var buffer1 = new[] { 'a', 'b', 'c', 'd' };
|
var buffer1 = new[] { 'a', 'b', 'c', 'd' };
|
||||||
var buffer2 = new[] { 'd', 'e', 'f' };
|
var buffer2 = new[] { 'd', 'e', 'f' };
|
||||||
|
|
||||||
|
|
@ -83,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
await writer.WriteLineAsync(buffer1);
|
await writer.WriteLineAsync(buffer1);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(writer.BufferedWriter.Entries);
|
Assert.Null(buffer.BufferSegments);
|
||||||
unbufferedWriter.Verify(v => v.Write('x'), Times.Once());
|
unbufferedWriter.Verify(v => v.Write('x'), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.Write(buffer1, 1, 2), Times.Once());
|
unbufferedWriter.Verify(v => v.Write(buffer1, 1, 2), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.Write(buffer1, 0, 4), Times.Once());
|
unbufferedWriter.Verify(v => v.Write(buffer1, 0, 4), Times.Once());
|
||||||
|
|
@ -98,7 +105,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var unbufferedWriter = new Mock<TextWriter>();
|
var unbufferedWriter = new Mock<TextWriter>();
|
||||||
var writer = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await writer.FlushAsync();
|
await writer.FlushAsync();
|
||||||
|
|
@ -108,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
await writer.WriteLineAsync("gh");
|
await writer.WriteLineAsync("gh");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(writer.BufferedWriter.Entries);
|
Assert.Null(buffer.BufferSegments);
|
||||||
unbufferedWriter.Verify(v => v.Write("a"), Times.Once());
|
unbufferedWriter.Verify(v => v.Write("a"), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.WriteLine("ab"), Times.Once());
|
unbufferedWriter.Verify(v => v.WriteLine("ab"), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.WriteAsync("ef"), Times.Once());
|
unbufferedWriter.Verify(v => v.WriteAsync("ef"), Times.Once());
|
||||||
|
|
@ -122,7 +131,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
// Arrange
|
// Arrange
|
||||||
var newLine = Environment.NewLine;
|
var newLine = Environment.NewLine;
|
||||||
var expected = new List<object> { "False", newLine, "1.1", newLine, "3", newLine };
|
var expected = new List<object> { "False", newLine, "1.1", newLine, "3", newLine };
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
writer.WriteLine(false);
|
writer.WriteLine(false);
|
||||||
|
|
@ -130,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
writer.WriteLine(3L);
|
writer.WriteLine(3L);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expected, writer.BufferedWriter.Entries);
|
Assert.Equal(expected, GetValues(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -139,7 +149,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var unbufferedWriter = new Mock<TextWriter>();
|
var unbufferedWriter = new Mock<TextWriter>();
|
||||||
var writer = new RazorTextWriter(unbufferedWriter.Object, Encoding.UTF8, new HtmlTestEncoder());
|
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
|
|
@ -148,49 +160,27 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
writer.WriteLine(3L);
|
writer.WriteLine(3L);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(writer.BufferedWriter.Entries);
|
Assert.Null(buffer.BufferSegments);
|
||||||
unbufferedWriter.Verify(v => v.Write("False"), Times.Once());
|
unbufferedWriter.Verify(v => v.Write("False"), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.Write("1.1"), Times.Once());
|
unbufferedWriter.Verify(v => v.Write("1.1"), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.Write("3"), Times.Once());
|
unbufferedWriter.Verify(v => v.Write("3"), Times.Once());
|
||||||
unbufferedWriter.Verify(v => v.WriteLine(), Times.Exactly(3));
|
unbufferedWriter.Verify(v => v.WriteLine(), Times.Exactly(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Write_WritesCharBuffer()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var input1 = new ArraySegment<char>(new char[] { 'a', 'b', 'c', 'd' }, 1, 3);
|
|
||||||
var input2 = new ArraySegment<char>(new char[] { 'e', 'f' }, 0, 2);
|
|
||||||
var input3 = new ArraySegment<char>(new char[] { 'g', 'h', 'i', 'j' }, 3, 1);
|
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
|
||||||
|
|
||||||
// Act
|
|
||||||
writer.Write(input1.Array, input1.Offset, input1.Count);
|
|
||||||
await writer.WriteAsync(input2.Array, input2.Offset, input2.Count);
|
|
||||||
await writer.WriteLineAsync(input3.Array, input3.Offset, input3.Count);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var buffer = writer.BufferedWriter.Entries;
|
|
||||||
Assert.Equal(4, buffer.Count);
|
|
||||||
Assert.Equal("bcd", buffer[0]);
|
|
||||||
Assert.Equal("ef", buffer[1]);
|
|
||||||
Assert.Equal("j", buffer[2]);
|
|
||||||
Assert.Equal(Environment.NewLine, buffer[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task WriteLines_WritesCharBuffer()
|
public async Task WriteLines_WritesCharBuffer()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var newLine = Environment.NewLine;
|
var newLine = Environment.NewLine;
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
await writer.WriteLineAsync();
|
await writer.WriteLineAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var actual = writer.BufferedWriter.Entries;
|
var actual = GetValues(buffer);
|
||||||
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,7 +193,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
var input2 = "from";
|
var input2 = "from";
|
||||||
var input3 = "ASP";
|
var input3 = "ASP";
|
||||||
var input4 = ".Net";
|
var input4 = ".Net";
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
|
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
writer.Write(input1);
|
writer.Write(input1);
|
||||||
|
|
@ -212,66 +203,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
await writer.WriteLineAsync(input4);
|
await writer.WriteLineAsync(input4);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var actual = writer.BufferedWriter.Entries;
|
var actual = GetValues(buffer);
|
||||||
Assert.Equal<object>(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
Assert.Equal<object>(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Write_HtmlContent_AddsToEntries()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
|
||||||
var content = new HtmlString("Hello, world!");
|
|
||||||
|
|
||||||
// Act
|
|
||||||
writer.Write(content);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Collection(
|
|
||||||
writer.BufferedWriter.Entries,
|
|
||||||
item => Assert.Same(content, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Write_Object_HtmlContent_AddsToEntries()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
|
||||||
var content = new HtmlString("Hello, world!");
|
|
||||||
|
|
||||||
// Act
|
|
||||||
writer.Write((object)content);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Collection(
|
|
||||||
writer.BufferedWriter.Entries,
|
|
||||||
item => Assert.Same(content, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void WriteLine_Object_HtmlContent_AddsToEntries()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
|
||||||
var content = new HtmlString("Hello, world!");
|
|
||||||
|
|
||||||
// Act
|
|
||||||
writer.WriteLine(content);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Collection(
|
|
||||||
writer.BufferedWriter.Entries,
|
|
||||||
item => Assert.Same(content, item),
|
|
||||||
item => Assert.Equal(Environment.NewLine, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Write_HtmlContent_AfterFlush_GoesToStream()
|
public void Write_HtmlContent_AfterFlush_GoesToStream()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var stringWriter = new StringWriter();
|
var stringWriter = new StringWriter();
|
||||||
|
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||||
var writer = new RazorTextWriter(stringWriter, Encoding.UTF8, new HtmlTestEncoder());
|
var writer = new RazorTextWriter(stringWriter, buffer, new HtmlTestEncoder());
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
|
|
||||||
var content = new HtmlString("Hello, world!");
|
var content = new HtmlString("Hello, world!");
|
||||||
|
|
@ -283,6 +225,15 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||||
Assert.Equal("Hello, world!", stringWriter.ToString());
|
Assert.Equal("Hello, world!", stringWriter.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object[] GetValues(RazorBuffer buffer)
|
||||||
|
{
|
||||||
|
return buffer.BufferSegments
|
||||||
|
.SelectMany(c => c.Data)
|
||||||
|
.Select(d => d.Value)
|
||||||
|
.TakeWhile(d => d != null)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
private class TestClass
|
private class TestClass
|
||||||
{
|
{
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,11 @@ using Microsoft.AspNet.Http.Features;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Extensions.WebEncoders.Testing;
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -1563,6 +1565,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
private static ViewContext CreateViewContext(RazorView view)
|
private static ViewContext CreateViewContext(RazorView view)
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
var serviceProvider = new ServiceCollection()
|
||||||
|
.AddScoped<IRazorBufferScope, TestRazorBufferScope>()
|
||||||
|
.BuildServiceProvider();
|
||||||
|
httpContext.RequestServices = serviceProvider;
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
return new ViewContext(
|
return new ViewContext(
|
||||||
actionContext,
|
actionContext,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||||
|
{
|
||||||
|
public class TestRazorBufferScope : IRazorBufferScope
|
||||||
|
{
|
||||||
|
public const int BufferSize = 128;
|
||||||
|
private readonly int _offset;
|
||||||
|
private readonly int _count;
|
||||||
|
|
||||||
|
public TestRazorBufferScope()
|
||||||
|
: this(0, BufferSize)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestRazorBufferScope(int offset, int count)
|
||||||
|
{
|
||||||
|
_offset = offset;
|
||||||
|
_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorBufferSegment GetSegment()
|
||||||
|
{
|
||||||
|
var razorValues = new RazorValue[BufferSize];
|
||||||
|
return new RazorBufferSegment(new ArraySegment<RazorValue>(razorValues, _offset, _count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Html;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Abstractions;
|
using Microsoft.AspNet.Mvc.Abstractions;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
@ -21,6 +22,7 @@ using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Internal;
|
using Microsoft.Extensions.Internal;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Extensions.WebEncoders.Testing;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -34,7 +36,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var id = Guid.NewGuid().ToString();
|
var id = Guid.NewGuid().ToString();
|
||||||
var tagHelperContext = GetTagHelperContext(id);
|
var tagHelperContext = GetTagHelperContext(id);
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext()
|
ViewContext = GetViewContext()
|
||||||
};
|
};
|
||||||
|
|
@ -55,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryBy = varyBy
|
VaryBy = varyBy
|
||||||
|
|
@ -83,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByCookie = varyByCookie
|
VaryByCookie = varyByCookie
|
||||||
|
|
@ -108,7 +110,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByHeader = varyByHeader
|
VaryByHeader = varyByHeader
|
||||||
|
|
@ -135,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByQuery = varyByQuery
|
VaryByQuery = varyByQuery
|
||||||
|
|
@ -160,7 +162,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByRoute = varyByRoute
|
VaryByRoute = varyByRoute
|
||||||
|
|
@ -181,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = "CacheTagHelper||testid||VaryByUser||";
|
var expected = "CacheTagHelper||testid||VaryByUser||";
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByUser = true
|
VaryByUser = true
|
||||||
|
|
@ -200,7 +202,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = "CacheTagHelper||testid||VaryByUser||test_name";
|
var expected = "CacheTagHelper||testid||VaryByUser||test_name";
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByUser = true
|
VaryByUser = true
|
||||||
|
|
@ -222,7 +224,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var expected = GetHashedBytes("CacheTagHelper||testid||VaryBy||custom-value||" +
|
var expected = GetHashedBytes("CacheTagHelper||testid||VaryBy||custom-value||" +
|
||||||
"VaryByHeader(content-type||text/html)||VaryByUser||someuser");
|
"VaryByHeader(content-type||text/html)||VaryByUser||someuser");
|
||||||
var tagHelperContext = GetTagHelperContext();
|
var tagHelperContext = GetTagHelperContext();
|
||||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
VaryByUser = true,
|
VaryByUser = true,
|
||||||
|
|
@ -262,7 +264,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput = GetTagHelperOutput(
|
var tagHelperOutput = GetTagHelperOutput(
|
||||||
attributes: new TagHelperAttributeList(),
|
attributes: new TagHelperAttributeList(),
|
||||||
childContent: childContent);
|
childContent: childContent);
|
||||||
var cacheTagHelper = new CacheTagHelper(cache.Object)
|
var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
Enabled = false
|
Enabled = false
|
||||||
|
|
@ -303,7 +305,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput = GetTagHelperOutput(
|
var tagHelperOutput = GetTagHelperOutput(
|
||||||
attributes: new TagHelperAttributeList(),
|
attributes: new TagHelperAttributeList(),
|
||||||
childContent: childContent);
|
childContent: childContent);
|
||||||
var cacheTagHelper = new CacheTagHelper(cache.Object)
|
var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
Enabled = true
|
Enabled = true
|
||||||
|
|
@ -335,7 +337,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput1 = GetTagHelperOutput(
|
var tagHelperOutput1 = GetTagHelperOutput(
|
||||||
attributes: new TagHelperAttributeList(),
|
attributes: new TagHelperAttributeList(),
|
||||||
childContent: childContent);
|
childContent: childContent);
|
||||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
VaryByQuery = "key1,key2",
|
VaryByQuery = "key1,key2",
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
|
|
@ -357,7 +359,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput2 = GetTagHelperOutput(
|
var tagHelperOutput2 = GetTagHelperOutput(
|
||||||
attributes: new TagHelperAttributeList(),
|
attributes: new TagHelperAttributeList(),
|
||||||
childContent: "different-content");
|
childContent: "different-content");
|
||||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
VaryByQuery = "key1,key2",
|
VaryByQuery = "key1,key2",
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
|
|
@ -386,7 +388,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||||
tagHelperOutput1.PreContent.Append("<cache>");
|
tagHelperOutput1.PreContent.Append("<cache>");
|
||||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
VaryByCookie = "cookie1,cookie2",
|
VaryByCookie = "cookie1,cookie2",
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
|
|
@ -408,7 +410,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
VaryByCookie = "cookie1,cookie2",
|
VaryByCookie = "cookie1,cookie2",
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
|
|
@ -431,7 +433,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4);
|
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ExpiresOn = expiresOn
|
ExpiresOn = expiresOn
|
||||||
};
|
};
|
||||||
|
|
@ -449,7 +451,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
|
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -470,7 +472,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var expiresOn1 = DateTimeOffset.UtcNow.AddDays(12);
|
var expiresOn1 = DateTimeOffset.UtcNow.AddDays(12);
|
||||||
var expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
|
var expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ExpiresOn = expiresOn1
|
ExpiresOn = expiresOn1
|
||||||
};
|
};
|
||||||
|
|
@ -491,7 +493,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expiresAfter = TimeSpan.FromSeconds(42);
|
var expiresAfter = TimeSpan.FromSeconds(42);
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ExpiresAfter = expiresAfter
|
ExpiresAfter = expiresAfter
|
||||||
};
|
};
|
||||||
|
|
@ -509,7 +511,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var expiresSliding = TimeSpan.FromSeconds(37);
|
var expiresSliding = TimeSpan.FromSeconds(37);
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ExpiresSliding = expiresSliding
|
ExpiresSliding = expiresSliding
|
||||||
};
|
};
|
||||||
|
|
@ -527,7 +529,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
// Arrange
|
// Arrange
|
||||||
var priority = CacheItemPriority.High;
|
var priority = CacheItemPriority.High;
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
Priority = priority
|
Priority = priority
|
||||||
};
|
};
|
||||||
|
|
@ -546,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var expiresSliding = TimeSpan.FromSeconds(30);
|
var expiresSliding = TimeSpan.FromSeconds(30);
|
||||||
var expected = new[] { Mock.Of<IChangeToken>(), Mock.Of<IChangeToken>() };
|
var expected = new[] { Mock.Of<IChangeToken>(), Mock.Of<IChangeToken>() };
|
||||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ExpiresSliding = expiresSliding
|
ExpiresSliding = expiresSliding
|
||||||
};
|
};
|
||||||
|
|
@ -576,7 +578,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresAfter = TimeSpan.FromMinutes(10)
|
ExpiresAfter = TimeSpan.FromMinutes(10)
|
||||||
|
|
@ -597,7 +599,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresAfter = TimeSpan.FromMinutes(10)
|
ExpiresAfter = TimeSpan.FromMinutes(10)
|
||||||
|
|
@ -629,7 +631,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresOn = currentTime.AddMinutes(5)
|
ExpiresOn = currentTime.AddMinutes(5)
|
||||||
|
|
@ -651,7 +653,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresOn = currentTime.AddMinutes(5)
|
ExpiresOn = currentTime.AddMinutes(5)
|
||||||
|
|
@ -682,7 +684,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresSliding = TimeSpan.FromSeconds(30)
|
ExpiresSliding = TimeSpan.FromSeconds(30)
|
||||||
|
|
@ -704,7 +706,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
ExpiresSliding = TimeSpan.FromSeconds(30)
|
ExpiresSliding = TimeSpan.FromSeconds(30)
|
||||||
|
|
@ -751,7 +753,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
});
|
});
|
||||||
tagHelperOutput.PreContent.SetContent("<cache>");
|
tagHelperOutput.PreContent.SetContent("<cache>");
|
||||||
tagHelperOutput.PostContent.SetContent("</cache>");
|
tagHelperOutput.PostContent.SetContent("</cache>");
|
||||||
var cacheTagHelper = new CacheTagHelper(cache)
|
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||||
{
|
{
|
||||||
ViewContext = GetViewContext(),
|
ViewContext = GetViewContext(),
|
||||||
};
|
};
|
||||||
|
|
@ -759,13 +761,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
|
|
||||||
// Act - 1
|
// Act - 1
|
||||||
await cacheTagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
|
await cacheTagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
|
||||||
TagHelperContent cachedValue;
|
IHtmlContent cachedValue;
|
||||||
var result = cache.TryGetValue(key, out cachedValue);
|
var result = cache.TryGetValue(key, out cachedValue);
|
||||||
|
|
||||||
// Assert - 1
|
// Assert - 1
|
||||||
Assert.Equal(expectedContent.GetContent(), tagHelperOutput.Content.GetContent());
|
Assert.Equal("HtmlEncode[[some-content]]", tagHelperOutput.Content.GetContent());
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
Assert.Equal(expectedContent, cachedValue);
|
|
||||||
|
|
||||||
// Act - 2
|
// Act - 2
|
||||||
tokenSource.Cancel();
|
tokenSource.Cancel();
|
||||||
|
|
@ -808,7 +809,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
getChildContentAsync: useCachedResult =>
|
getChildContentAsync: useCachedResult =>
|
||||||
{
|
{
|
||||||
var tagHelperContent = new DefaultTagHelperContent();
|
var tagHelperContent = new DefaultTagHelperContent();
|
||||||
tagHelperContent.SetContent(childContent);
|
tagHelperContent.SetHtmlContent(childContent);
|
||||||
return Task.FromResult<TagHelperContent>(tagHelperContent);
|
return Task.FromResult<TagHelperContent>(tagHelperContent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue