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 Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||
|
|
@ -14,6 +15,7 @@ using Microsoft.AspNet.Razor.TagHelpers;
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.CompilationAbstractions;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.MemoryPool;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
|
||||
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.
|
||||
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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// writer for all further write operations.
|
||||
/// </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
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -28,14 +23,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// </summary>
|
||||
/// <param name="unbufferedWriter">The <see cref="TextWriter"/> to write output to when this instance
|
||||
/// 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>
|
||||
public RazorTextWriter(TextWriter unbufferedWriter, Encoding encoding, HtmlEncoder encoder)
|
||||
public RazorTextWriter(TextWriter unbufferedWriter, IHtmlContentBuilder buffer, HtmlEncoder encoder)
|
||||
{
|
||||
UnbufferedWriter = unbufferedWriter;
|
||||
HtmlEncoder = encoder;
|
||||
|
||||
BufferedWriter = new StringCollectionTextWriter(encoding);
|
||||
BufferedWriter = new HtmlContentWrapperTextWriter(buffer, unbufferedWriter.Encoding);
|
||||
TargetWriter = BufferedWriter;
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +46,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <summary>
|
||||
/// Gets the buffered content.
|
||||
/// </summary>
|
||||
public IHtmlContent Buffer => BufferedWriter.Content;
|
||||
public IHtmlContent Buffer => BufferedWriter.ContentBuilder;
|
||||
|
||||
// Internal for unit testing
|
||||
internal StringCollectionTextWriter BufferedWriter { get; }
|
||||
internal HtmlContentWrapperTextWriter BufferedWriter { get; }
|
||||
|
||||
private TextWriter UnbufferedWriter { get; }
|
||||
|
||||
|
|
@ -80,7 +75,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
if (count < 0 || (buffer.Length - index < count))
|
||||
|
||||
if (count < 0 || (index + count > buffer.Length))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
{
|
||||
|
|
@ -20,6 +23,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private readonly IRazorViewEngine _viewEngine;
|
||||
private readonly IRazorPageActivator _pageActivator;
|
||||
private readonly HtmlEncoder _htmlEncoder;
|
||||
private IRazorBufferScope _bufferScope;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorView"/>
|
||||
|
|
@ -93,6 +97,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
_bufferScope = context.HttpContext.RequestServices.GetRequiredService<IRazorBufferScope>();
|
||||
var bodyWriter = await RenderPageAsync(RazorPage, context, ViewStartPages);
|
||||
await RenderLayoutAsync(context, bodyWriter);
|
||||
}
|
||||
|
|
@ -102,7 +107,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
ViewContext context,
|
||||
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
|
||||
// and ViewComponents to reference it.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
|
|
@ -41,9 +44,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// Creates a new <see cref="CacheTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="memoryCache">The <see cref="IMemoryCache"/>.</param>
|
||||
public CacheTagHelper(IMemoryCache memoryCache)
|
||||
public CacheTagHelper(IMemoryCache memoryCache, HtmlEncoder htmlEncoder)
|
||||
{
|
||||
MemoryCache = memoryCache;
|
||||
HtmlEncoder = htmlEncoder;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -60,6 +64,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
/// </summary>
|
||||
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>
|
||||
/// Gets or sets the <see cref="ViewContext"/> for the current executing View.
|
||||
/// </summary>
|
||||
|
|
@ -147,7 +156,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
throw new ArgumentNullException(nameof(output));
|
||||
}
|
||||
|
||||
TagHelperContent result = null;
|
||||
IHtmlContent result = null;
|
||||
if (Enabled)
|
||||
{
|
||||
var key = GenerateKey(context);
|
||||
|
|
@ -157,8 +166,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// created within this scope get copied to this scope.
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -371,5 +387,30 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
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.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
|
|
@ -184,7 +185,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var page = CreatePage(v =>
|
||||
{
|
||||
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("World!");
|
||||
var returnValue = v.EndTagHelperWritingScope();
|
||||
|
|
@ -1125,7 +1127,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public async Task Write_WithHtmlString_WritesValueWithoutEncoding()
|
||||
{
|
||||
// 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 =>
|
||||
{
|
||||
|
|
@ -1137,9 +1140,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
await page.ExecuteAsync();
|
||||
|
||||
// Assert
|
||||
var buffer = writer.BufferedWriter.Entries;
|
||||
Assert.Equal(1, buffer.Count);
|
||||
Assert.Equal("Hello world", HtmlContentUtilities.HtmlContentToString(((IHtmlContent)buffer[0])));
|
||||
Assert.Equal("Hello world", HtmlContentUtilities.HtmlContentToString(writer.Buffer));
|
||||
}
|
||||
|
||||
private static TestableRazorPage CreatePage(
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
|
|
@ -21,8 +23,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
public void Write_WritesDataTypes_ToBuffer()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
||||
var writer = new RazorTextWriter(TextWriter.Null, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var expected = new object[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
writer.Write(true);
|
||||
|
|
@ -34,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.Write('m');
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.BufferedWriter.Entries);
|
||||
Assert.Equal(expected, GetValues(buffer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -44,7 +47,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718" };
|
||||
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();
|
||||
|
||||
// Act
|
||||
|
|
@ -57,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.Write(2.718m);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Entries);
|
||||
Assert.Null(buffer.BufferSegments);
|
||||
foreach (var item in expected)
|
||||
{
|
||||
unbufferedWriter.Verify(v => v.Write(item), Times.Once());
|
||||
|
|
@ -70,7 +75,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
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 buffer2 = new[] { 'd', 'e', 'f' };
|
||||
|
||||
|
|
@ -83,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync(buffer1);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Entries);
|
||||
Assert.Null(buffer.BufferSegments);
|
||||
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());
|
||||
|
|
@ -98,7 +105,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
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
|
||||
await writer.FlushAsync();
|
||||
|
|
@ -108,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync("gh");
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Entries);
|
||||
Assert.Null(buffer.BufferSegments);
|
||||
unbufferedWriter.Verify(v => v.Write("a"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteLine("ab"), Times.Once());
|
||||
unbufferedWriter.Verify(v => v.WriteAsync("ef"), Times.Once());
|
||||
|
|
@ -122,7 +131,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var newLine = Environment.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
|
||||
writer.WriteLine(false);
|
||||
|
|
@ -130,7 +140,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.BufferedWriter.Entries);
|
||||
Assert.Equal(expected, GetValues(buffer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -139,7 +149,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
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
|
||||
writer.Flush();
|
||||
|
|
@ -148,49 +160,27 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(writer.BufferedWriter.Entries);
|
||||
Assert.Null(buffer.BufferSegments);
|
||||
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());
|
||||
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]
|
||||
public async Task WriteLines_WritesCharBuffer()
|
||||
{
|
||||
// Arrange
|
||||
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
|
||||
writer.WriteLine();
|
||||
await writer.WriteLineAsync();
|
||||
|
||||
// Assert
|
||||
var actual = writer.BufferedWriter.Entries;
|
||||
var actual = GetValues(buffer);
|
||||
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +193,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
var input2 = "from";
|
||||
var input3 = "ASP";
|
||||
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
|
||||
writer.Write(input1);
|
||||
|
|
@ -212,66 +203,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
await writer.WriteLineAsync(input4);
|
||||
|
||||
// Assert
|
||||
var actual = writer.BufferedWriter.Entries;
|
||||
var actual = GetValues(buffer);
|
||||
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]
|
||||
public void Write_HtmlContent_AfterFlush_GoesToStream()
|
||||
{
|
||||
// Arrange
|
||||
var stringWriter = new StringWriter();
|
||||
|
||||
var writer = new RazorTextWriter(stringWriter, Encoding.UTF8, new HtmlTestEncoder());
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(stringWriter, buffer, new HtmlTestEncoder());
|
||||
writer.Flush();
|
||||
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
|
@ -283,6 +225,15 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
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
|
||||
{
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ using Microsoft.AspNet.Http.Features;
|
|||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
|
|
@ -1563,6 +1565,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private static ViewContext CreateViewContext(RazorView view)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddScoped<IRazorBufferScope, TestRazorBufferScope>()
|
||||
.BuildServiceProvider();
|
||||
httpContext.RequestServices = serviceProvider;
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
return new ViewContext(
|
||||
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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
|
@ -21,6 +22,7 @@ using Microsoft.AspNet.Routing;
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -34,7 +36,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var id = Guid.NewGuid().ToString();
|
||||
var tagHelperContext = GetTagHelperContext(id);
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext()
|
||||
};
|
||||
|
|
@ -55,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryBy = varyBy
|
||||
|
|
@ -83,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByCookie = varyByCookie
|
||||
|
|
@ -108,7 +110,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByHeader = varyByHeader
|
||||
|
|
@ -135,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByQuery = varyByQuery
|
||||
|
|
@ -160,7 +162,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByRoute = varyByRoute
|
||||
|
|
@ -181,7 +183,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expected = "CacheTagHelper||testid||VaryByUser||";
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByUser = true
|
||||
|
|
@ -200,7 +202,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expected = "CacheTagHelper||testid||VaryByUser||test_name";
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByUser = true
|
||||
|
|
@ -222,7 +224,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var expected = GetHashedBytes("CacheTagHelper||testid||VaryBy||custom-value||" +
|
||||
"VaryByHeader(content-type||text/html)||VaryByUser||someuser");
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>())
|
||||
var cacheTagHelper = new CacheTagHelper(Mock.Of<IMemoryCache>(), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByUser = true,
|
||||
|
|
@ -262,7 +264,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput = GetTagHelperOutput(
|
||||
attributes: new TagHelperAttributeList(),
|
||||
childContent: childContent);
|
||||
var cacheTagHelper = new CacheTagHelper(cache.Object)
|
||||
var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
Enabled = false
|
||||
|
|
@ -303,7 +305,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput = GetTagHelperOutput(
|
||||
attributes: new TagHelperAttributeList(),
|
||||
childContent: childContent);
|
||||
var cacheTagHelper = new CacheTagHelper(cache.Object)
|
||||
var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
Enabled = true
|
||||
|
|
@ -335,7 +337,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput1 = GetTagHelperOutput(
|
||||
attributes: new TagHelperAttributeList(),
|
||||
childContent: childContent);
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
VaryByQuery = "key1,key2",
|
||||
ViewContext = GetViewContext(),
|
||||
|
|
@ -357,7 +359,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput2 = GetTagHelperOutput(
|
||||
attributes: new TagHelperAttributeList(),
|
||||
childContent: "different-content");
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
VaryByQuery = "key1,key2",
|
||||
ViewContext = GetViewContext(),
|
||||
|
|
@ -386,7 +388,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||
tagHelperOutput1.PreContent.Append("<cache>");
|
||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
VaryByCookie = "cookie1,cookie2",
|
||||
ViewContext = GetViewContext(),
|
||||
|
|
@ -408,7 +410,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
VaryByCookie = "cookie1,cookie2",
|
||||
ViewContext = GetViewContext(),
|
||||
|
|
@ -431,7 +433,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresOn = expiresOn
|
||||
};
|
||||
|
|
@ -449,7 +451,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
|
||||
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 expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresOn = expiresOn1
|
||||
};
|
||||
|
|
@ -491,7 +493,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expiresAfter = TimeSpan.FromSeconds(42);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresAfter = expiresAfter
|
||||
};
|
||||
|
|
@ -509,7 +511,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var expiresSliding = TimeSpan.FromSeconds(37);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresSliding = expiresSliding
|
||||
};
|
||||
|
|
@ -527,7 +529,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Arrange
|
||||
var priority = CacheItemPriority.High;
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
Priority = priority
|
||||
};
|
||||
|
|
@ -546,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var expiresSliding = TimeSpan.FromSeconds(30);
|
||||
var expected = new[] { Mock.Of<IChangeToken>(), Mock.Of<IChangeToken>() };
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresSliding = expiresSliding
|
||||
};
|
||||
|
|
@ -576,7 +578,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresAfter = TimeSpan.FromMinutes(10)
|
||||
|
|
@ -597,7 +599,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresAfter = TimeSpan.FromMinutes(10)
|
||||
|
|
@ -629,7 +631,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresOn = currentTime.AddMinutes(5)
|
||||
|
|
@ -651,7 +653,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresOn = currentTime.AddMinutes(5)
|
||||
|
|
@ -682,7 +684,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1);
|
||||
tagHelperOutput1.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput1.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresSliding = TimeSpan.FromSeconds(30)
|
||||
|
|
@ -704,7 +706,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2);
|
||||
tagHelperOutput2.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput2.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache)
|
||||
var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
ExpiresSliding = TimeSpan.FromSeconds(30)
|
||||
|
|
@ -751,7 +753,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
});
|
||||
tagHelperOutput.PreContent.SetContent("<cache>");
|
||||
tagHelperOutput.PostContent.SetContent("</cache>");
|
||||
var cacheTagHelper = new CacheTagHelper(cache)
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
};
|
||||
|
|
@ -759,13 +761,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// Act - 1
|
||||
await cacheTagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
|
||||
TagHelperContent cachedValue;
|
||||
IHtmlContent cachedValue;
|
||||
var result = cache.TryGetValue(key, out cachedValue);
|
||||
|
||||
// Assert - 1
|
||||
Assert.Equal(expectedContent.GetContent(), tagHelperOutput.Content.GetContent());
|
||||
Assert.Equal("HtmlEncode[[some-content]]", tagHelperOutput.Content.GetContent());
|
||||
Assert.True(result);
|
||||
Assert.Equal(expectedContent, cachedValue);
|
||||
|
||||
// Act - 2
|
||||
tokenSource.Cancel();
|
||||
|
|
@ -808,7 +809,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
getChildContentAsync: useCachedResult =>
|
||||
{
|
||||
var tagHelperContent = new DefaultTagHelperContent();
|
||||
tagHelperContent.SetContent(childContent);
|
||||
tagHelperContent.SetHtmlContent(childContent);
|
||||
return Task.FromResult<TagHelperContent>(tagHelperContent);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue