Move buffer types to ViewFeatures
Use buffer pooling in more places
This commit is contained in:
parent
0c3e7b5a75
commit
c5b6efd6bf
|
|
@ -1,17 +0,0 @@
|
|||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ 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;
|
||||
|
|
@ -160,9 +159,6 @@ 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>();
|
||||
|
||||
if (PlatformServices.Default?.AssemblyLoadContextAccessor != null)
|
||||
{
|
||||
services.TryAddSingleton(PlatformServices.Default.AssemblyLoadContextAccessor);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using Microsoft.AspNet.Mvc.Razor.Internal;
|
|||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -37,12 +38,12 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private bool _renderedBody;
|
||||
private AttributeInfo _attributeInfo;
|
||||
private TagHelperAttributeInfo _tagHelperAttributeInfo;
|
||||
private StringCollectionTextWriter _valueBuffer;
|
||||
private HtmlContentWrapperTextWriter _valueBuffer;
|
||||
private IViewBufferScope _bufferScope;
|
||||
|
||||
public RazorPage()
|
||||
{
|
||||
SectionWriters = new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
_writerScopes = new Stack<TextWriter>();
|
||||
}
|
||||
|
||||
|
|
@ -148,6 +149,20 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
}
|
||||
|
||||
private IViewBufferScope BufferScope
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_bufferScope == null)
|
||||
{
|
||||
var services = ViewContext.HttpContext.RequestServices;
|
||||
_bufferScope = services.GetRequiredService<IViewBufferScope>();
|
||||
}
|
||||
|
||||
return _bufferScope;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format an error message about using an indexer when the tag helper property is <c>null</c>.
|
||||
/// </summary>
|
||||
|
|
@ -194,7 +209,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// </remarks>
|
||||
public void StartTagHelperWritingScope()
|
||||
{
|
||||
StartTagHelperWritingScope(new StringCollectionTextWriter(Output.Encoding));
|
||||
var buffer = new ViewBuffer(BufferScope, Path);
|
||||
StartTagHelperWritingScope(new HtmlContentWrapperTextWriter(buffer, Output.Encoding));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -221,7 +237,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
// from HTML helpers) is redirected.
|
||||
ViewContext.Writer = writer;
|
||||
|
||||
_writerScopes.Push(ViewContext.Writer);
|
||||
_writerScopes.Push(writer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -258,10 +274,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
else
|
||||
{
|
||||
var stringCollectionTextWriter = writer as StringCollectionTextWriter;
|
||||
if (stringCollectionTextWriter != null)
|
||||
var htmlContentTextWriter = writer as HtmlContentWrapperTextWriter;
|
||||
if (htmlContentTextWriter != null)
|
||||
{
|
||||
tagHelperContent.Append(stringCollectionTextWriter.Content);
|
||||
tagHelperContent.Append(htmlContentTextWriter.ContentBuilder);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -586,7 +602,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
if (_valueBuffer == null)
|
||||
{
|
||||
_valueBuffer = new StringCollectionTextWriter(Output.Encoding);
|
||||
var buffer = new ViewBuffer(BufferScope, Path);
|
||||
_valueBuffer = new HtmlContentWrapperTextWriter(buffer, Output.Encoding);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(prefix))
|
||||
|
|
@ -604,7 +621,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
executionContext.AddHtmlAttribute(
|
||||
_tagHelperAttributeInfo.Name,
|
||||
_valueBuffer?.Content ?? HtmlString.Empty);
|
||||
(IHtmlContent)_valueBuffer?.ContentBuilder ?? HtmlString.Empty);
|
||||
_valueBuffer = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ 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.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private readonly IRazorViewEngine _viewEngine;
|
||||
private readonly IRazorPageActivator _pageActivator;
|
||||
private readonly HtmlEncoder _htmlEncoder;
|
||||
private IRazorBufferScope _bufferScope;
|
||||
private IViewBufferScope _bufferScope;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorView"/>
|
||||
|
|
@ -97,7 +97,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
_bufferScope = context.HttpContext.RequestServices.GetRequiredService<IRazorBufferScope>();
|
||||
_bufferScope = context.HttpContext.RequestServices.GetRequiredService<IViewBufferScope>();
|
||||
var bodyWriter = await RenderPageAsync(RazorPage, context, invokeViewStarts: true);
|
||||
await RenderLayoutAsync(context, bodyWriter);
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
bool invokeViewStarts)
|
||||
{
|
||||
Debug.Assert(_bufferScope != null);
|
||||
var buffer = new RazorBuffer(_bufferScope, page.Path);
|
||||
var buffer = new ViewBuffer(_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
|
||||
|
|
|
|||
|
|
@ -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.ViewFeatures.Buffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates and manages the lifetime of <see cref="ViewBufferValue[]"/> instances.
|
||||
/// </summary>
|
||||
public interface IViewBufferScope
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ViewBufferValue[]"/>.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="ViewBufferValue[]"/>.</returns>
|
||||
ViewBufferValue[] GetSegment();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// 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.Buffers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Buffer
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IViewBufferScope"/> that uses pooled memory.
|
||||
/// </summary>
|
||||
public class MemoryPoolViewBufferScope : IViewBufferScope, IDisposable
|
||||
{
|
||||
public static readonly int SegmentSize = 512;
|
||||
private readonly ArrayPool<ViewBufferValue> _pool;
|
||||
private List<ViewBufferValue[]> _leased;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="MemoryPoolViewBufferScope"/>.
|
||||
/// </summary>
|
||||
/// <param name="pool">The <see cref="ArrayPool{ViewBufferValue}"/> for creating
|
||||
/// <see cref="ViewBufferValue"/> instances.</param>
|
||||
public MemoryPoolViewBufferScope(ArrayPool<ViewBufferValue> pool)
|
||||
{
|
||||
_pool = pool;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ViewBufferValue[] GetSegment()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(typeof(MemoryPoolViewBufferScope).FullName);
|
||||
}
|
||||
|
||||
if (_leased == null)
|
||||
{
|
||||
_leased = new List<ViewBufferValue[]>(1);
|
||||
}
|
||||
|
||||
ViewBufferValue[] segment = null;
|
||||
|
||||
try
|
||||
{
|
||||
segment = _pool.Rent(SegmentSize);
|
||||
_leased.Add(segment);
|
||||
}
|
||||
catch when (segment != null)
|
||||
{
|
||||
_pool.Return(segment);
|
||||
throw;
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
|
||||
if (_leased == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < _leased.Count; i++)
|
||||
{
|
||||
_pool.Return(_leased[i]);
|
||||
}
|
||||
|
||||
_leased.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,23 +9,23 @@ using System.Text.Encodings.Web;
|
|||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Buffer
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IHtmlContentBuilder"/> that is backed by a buffer provided by <see cref="IRazorBufferScope"/>.
|
||||
/// An <see cref="IHtmlContentBuilder"/> that is backed by a buffer provided by <see cref="IViewBufferScope"/>.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{DebuggerToString()}")]
|
||||
public class RazorBuffer : IHtmlContentBuilder
|
||||
public class ViewBuffer : IHtmlContentBuilder
|
||||
{
|
||||
private readonly IRazorBufferScope _bufferScope;
|
||||
private readonly IViewBufferScope _bufferScope;
|
||||
private readonly string _name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorBuffer"/>.
|
||||
/// Initializes a new instance of <see cref="ViewBuffer"/>.
|
||||
/// </summary>
|
||||
/// <param name="bufferScope">The <see cref="IRazorBufferScope"/>.</param>
|
||||
/// <param name="bufferScope">The <see cref="IViewBufferScope"/>.</param>
|
||||
/// <param name="name">A name to identify this instance.</param>
|
||||
public RazorBuffer(IRazorBufferScope bufferScope, string name)
|
||||
public ViewBuffer(IViewBufferScope bufferScope, string name)
|
||||
{
|
||||
if (bufferScope == null)
|
||||
{
|
||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
/// <summary>
|
||||
/// Gets the backing buffer.
|
||||
/// </summary>
|
||||
public IList<RazorBufferSegment> BufferSegments { get; private set; }
|
||||
public IList<ViewBufferValue[]> BufferSegments { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count of entries in the last element of <see cref="BufferSegments"/>.
|
||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
return this;
|
||||
}
|
||||
|
||||
AppendValue(new RazorValue(unencoded));
|
||||
AppendValue(new ViewBufferValue(unencoded));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
return this;
|
||||
}
|
||||
|
||||
AppendValue(new RazorValue(content));
|
||||
AppendValue(new ViewBufferValue(content));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -79,23 +79,23 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
}
|
||||
|
||||
var value = new HtmlString(encoded);
|
||||
AppendValue(new RazorValue(value));
|
||||
AppendValue(new ViewBufferValue(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void AppendValue(RazorValue value)
|
||||
private void AppendValue(ViewBufferValue value)
|
||||
{
|
||||
RazorBufferSegment segment;
|
||||
ViewBufferValue[] segment;
|
||||
if (BufferSegments == null)
|
||||
{
|
||||
BufferSegments = new List<RazorBufferSegment>(1);
|
||||
BufferSegments = new List<ViewBufferValue[]>(1);
|
||||
segment = _bufferScope.GetSegment();
|
||||
BufferSegments.Add(segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = BufferSegments[BufferSegments.Count - 1];
|
||||
if (CurrentCount == segment.Data.Count)
|
||||
if (CurrentCount == segment.Length)
|
||||
{
|
||||
segment = _bufferScope.GetSegment();
|
||||
BufferSegments.Add(segment);
|
||||
|
|
@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
}
|
||||
}
|
||||
|
||||
segment.Data.Array[segment.Data.Offset + CurrentCount] = value;
|
||||
segment[CurrentCount] = value;
|
||||
CurrentCount++;
|
||||
}
|
||||
|
||||
|
|
@ -137,11 +137,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
for (var i = 0; i < BufferSegments.Count; i++)
|
||||
{
|
||||
var segment = BufferSegments[i];
|
||||
var count = i == BufferSegments.Count - 1 ? CurrentCount : segment.Data.Count;
|
||||
var count = i == BufferSegments.Count - 1 ? CurrentCount : segment.Length;
|
||||
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
var value = segment.Data.Array[segment.Data.Offset + j];
|
||||
var value = segment[j];
|
||||
value.WriteTo(writer, encoder);
|
||||
}
|
||||
}
|
||||
|
|
@ -6,27 +6,27 @@ using System.IO;
|
|||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNet.Html;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Buffer
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates a string or <see cref="IHtmlContent"/> value.
|
||||
/// </summary>
|
||||
public struct RazorValue
|
||||
public struct ViewBufferValue
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorValue"/> with a <c>string</c> value.
|
||||
/// Initializes a new instance of <see cref="ViewBufferValue"/> with a <c>string</c> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public RazorValue(string value)
|
||||
public ViewBufferValue(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorValue"/> with a <see cref="IHtmlContent"/> value.
|
||||
/// Initializes a new instance of <see cref="ViewBufferValue"/> with a <see cref="IHtmlContent"/> value.
|
||||
/// </summary>
|
||||
/// <param name="value">The <see cref="IHtmlContent"/>.</param>
|
||||
public RazorValue(IHtmlContent content)
|
||||
public ViewBufferValue(IHtmlContent content)
|
||||
{
|
||||
Value = content;
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Controllers;
|
||||
using Microsoft.AspNet.Mvc.Formatters;
|
||||
|
|
@ -9,8 +10,10 @@ using Microsoft.AspNet.Mvc.Rendering;
|
|||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.MemoryPool;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -136,6 +139,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
// These are stateless so their lifetime isn't really important.
|
||||
services.TryAddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
|
||||
services.TryAddSingleton<SaveTempDataFilter>();
|
||||
|
||||
services.TryAddSingleton(ArrayPool<ViewBufferValue>.Shared);
|
||||
services.TryAddScoped<IViewBufferScope, MemoryPoolViewBufferScope>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
|
|
@ -18,13 +19,15 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
private readonly HtmlEncoder _htmlEncoder;
|
||||
private readonly IViewComponentInvokerFactory _invokerFactory;
|
||||
private readonly IViewComponentSelector _selector;
|
||||
private readonly IViewBufferScope _viewBufferScope;
|
||||
private ViewContext _viewContext;
|
||||
|
||||
public DefaultViewComponentHelper(
|
||||
IViewComponentDescriptorCollectionProvider descriptorProvider,
|
||||
HtmlEncoder htmlEncoder,
|
||||
IViewComponentSelector selector,
|
||||
IViewComponentInvokerFactory invokerFactory)
|
||||
IViewComponentInvokerFactory invokerFactory,
|
||||
IViewBufferScope viewBufferScope)
|
||||
{
|
||||
if (descriptorProvider == null)
|
||||
{
|
||||
|
|
@ -46,10 +49,16 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
throw new ArgumentNullException(nameof(invokerFactory));
|
||||
}
|
||||
|
||||
if (viewBufferScope == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewBufferScope));
|
||||
}
|
||||
|
||||
_descriptorProvider = descriptorProvider;
|
||||
_htmlEncoder = htmlEncoder;
|
||||
_selector = selector;
|
||||
_invokerFactory = invokerFactory;
|
||||
_viewBufferScope = viewBufferScope;
|
||||
}
|
||||
|
||||
public void Contextualize(ViewContext viewContext)
|
||||
|
|
@ -71,10 +80,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
var descriptor = SelectComponent(name);
|
||||
|
||||
using (var writer = new StringCollectionTextWriter(_viewContext.Writer.Encoding))
|
||||
var viewBuffer = new ViewBuffer(_viewBufferScope, name);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
|
||||
{
|
||||
InvokeCore(writer, descriptor, arguments);
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,11 +96,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
}
|
||||
|
||||
var descriptor = SelectComponent(componentType);
|
||||
|
||||
using (var writer = new StringCollectionTextWriter(_viewContext.Writer.Encoding))
|
||||
var viewBuffer = new ViewBuffer(_viewBufferScope, componentType.Name);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
|
||||
{
|
||||
InvokeCore(writer, descriptor, arguments);
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,10 +135,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
var descriptor = SelectComponent(name);
|
||||
|
||||
using (var writer = new StringCollectionTextWriter(_viewContext.Writer.Encoding))
|
||||
var viewBuffer = new ViewBuffer(_viewBufferScope, name);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
|
||||
{
|
||||
await InvokeCoreAsync(writer, descriptor, arguments);
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,10 +152,11 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
var descriptor = SelectComponent(componentType);
|
||||
|
||||
using (var writer = new StringCollectionTextWriter(_viewContext.Writer.Encoding))
|
||||
var viewBuffer = new ViewBuffer(_viewBufferScope, componentType.Name);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
|
||||
{
|
||||
await InvokeCoreAsync(writer, descriptor, arguments);
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ using Microsoft.AspNet.Html;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
|
|
@ -124,6 +124,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
var fieldNameBase = oldPrefix;
|
||||
var result = new HtmlContentBuilder();
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var viewBufferScope = serviceProvider.GetRequiredService<IViewBufferScope>();
|
||||
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
|
|
@ -143,6 +144,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
viewBufferScope,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
modelExplorer,
|
||||
|
|
@ -223,6 +225,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices;
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var viewBufferScope = serviceProvider.GetRequiredService<IViewBufferScope>();
|
||||
|
||||
var content = new HtmlContentBuilder();
|
||||
foreach (var propertyExplorer in modelExplorer.Properties)
|
||||
|
|
@ -235,6 +238,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
viewBufferScope,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
propertyExplorer,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Html;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -87,6 +88,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
var fieldNameBase = oldPrefix;
|
||||
var result = new HtmlContentBuilder();
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var viewBufferScope = serviceProvider.GetRequiredService<IViewBufferScope>();
|
||||
|
||||
var index = 0;
|
||||
foreach (var item in collection)
|
||||
|
|
@ -106,6 +108,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
viewBufferScope,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
modelExplorer,
|
||||
|
|
@ -245,6 +248,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices;
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var viewBufferScope = serviceProvider.GetRequiredService<IViewBufferScope>();
|
||||
|
||||
var content = new HtmlContentBuilder();
|
||||
foreach (var propertyExplorer in modelExplorer.Properties)
|
||||
|
|
@ -257,6 +261,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
viewBufferScope,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
propertyExplorer,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="HtmlTextWriter"/> implementation which writes to an <see cref="IHtmlContentBuilder"/> instance.
|
||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// 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>
|
||||
/// <param name="encoding">The <see cref="System.Text.Encoding"/> in which output is written.</param>
|
||||
public HtmlContentWrapperTextWriter(IHtmlContentBuilder contentBuilder, Encoding encoding)
|
||||
{
|
||||
if (contentBuilder == null)
|
||||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
private readonly IHtmlGenerator _htmlGenerator;
|
||||
private readonly ICompositeViewEngine _viewEngine;
|
||||
private readonly HtmlEncoder _htmlEncoder;
|
||||
private readonly IViewBufferScope _bufferScope;
|
||||
|
||||
private ViewContext _viewContext;
|
||||
|
||||
|
|
@ -43,6 +45,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
IHtmlGenerator htmlGenerator,
|
||||
ICompositeViewEngine viewEngine,
|
||||
IModelMetadataProvider metadataProvider,
|
||||
IViewBufferScope bufferScope,
|
||||
HtmlEncoder htmlEncoder,
|
||||
UrlEncoder urlEncoder,
|
||||
JavaScriptEncoder javaScriptEncoder)
|
||||
|
|
@ -62,6 +65,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(metadataProvider));
|
||||
}
|
||||
|
||||
if (bufferScope == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bufferScope));
|
||||
}
|
||||
|
||||
if (htmlEncoder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(htmlEncoder));
|
||||
|
|
@ -80,6 +88,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
_viewEngine = viewEngine;
|
||||
_htmlGenerator = htmlGenerator;
|
||||
_htmlEncoder = htmlEncoder;
|
||||
_bufferScope = bufferScope;
|
||||
MetadataProvider = metadataProvider;
|
||||
UrlEncoder = urlEncoder;
|
||||
JavaScriptEncoder = javaScriptEncoder;
|
||||
|
|
@ -349,10 +358,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
|
||||
return GenerateDisplay(metadata,
|
||||
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
|
||||
templateName,
|
||||
additionalViewData);
|
||||
return GenerateDisplay(
|
||||
metadata,
|
||||
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
|
||||
templateName,
|
||||
additionalViewData);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -493,10 +503,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(partialViewName));
|
||||
}
|
||||
|
||||
using (var writer = new StringCollectionTextWriter(Encoding.UTF8))
|
||||
var viewBuffer = new ViewBuffer(_bufferScope, partialViewName);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, Encoding.UTF8))
|
||||
{
|
||||
await RenderPartialCoreAsync(partialViewName, model, viewData, writer);
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -519,6 +530,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
{
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
_viewEngine,
|
||||
_bufferScope,
|
||||
ViewContext,
|
||||
ViewData,
|
||||
modelExplorer,
|
||||
|
|
@ -815,6 +827,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
{
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
_viewEngine,
|
||||
_bufferScope,
|
||||
ViewContext,
|
||||
ViewData,
|
||||
modelExplorer,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNet.Html;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
|
|
@ -21,35 +22,19 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
IHtmlGenerator htmlGenerator,
|
||||
ICompositeViewEngine viewEngine,
|
||||
IModelMetadataProvider metadataProvider,
|
||||
IViewBufferScope bufferScope,
|
||||
HtmlEncoder htmlEncoder,
|
||||
UrlEncoder urlEncoder,
|
||||
JavaScriptEncoder javaScriptEncoder)
|
||||
: base(htmlGenerator, viewEngine, metadataProvider, htmlEncoder, urlEncoder, javaScriptEncoder)
|
||||
: base(
|
||||
htmlGenerator,
|
||||
viewEngine,
|
||||
metadataProvider,
|
||||
bufferScope,
|
||||
htmlEncoder,
|
||||
urlEncoder,
|
||||
javaScriptEncoder)
|
||||
{
|
||||
if (htmlGenerator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(htmlGenerator));
|
||||
}
|
||||
if (viewEngine == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewEngine));
|
||||
}
|
||||
if (metadataProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(metadataProvider));
|
||||
}
|
||||
if (htmlEncoder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(htmlEncoder));
|
||||
}
|
||||
if (urlEncoder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(urlEncoder));
|
||||
}
|
||||
if (javaScriptEncoder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(javaScriptEncoder));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -1,260 +0,0 @@
|
|||
// 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;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Html;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="HtmlTextWriter"/> that stores individual write operations as a sequence of
|
||||
/// <see cref="string"/> and <see cref="IHtmlContent"/> instances.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is primarily designed to avoid creating large in-memory strings.
|
||||
/// Refer to https://aspnetwebstack.codeplex.com/workitem/585 for more details.
|
||||
/// </remarks>
|
||||
public class StringCollectionTextWriter : HtmlTextWriter
|
||||
{
|
||||
private const int MaxCharToStringLength = 1024;
|
||||
private static readonly Task _completedTask = Task.FromResult(0);
|
||||
|
||||
private readonly Encoding _encoding;
|
||||
private readonly StringCollectionTextWriterContent _content;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="StringCollectionTextWriter"/>.
|
||||
/// </summary>
|
||||
/// <param name="encoding">The character <see cref="Encoding"/> in which the output is written.</param>
|
||||
public StringCollectionTextWriter(Encoding encoding)
|
||||
{
|
||||
_encoding = encoding;
|
||||
Entries = new List<object>();
|
||||
_content = new StringCollectionTextWriterContent(Entries);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Encoding Encoding
|
||||
{
|
||||
get { return _encoding; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content written to the writer as an <see cref="IHtmlContent"/>.
|
||||
/// </summary>
|
||||
public IHtmlContent Content => _content;
|
||||
|
||||
// internal for testing purposes.
|
||||
internal List<object> Entries { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(char value)
|
||||
{
|
||||
_content.Append(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 || (buffer.Length - index < count))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
// Split large char arrays into 1KB strings.
|
||||
var currentCount = count;
|
||||
if (MaxCharToStringLength < currentCount)
|
||||
{
|
||||
currentCount = MaxCharToStringLength;
|
||||
}
|
||||
|
||||
_content.Append(new string(buffer, index, currentCount));
|
||||
index += currentCount;
|
||||
count -= currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_content.Append(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(IHtmlContent value)
|
||||
{
|
||||
_content.Append(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteAsync(char value)
|
||||
{
|
||||
Write(value);
|
||||
return _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 _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteAsync(string value)
|
||||
{
|
||||
Write(value);
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteLine()
|
||||
{
|
||||
_content.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
Write(value);
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteLineAsync(char value)
|
||||
{
|
||||
WriteLine(value);
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteLineAsync(char[] value, int start, int offset)
|
||||
{
|
||||
WriteLine(value, start, offset);
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteLineAsync(string value)
|
||||
{
|
||||
WriteLine(value);
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task WriteLineAsync()
|
||||
{
|
||||
WriteLine();
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the specified <paramref name="writer"/> is a <see cref="HtmlTextWriter"/> the contents
|
||||
/// are copied. It is just written to the <paramref name="writer"/> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to which the content must be copied/written.</param>
|
||||
/// <param name="encoder">The <see cref="HtmlEncoder"/> to encode the copied/written content.</param>
|
||||
public void CopyTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
var htmlTextWriter = writer as HtmlTextWriter;
|
||||
if (htmlTextWriter != null)
|
||||
{
|
||||
htmlTextWriter.Write(Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
Content.WriteTo(writer, encoder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the specified <paramref name="writer"/> is a <see cref="HtmlTextWriter"/> the contents
|
||||
/// are copied. It is just written to the <paramref name="writer"/> otherwise.
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="TextWriter"/> to which the content must be copied/written.</param>
|
||||
/// <param name="encoder">The <see cref="HtmlEncoder"/> to encode the copied/written content.</param>
|
||||
public Task CopyToAsync(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
CopyTo(writer, encoder);
|
||||
return _completedTask;
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{DebuggerToString()}")]
|
||||
private class StringCollectionTextWriterContent : IHtmlContent
|
||||
{
|
||||
private readonly List<object> _entries;
|
||||
|
||||
public StringCollectionTextWriterContent(List<object> entries)
|
||||
{
|
||||
_entries = entries;
|
||||
}
|
||||
|
||||
public void Append(string value)
|
||||
{
|
||||
_entries.Add(value);
|
||||
}
|
||||
|
||||
public void Append(IHtmlContent content)
|
||||
{
|
||||
_entries.Add(content);
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
foreach (var item in _entries)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemAsString = item as string;
|
||||
if (itemAsString != null)
|
||||
{
|
||||
writer.Write(itemAsString);
|
||||
}
|
||||
else
|
||||
{
|
||||
((IHtmlContent)item).WriteTo(writer, encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string DebuggerToString()
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
WriteTo(writer, HtmlEncoder.Default);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,24 +7,27 @@ using Microsoft.AspNet.Html;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
||||
{
|
||||
public class TemplateBuilder
|
||||
{
|
||||
private IViewEngine _viewEngine;
|
||||
private ViewContext _viewContext;
|
||||
private ViewDataDictionary _viewData;
|
||||
private ModelExplorer _modelExplorer;
|
||||
private readonly IViewEngine _viewEngine;
|
||||
private readonly IViewBufferScope _bufferScope;
|
||||
private readonly ViewContext _viewContext;
|
||||
private readonly ViewDataDictionary _viewData;
|
||||
private readonly ModelExplorer _modelExplorer;
|
||||
private object _model;
|
||||
private ModelMetadata _metadata;
|
||||
private string _htmlFieldName;
|
||||
private string _templateName;
|
||||
private bool _readOnly;
|
||||
private object _additionalViewData;
|
||||
private readonly ModelMetadata _metadata;
|
||||
private readonly string _htmlFieldName;
|
||||
private readonly string _templateName;
|
||||
private readonly bool _readOnly;
|
||||
private readonly object _additionalViewData;
|
||||
|
||||
public TemplateBuilder(
|
||||
IViewEngine viewEngine,
|
||||
IViewBufferScope bufferScope,
|
||||
ViewContext viewContext,
|
||||
ViewDataDictionary viewData,
|
||||
ModelExplorer modelExplorer,
|
||||
|
|
@ -38,6 +41,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
throw new ArgumentNullException(nameof(viewEngine));
|
||||
}
|
||||
|
||||
if (bufferScope == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(_bufferScope));
|
||||
}
|
||||
|
||||
if (viewContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewContext));
|
||||
|
|
@ -54,6 +62,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
}
|
||||
|
||||
_viewEngine = viewEngine;
|
||||
_bufferScope = bufferScope;
|
||||
_viewContext = viewContext;
|
||||
_viewData = viewData;
|
||||
_modelExplorer = modelExplorer;
|
||||
|
|
@ -117,7 +126,13 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
var visitedObjectsKey = _model ?? _modelExplorer.ModelType;
|
||||
viewData.TemplateInfo.AddVisited(visitedObjectsKey);
|
||||
|
||||
var templateRenderer = new TemplateRenderer(_viewEngine, _viewContext, viewData, _templateName, _readOnly);
|
||||
var templateRenderer = new TemplateRenderer(
|
||||
_viewEngine,
|
||||
_bufferScope,
|
||||
_viewContext,
|
||||
viewData,
|
||||
_templateName,
|
||||
_readOnly);
|
||||
|
||||
return templateRenderer.Render();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNet.Http;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
||||
|
|
@ -67,14 +68,16 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
{ IEnumerableOfIFormFileName, DefaultEditorTemplates.FileCollectionInputTemplate },
|
||||
};
|
||||
|
||||
private ViewContext _viewContext;
|
||||
private ViewDataDictionary _viewData;
|
||||
private IViewEngine _viewEngine;
|
||||
private string _templateName;
|
||||
private bool _readOnly;
|
||||
private readonly IViewEngine _viewEngine;
|
||||
private readonly IViewBufferScope _bufferScope;
|
||||
private readonly ViewContext _viewContext;
|
||||
private readonly ViewDataDictionary _viewData;
|
||||
private readonly string _templateName;
|
||||
private readonly bool _readOnly;
|
||||
|
||||
public TemplateRenderer(
|
||||
IViewEngine viewEngine,
|
||||
IViewBufferScope bufferScope,
|
||||
ViewContext viewContext,
|
||||
ViewDataDictionary viewData,
|
||||
string templateName,
|
||||
|
|
@ -85,6 +88,11 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
throw new ArgumentNullException(nameof(viewEngine));
|
||||
}
|
||||
|
||||
if (bufferScope == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bufferScope));
|
||||
}
|
||||
|
||||
if (viewContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(viewContext));
|
||||
|
|
@ -96,6 +104,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
}
|
||||
|
||||
_viewEngine = viewEngine;
|
||||
_bufferScope = bufferScope;
|
||||
_viewContext = viewContext;
|
||||
_viewData = viewData;
|
||||
_templateName = templateName;
|
||||
|
|
@ -118,7 +127,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
|
||||
if (viewEngineResult.Success)
|
||||
{
|
||||
using (var writer = new StringCollectionTextWriter(_viewContext.Writer.Encoding))
|
||||
var viewBuffer = new ViewBuffer(_bufferScope, viewName);
|
||||
using (var writer = new HtmlContentWrapperTextWriter(viewBuffer, _viewContext.Writer.Encoding))
|
||||
{
|
||||
// Forcing synchronous behavior so users don't have to await templates.
|
||||
var view = viewEngineResult.View;
|
||||
|
|
@ -127,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures.Internal
|
|||
var viewContext = new ViewContext(_viewContext, viewEngineResult.View, _viewData, writer);
|
||||
var renderTask = viewEngineResult.View.RenderAsync(viewContext);
|
||||
renderTask.GetAwaiter().GetResult();
|
||||
return writer.Content;
|
||||
return writer.ContentBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@
|
|||
"version": "1.0.0-*",
|
||||
"type": "build"
|
||||
},
|
||||
"Microsoft.Extensions.WebEncoders": "1.0.0-*"
|
||||
"Microsoft.Extensions.WebEncoders": "1.0.0-*",
|
||||
"System.Buffers": "4.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"net451": {},
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
|
|||
{
|
||||
// Arrange
|
||||
var collection = new ServiceCollection();
|
||||
var htmlEncoder = new HtmlTestEncoder();
|
||||
|
||||
collection.Configure<RazorViewEngineOptions>(options =>
|
||||
{
|
||||
|
|
@ -123,9 +124,10 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
|
|||
LanguageViewLocationExpanderFormat.Suffix,
|
||||
setupAction: null);
|
||||
|
||||
|
||||
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>)));
|
||||
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer), typeof(TestViewLocalizer)));
|
||||
collection.Add(ServiceDescriptor.Singleton(typeof(HtmlEncoder), typeof(HtmlTestEncoder)));
|
||||
collection.Add(ServiceDescriptor.Singleton(typeof(HtmlEncoder), htmlEncoder));
|
||||
|
||||
// Assert
|
||||
Assert.Collection(collection,
|
||||
|
|
@ -172,7 +174,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal
|
|||
service =>
|
||||
{
|
||||
Assert.Equal(typeof(HtmlEncoder), service.ServiceType);
|
||||
Assert.Equal(typeof(HtmlTestEncoder), service.ImplementationInstance);
|
||||
Assert.Same(htmlEncoder, service.ImplementationInstance);
|
||||
Assert.Equal(ServiceLifetime.Singleton, service.Lifetime);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,22 +5,22 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var page = CreatePage(v =>
|
||||
{
|
||||
v.HtmlEncoder = new HtmlTestEncoder();
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), v.Path);
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), v.Path);
|
||||
v.StartTagHelperWritingScope(new RazorTextWriter(TextWriter.Null, buffer, v.HtmlEncoder));
|
||||
v.Write("Hello ");
|
||||
v.Write("World!");
|
||||
|
|
@ -1127,7 +1127,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public async Task Write_WithHtmlString_WritesValueWithoutEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), string.Empty);
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), string.Empty);
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
var page = CreatePage(p =>
|
||||
|
|
@ -1177,8 +1177,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
private static ViewContext CreateViewContext(TextWriter writer = null)
|
||||
{
|
||||
writer = writer ?? new StringWriter();
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddSingleton<IViewBufferScope, TestViewBufferScope>()
|
||||
.BuildServiceProvider();
|
||||
httpContext.RequestServices = serviceProvider;
|
||||
var actionContext = new ActionContext(
|
||||
new DefaultHttpContext(),
|
||||
httpContext,
|
||||
new RouteData(),
|
||||
new ActionDescriptor());
|
||||
return new ViewContext(
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ 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.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
var expected = new object[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718" };
|
||||
var unbufferedWriter = new Mock<TextWriter>();
|
||||
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||
var testClass = new TestClass();
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var unbufferedWriter = new Mock<TextWriter> { CallBase = true };
|
||||
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||
var buffer1 = new[] { 'a', 'b', 'c', 'd' };
|
||||
var buffer2 = new[] { 'd', 'e', 'f' };
|
||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var unbufferedWriter = new Mock<TextWriter>();
|
||||
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var newLine = Environment.NewLine;
|
||||
var expected = new List<object> { "False", newLine, "1.1", newLine, "3", newLine };
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
// Arrange
|
||||
var unbufferedWriter = new Mock<TextWriter>();
|
||||
unbufferedWriter.SetupGet(w => w.Encoding).Returns(Encoding.UTF8);
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(unbufferedWriter.Object, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -172,7 +172,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
var newLine = Environment.NewLine;
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -193,7 +193,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
var input2 = "from";
|
||||
var input3 = "ASP";
|
||||
var input4 = ".Net";
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(TextWriter.Null, buffer, new HtmlTestEncoder());
|
||||
|
||||
// Act
|
||||
|
|
@ -212,7 +212,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
{
|
||||
// Arrange
|
||||
var stringWriter = new StringWriter();
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new RazorTextWriter(stringWriter, buffer, new HtmlTestEncoder());
|
||||
writer.Flush();
|
||||
|
||||
|
|
@ -225,10 +225,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
Assert.Equal("Hello, world!", stringWriter.ToString());
|
||||
}
|
||||
|
||||
private static object[] GetValues(RazorBuffer buffer)
|
||||
private static object[] GetValues(ViewBuffer buffer)
|
||||
{
|
||||
return buffer.BufferSegments
|
||||
.SelectMany(c => c.Data)
|
||||
.SelectMany(c => c)
|
||||
.Select(d => d.Value)
|
||||
.TakeWhile(d => d != null)
|
||||
.ToArray();
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ using System.Threading.Tasks;
|
|||
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.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
|
@ -1661,7 +1661,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddScoped<IRazorBufferScope, TestRazorBufferScope>()
|
||||
.AddScoped<IViewBufferScope, TestViewBufferScope>()
|
||||
.BuildServiceProvider();
|
||||
httpContext.RequestServices = serviceProvider;
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,8 @@
|
|||
"compile": [
|
||||
"../Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileProvider.cs",
|
||||
"../Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileInfo.cs",
|
||||
"../Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileTrigger.cs"
|
||||
"../Microsoft.AspNet.Mvc.Razor.Host.Test/TestFileTrigger.cs",
|
||||
"../Microsoft.AspNet.Mvc.ViewFeatures.Test/TestViewBufferScope.cs"
|
||||
],
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Http": "1.0.0-*",
|
||||
|
|
|
|||
|
|
@ -5,19 +5,20 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
||||
{
|
||||
public class RazorBufferTest
|
||||
public class ViewBufferTest
|
||||
{
|
||||
[Fact]
|
||||
public void Append_AddsStringRazorValue()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
|
||||
// Act
|
||||
buffer.Append("Hello world");
|
||||
|
|
@ -25,14 +26,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
// Assert
|
||||
var segment = Assert.Single(buffer.BufferSegments);
|
||||
Assert.Equal(1, buffer.CurrentCount);
|
||||
Assert.Equal("Hello world", segment.Data.Array[0].Value);
|
||||
Assert.Equal("Hello world", segment[0].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Append_AddsHtmlContentRazorValue()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var content = new HtmlString("hello-world");
|
||||
|
||||
// Act
|
||||
|
|
@ -41,14 +42,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
// Assert
|
||||
var segment = Assert.Single(buffer.BufferSegments);
|
||||
Assert.Equal(1, buffer.CurrentCount);
|
||||
Assert.Same(content, segment.Data.Array[0].Value);
|
||||
Assert.Same(content, segment[0].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppendHtml_AddsHtmlStringValues()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var value = "Hello world";
|
||||
|
||||
// Act
|
||||
|
|
@ -57,7 +58,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
// Assert
|
||||
var segment = Assert.Single(buffer.BufferSegments);
|
||||
Assert.Equal(1, buffer.CurrentCount);
|
||||
var htmlString = Assert.IsType<HtmlString>(segment.Data.Array[0].Value);
|
||||
var htmlString = Assert.IsType<HtmlString>(segment[0].Value);
|
||||
Assert.Equal("Hello world", htmlString.ToString());
|
||||
}
|
||||
|
||||
|
|
@ -65,8 +66,8 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
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());
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var expected = Enumerable.Range(0, TestViewBufferScope.DefaultBufferSize).Select(i => i.ToString());
|
||||
|
||||
// Act
|
||||
foreach (var item in expected)
|
||||
|
|
@ -79,51 +80,22 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
// Assert
|
||||
Assert.Equal(2, buffer.CurrentCount);
|
||||
Assert.Collection(buffer.BufferSegments,
|
||||
segment => Assert.Equal(expected, segment.Data.Array.Select(v => v.Value)),
|
||||
segment => Assert.Equal(expected, segment.Select(v => v.Value)),
|
||||
segment =>
|
||||
{
|
||||
var array = segment.Data.Array;
|
||||
var array = segment;
|
||||
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)]
|
||||
[InlineData(TestViewBufferScope.DefaultBufferSize + 3)]
|
||||
public void Clear_ResetsBackingBufferAndIndex(int valuesToWrite)
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
|
||||
// Act
|
||||
for (var i = 0; i < valuesToWrite; i++)
|
||||
|
|
@ -136,14 +108,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
// Assert
|
||||
var segment = Assert.Single(buffer.BufferSegments);
|
||||
Assert.Equal(1, buffer.CurrentCount);
|
||||
Assert.Equal("world", segment.Data.Array[0].Value);
|
||||
Assert.Equal("world", segment[0].Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteTo_WritesSelf_WhenWriterIsHtmlTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var htmlWriter = new Mock<HtmlTextWriter>();
|
||||
htmlWriter.Setup(w => w.Write(buffer)).Verifiable();
|
||||
|
||||
|
|
@ -159,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
public void WriteTo_WritesRazorValues_ToTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(), "some-name");
|
||||
var writer = new StringWriter();
|
||||
|
||||
// Act
|
||||
|
|
@ -180,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Buffer
|
|||
public void WriteTo_WritesRazorValuesFromAllBuffers(int valuesToWrite)
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(1, 5), "some-name");
|
||||
var buffer = new ViewBuffer(new TestViewBufferScope(4), "some-name");
|
||||
var writer = new StringWriter();
|
||||
var expected = string.Join("", Enumerable.Range(0, valuesToWrite).Select(_ => "abc"));
|
||||
|
||||
|
|
@ -18,7 +18,9 @@ using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
|||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Moq;
|
||||
|
|
@ -240,21 +242,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
|
||||
.Returns(urlHelper);
|
||||
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(ICompositeViewEngine)))
|
||||
.Returns(viewEngine);
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IUrlHelperFactory)))
|
||||
.Returns(urlHelperFactory.Object);
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
|
||||
.Returns(new Mock<IViewComponentHelper>().Object);
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
|
||||
.Returns(new Mock<IViewComponentHelper>().Object);
|
||||
|
||||
httpContext.RequestServices = serviceProvider.Object;
|
||||
if (htmlGenerator == null)
|
||||
{
|
||||
htmlGenerator = new DefaultHtmlGenerator(
|
||||
|
|
@ -270,6 +257,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
htmlGenerator,
|
||||
viewEngine,
|
||||
provider,
|
||||
new TestViewBufferScope(),
|
||||
new HtmlTestEncoder(),
|
||||
UrlEncoder.Default,
|
||||
JavaScriptEncoder.Default);
|
||||
|
|
@ -278,14 +266,22 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
innerHelper = innerHelperWrapper(innerHelper);
|
||||
}
|
||||
serviceProvider
|
||||
.Setup(s => s.GetService(typeof(IHtmlHelper)))
|
||||
.Returns(() => innerHelper);
|
||||
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddSingleton(viewEngine)
|
||||
.AddSingleton(urlHelperFactory.Object)
|
||||
.AddSingleton(Mock.Of<IViewComponentHelper>())
|
||||
.AddSingleton(innerHelper)
|
||||
.AddSingleton<IViewBufferScope, TestViewBufferScope>()
|
||||
.BuildServiceProvider();
|
||||
|
||||
httpContext.RequestServices = serviceProvider;
|
||||
|
||||
var htmlHelper = new HtmlHelper<TModel>(
|
||||
htmlGenerator,
|
||||
viewEngine,
|
||||
provider,
|
||||
new TestViewBufferScope(),
|
||||
new HtmlTestEncoder(),
|
||||
UrlEncoder.Default,
|
||||
JavaScriptEncoder.Default);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.TestCommon;
|
||||
using Microsoft.AspNet.Mvc.ViewEngines;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -1567,6 +1568,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
new Mock<IHtmlGenerator>(MockBehavior.Strict).Object,
|
||||
new Mock<ICompositeViewEngine>(MockBehavior.Strict).Object,
|
||||
metadataProvider,
|
||||
new TestViewBufferScope(),
|
||||
new Mock<HtmlEncoder>(MockBehavior.Strict).Object,
|
||||
new Mock<UrlEncoder>(MockBehavior.Strict).Object,
|
||||
new Mock<JavaScriptEncoder>(MockBehavior.Strict).Object)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
|
@ -58,7 +59,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
htmlHelperOptions: new HtmlHelperOptions());
|
||||
var view = Mock.Of<IView>();
|
||||
var viewData = new ViewDataDictionary(originalContext.ViewData);
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var writer = new HtmlContentWrapperTextWriter(new HtmlContentBuilder(), Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
var context = new ViewContext(originalContext, view, viewData, writer);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// 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.ViewFeatures.Buffer
|
||||
{
|
||||
public class TestViewBufferScope : IViewBufferScope
|
||||
{
|
||||
public const int DefaultBufferSize = 128;
|
||||
private readonly int _bufferSize;
|
||||
|
||||
public TestViewBufferScope(int bufferSize = DefaultBufferSize)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public ViewBufferValue[] GetSegment() => new ViewBufferValue[_bufferSize];
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNet.Mvc.ViewFeatures.Buffer;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -482,6 +483,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
services.AddSingleton<ITempDataDictionaryFactory, TempDataDictionaryFactory>();
|
||||
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
|
||||
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
|
||||
services.AddSingleton<IViewBufferScope, TestViewBufferScope>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Razor.Buffer;
|
||||
using Microsoft.AspNet.Html;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
public class HtmlContentWrapperTextWriterTest
|
||||
{
|
||||
|
|
@ -20,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
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 buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
|
|
@ -29,12 +32,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
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]);
|
||||
Assert.Collection(buffer.Values,
|
||||
value => Assert.Equal("bcd", value),
|
||||
value => Assert.Equal("ef", value),
|
||||
value => Assert.Equal("j", value),
|
||||
value => Assert.Equal(Environment.NewLine, value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -42,14 +44,15 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
// Arrange
|
||||
var charArray = Enumerable.Range(0, 2050).Select(_ => 'a').ToArray();
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
writer.Write(charArray);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(GetValues(buffer),
|
||||
Assert.Collection(
|
||||
buffer.Values,
|
||||
value => Assert.Equal(new string('a', 1024), value),
|
||||
value => Assert.Equal(new string('a', 1024), value),
|
||||
value => Assert.Equal("aa", value));
|
||||
|
|
@ -59,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public void Write_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
|
|
@ -68,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
GetValues(buffer),
|
||||
buffer.Values,
|
||||
item => Assert.Same(content, item));
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +79,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public void Write_Object_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
|
|
@ -85,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
GetValues(buffer),
|
||||
buffer.Values,
|
||||
item => Assert.Same(content, item));
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +96,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
public void WriteLine_Object_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
|
|
@ -102,7 +105,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
GetValues(buffer),
|
||||
buffer.Values,
|
||||
item => Assert.Same(content, item),
|
||||
item => Assert.Equal(Environment.NewLine, item));
|
||||
}
|
||||
|
|
@ -116,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
var input2 = "from";
|
||||
var input3 = "ASP";
|
||||
var input4 = ".Net";
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
|
|
@ -126,15 +129,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
await writer.WriteLineAsync(input4);
|
||||
|
||||
// Assert
|
||||
var actual = GetValues(buffer);
|
||||
Assert.Equal(new object[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||
Assert.Equal(new[] { input1, input2, newLine, input3, input4, newLine }, buffer.Values);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_HtmlContent_WritesToBuffer()
|
||||
{
|
||||
// Arrange
|
||||
var buffer = new RazorBuffer(new TestRazorBufferScope(), "some-name");
|
||||
var buffer = new TestHtmlContentBuilder();
|
||||
var writer = new HtmlContentWrapperTextWriter(buffer, Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
|
|
@ -143,17 +145,42 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
GetValues(buffer),
|
||||
buffer.Values,
|
||||
item => Assert.Same(content, item));
|
||||
}
|
||||
|
||||
private static object[] GetValues(RazorBuffer buffer)
|
||||
private class TestHtmlContentBuilder : IHtmlContentBuilder
|
||||
{
|
||||
return buffer.BufferSegments
|
||||
.SelectMany(c => c.Data)
|
||||
.Select(d => d.Value)
|
||||
.TakeWhile(d => d != null)
|
||||
.ToArray();
|
||||
public List<object> Values { get; } = new List<object>();
|
||||
|
||||
public IHtmlContentBuilder Append(string unencoded)
|
||||
{
|
||||
Values.Add(unencoded);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IHtmlContentBuilder Append(IHtmlContent content)
|
||||
{
|
||||
Values.Add(content);
|
||||
return this;
|
||||
}
|
||||
|
||||
public IHtmlContentBuilder AppendHtml(string encoded)
|
||||
{
|
||||
Values.Add(new HtmlString(encoded));
|
||||
return this;
|
||||
}
|
||||
|
||||
public IHtmlContentBuilder Clear()
|
||||
{
|
||||
Values.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public void WriteTo(TextWriter writer, HtmlEncoder encoder)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,214 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.WebEncoders.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
public class StringCollectionTextWriterTest
|
||||
{
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void Write_WritesDataTypes_ToBuffer()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[] { "True", "3", "18446744073709551615", "Hello world", "3.14", "2.718", "m" };
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
writer.Write(true);
|
||||
writer.Write(3);
|
||||
writer.Write(ulong.MaxValue);
|
||||
writer.Write(new TestClass());
|
||||
writer.Write(3.14);
|
||||
writer.Write(2.718m);
|
||||
writer.Write('m');
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture]
|
||||
public void WriteLine_WritesDataTypes_ToBuffer()
|
||||
{
|
||||
// Arrange
|
||||
var newLine = Environment.NewLine;
|
||||
var expected = new List<object> { "False", newLine, "1.1", newLine, "3", newLine };
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
writer.WriteLine(false);
|
||||
writer.WriteLine(1.1f);
|
||||
writer.WriteLine(3L);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, writer.Entries);
|
||||
}
|
||||
|
||||
[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 StringCollectionTextWriter(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 buffer = writer.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 StringCollectionTextWriter(Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
writer.WriteLine();
|
||||
await writer.WriteLineAsync();
|
||||
|
||||
// Assert
|
||||
var actual = writer.Entries;
|
||||
Assert.Equal<object>(new[] { newLine, newLine }, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Write_WritesStringBuffer()
|
||||
{
|
||||
// Arrange
|
||||
var newLine = Environment.NewLine;
|
||||
var input1 = "Hello";
|
||||
var input2 = "from";
|
||||
var input3 = "ASP";
|
||||
var input4 = ".Net";
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
writer.Write(input1);
|
||||
writer.WriteLine(input2);
|
||||
await writer.WriteAsync(input3);
|
||||
await writer.WriteLineAsync(input4);
|
||||
|
||||
// Assert
|
||||
var actual = writer.Entries;
|
||||
Assert.Equal(new[] { input1, input2, newLine, input3, input4, newLine }, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
// Act
|
||||
writer.Write(content);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
writer.Entries,
|
||||
item => Assert.Same(content, item));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Object_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
// Act
|
||||
writer.Write((object)content);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
writer.Entries,
|
||||
item => Assert.Same(content, item));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteLine_Object_HtmlContent_AddsToEntries()
|
||||
{
|
||||
// Arrange
|
||||
var writer = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var content = new HtmlString("Hello, world!");
|
||||
|
||||
// Act
|
||||
writer.WriteLine(content);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
writer.Entries,
|
||||
item => Assert.Same(content, item),
|
||||
item => Assert.Equal(Environment.NewLine, item));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy_CopiesContent_IfTargetTextWriterIsAStringCollectionTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var source = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var target = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
|
||||
// Act
|
||||
source.Write("Hello world");
|
||||
source.Write(new char[1], 0, 1);
|
||||
source.CopyTo(target, new HtmlTestEncoder());
|
||||
|
||||
// Assert
|
||||
// Make sure content was written to the source.
|
||||
Assert.Equal(2, source.Entries.Count);
|
||||
Assert.Equal(1, target.Entries.Count);
|
||||
|
||||
var entry = Assert.Single(target.Entries);
|
||||
Assert.Same(source.Content, entry);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy_WritesContent_IfTargetTextWriterIsNotAStringCollectionTextWriter()
|
||||
{
|
||||
// Arrange
|
||||
var source = new StringCollectionTextWriter(Encoding.UTF8);
|
||||
var target = new StringWriter();
|
||||
var expected = @"Hello world" + Environment.NewLine + "abc";
|
||||
|
||||
// Act
|
||||
source.WriteLine("Hello world");
|
||||
source.Write(new[] { 'x', 'a', 'b', 'c' }, 1, 3);
|
||||
source.CopyTo(target, new HtmlTestEncoder());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, target.ToString());
|
||||
}
|
||||
|
||||
private class TestClass
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "Hello world";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue