parent
39376617cc
commit
4ec6da1ed3
|
|
@ -45,10 +45,9 @@
|
||||||
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
|
<strong>Marketing:</strong> <a href="mailto:Marketing@example.com">Marketing@example.com</a>
|
||||||
</address>
|
</address>
|
||||||
|
|
||||||
@* Remove the Wait() calls once we add support for async sections *@
|
|
||||||
@{
|
@{
|
||||||
FlushAsync().Wait();
|
await FlushAsync();
|
||||||
Task.Delay(TimeSpan.FromSeconds(1)).Wait();
|
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||||
}
|
}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
body { padding-top: 0px; }
|
body { padding-top: 0px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@RenderSection("header", required: false)
|
@await RenderSectionAsync("header", required: false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||||
|
|
@ -37,6 +37,6 @@
|
||||||
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
|
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@RenderSection("footer", required: false)
|
@await RenderSectionAsync("footer", required: false)
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Internal
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility methods for dealing with <see cref="Task"/>.
|
/// Utility methods for dealing with <see cref="Task"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class TaskHelper
|
internal static class TaskHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Waits for the task to complete and throws the first faulting exception if the task is faulted.
|
/// Waits for the task to complete and throws the first faulting exception if the task is faulted.
|
||||||
|
|
@ -21,5 +21,18 @@ namespace Microsoft.AspNet.Mvc.Internal
|
||||||
{
|
{
|
||||||
task.GetAwaiter().GetResult();
|
task.GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits for the task to complete and throws the first faulting exception if the task is faulted.
|
||||||
|
/// It preserves the original stack trace when throwing the exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Invoking this method is equivalent to calling <see cref="Task{TResult}.Result"/> on the
|
||||||
|
/// <paramref name="task"/> if it is not completed.
|
||||||
|
/// </remarks>
|
||||||
|
public static TVal WaitAndThrowIfFaulted<TVal>(Task<TVal> task)
|
||||||
|
{
|
||||||
|
return task.GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,7 +22,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the action invoked to render the body.
|
/// Gets or sets the action invoked to render the body.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO: https://github.com/aspnet/Mvc/issues/845 tracks making this async
|
|
||||||
Action<TextWriter> RenderBodyDelegate { get; set; }
|
Action<TextWriter> RenderBodyDelegate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -53,12 +52,12 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the sections that can be rendered by this page.
|
/// Gets or sets the sections that can be rendered by this page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, HelperResult> PreviousSectionWriters { get; set; }
|
Dictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the sections that are defined by this page.
|
/// Gets the sections that are defined by this page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, HelperResult> SectionWriters { get; }
|
Dictionary<string, RenderAsyncDelegate> SectionWriters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders the page and writes the output to the <see cref="ViewContext.Writer"/>.
|
/// Renders the page and writes the output to the <see cref="ViewContext.Writer"/>.
|
||||||
|
|
|
||||||
|
|
@ -205,17 +205,17 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// {0} can only be called from a layout page.
|
/// {0} can only be called from a layout page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string RenderBodyCannotBeCalled
|
internal static string RazorPage_MethodCannotBeCalled
|
||||||
{
|
{
|
||||||
get { return GetString("RenderBodyCannotBeCalled"); }
|
get { return GetString("RazorPage_MethodCannotBeCalled"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// {0} can only be called from a layout page.
|
/// {0} can only be called from a layout page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatRenderBodyCannotBeCalled(object p0)
|
internal static string FormatRazorPage_MethodCannotBeCalled(object p0)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("RenderBodyCannotBeCalled"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("RazorPage_MethodCannotBeCalled"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -251,7 +251,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// {0} has already been called for the section named '{1}'.
|
/// The section named '{0}' has already been rendered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string SectionAlreadyRendered
|
internal static string SectionAlreadyRendered
|
||||||
{
|
{
|
||||||
|
|
@ -259,11 +259,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// {0} has already been called for the section named '{1}'.
|
/// The section named '{0}' has already been rendered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatSectionAlreadyRendered(object p0, object p1)
|
internal static string FormatSectionAlreadyRendered(object p0)
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("SectionAlreadyRendered"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("SectionAlreadyRendered"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -362,22 +362,6 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ViewMustBeContextualized"), p0, p1);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ViewMustBeContextualized"), p0, p1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method '{0}' cannot be invoked by this view.
|
|
||||||
/// </summary>
|
|
||||||
internal static string View_MethodCannotBeCalled
|
|
||||||
{
|
|
||||||
get { return GetString("View_MethodCannotBeCalled"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method '{0}' cannot be invoked by this view.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatView_MethodCannotBeCalled(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("View_MethodCannotBeCalled"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
public RazorPage()
|
public RazorPage()
|
||||||
{
|
{
|
||||||
SectionWriters = new Dictionary<string, HelperResult>(StringComparer.OrdinalIgnoreCase);
|
SectionWriters = new Dictionary<string, RenderAsyncDelegate>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_writerScopes = new Stack<TextWriter>();
|
_writerScopes = new Stack<TextWriter>();
|
||||||
}
|
}
|
||||||
|
|
@ -105,10 +105,10 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public bool IsLayoutBeingRendered { get; set; }
|
public bool IsLayoutBeingRendered { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<string, HelperResult> PreviousSectionWriters { get; set; }
|
public Dictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<string, HelperResult> SectionWriters { get; private set; }
|
public Dictionary<string, RenderAsyncDelegate> SectionWriters { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public abstract Task ExecuteAsync();
|
public abstract Task ExecuteAsync();
|
||||||
|
|
@ -215,7 +215,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual void WriteTo(TextWriter writer, object value)
|
public virtual void WriteTo(TextWriter writer, object value)
|
||||||
{
|
{
|
||||||
if (value != null)
|
if (value != null && value != HtmlString.Empty)
|
||||||
{
|
{
|
||||||
var helperResult = value as HelperResult;
|
var helperResult = value as HelperResult;
|
||||||
if (helperResult != null)
|
if (helperResult != null)
|
||||||
|
|
@ -415,7 +415,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
if (RenderBodyDelegate == null)
|
if (RenderBodyDelegate == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatRenderBodyCannotBeCalled("RenderBody"));
|
var message = Resources.FormatRazorPage_MethodCannotBeCalled(nameof(RenderBody));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderedBody = true;
|
_renderedBody = true;
|
||||||
|
|
@ -424,11 +425,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a named content section in the page that can be invoked in a Layout page using
|
/// Creates a named content section in the page that can be invoked in a Layout page using
|
||||||
/// <see cref="RenderSection(string)"/> or <see cref="RenderSection(string, bool)"/>.
|
/// <see cref="RenderSection(string)"/> or <see cref="RenderSectionAsync(string, bool)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the section to create.</param>
|
/// <param name="name">The name of the section to create.</param>
|
||||||
/// <param name="section">The <see cref="HelperResult"/> to execute when rendering the section.</param>
|
/// <param name="section">The <see cref="RenderAsyncDelegate"/> to execute when rendering the section.</param>
|
||||||
public void DefineSection(string name, HelperResult section)
|
public void DefineSection(string name, RenderAsyncDelegate section)
|
||||||
{
|
{
|
||||||
if (SectionWriters.ContainsKey(name))
|
if (SectionWriters.ContainsKey(name))
|
||||||
{
|
{
|
||||||
|
|
@ -439,33 +440,84 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
public bool IsSectionDefined([NotNull] string name)
|
public bool IsSectionDefined([NotNull] string name)
|
||||||
{
|
{
|
||||||
EnsureMethodCanBeInvoked("IsSectionDefined");
|
EnsureMethodCanBeInvoked(nameof(IsSectionDefined));
|
||||||
return PreviousSectionWriters.ContainsKey(name);
|
return PreviousSectionWriters.ContainsKey(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HelperResult RenderSection([NotNull] string name)
|
/// <summary>
|
||||||
|
/// In layout pages, renders the content of the section named <paramref name="name"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the section to render.</param>
|
||||||
|
/// <returns>Returns a HtmlString that contains the rendered HTML.</returns>
|
||||||
|
public HtmlString RenderSection([NotNull] string name)
|
||||||
{
|
{
|
||||||
return RenderSection(name, required: true);
|
return RenderSection(name, required: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HelperResult RenderSection([NotNull] string name, bool required)
|
/// <summary>
|
||||||
|
/// In layout pages, renders the content of the section named <paramref name="name"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The section to render.</param>
|
||||||
|
/// <param name="required">Indicates if this section must be rendered.</param>
|
||||||
|
/// <returns>Returns a HtmlString that contains the rendered HTML.</returns>
|
||||||
|
public HtmlString RenderSection([NotNull] string name, bool required)
|
||||||
{
|
{
|
||||||
EnsureMethodCanBeInvoked("RenderSection");
|
EnsureMethodCanBeInvoked(nameof(RenderSection));
|
||||||
if (_renderedSections.Contains(name))
|
|
||||||
|
var task = RenderSectionAsyncCore(name, required);
|
||||||
|
return TaskHelper.WaitAndThrowIfFaulted(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// In layout pages, asynchronously renders the content of the section named <paramref name="name"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The section to render.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that on completion returns a <see cref="HtmlString"/> containing
|
||||||
|
/// the rendered HTML.</returns>
|
||||||
|
public Task<HtmlString> RenderSectionAsync([NotNull] string name)
|
||||||
|
{
|
||||||
|
return RenderSectionAsync(name, required: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// In layout pages, asynchronously renders the content of the section named <paramref name="name"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The section to render.</param>
|
||||||
|
/// <returns>A <see cref="Task{TResult}"/> that on completion returns a <see cref="HtmlString"/> containing
|
||||||
|
/// the rendered HTML.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">if <paramref name="required"/> is <c>true</c> and the section
|
||||||
|
/// was not registered using the <c>@section</c> in the Razor page.</exception>
|
||||||
|
public async Task<HtmlString> RenderSectionAsync([NotNull] string name, bool required)
|
||||||
|
{
|
||||||
|
EnsureMethodCanBeInvoked(nameof(RenderSectionAsync));
|
||||||
|
return await RenderSectionAsyncCore(name, required);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<HtmlString> RenderSectionAsyncCore(string sectionName, bool required)
|
||||||
|
{
|
||||||
|
if (_renderedSections.Contains(sectionName))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatSectionAlreadyRendered("RenderSection", name));
|
var message = Resources.FormatSectionAlreadyRendered(sectionName);
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperResult action;
|
RenderAsyncDelegate renderDelegate;
|
||||||
if (PreviousSectionWriters.TryGetValue(name, out action))
|
if (PreviousSectionWriters.TryGetValue(sectionName, out renderDelegate))
|
||||||
{
|
{
|
||||||
_renderedSections.Add(name);
|
_renderedSections.Add(sectionName);
|
||||||
return action;
|
|
||||||
|
using (var writer = new StringCollectionTextWriter(Output.Encoding))
|
||||||
|
{
|
||||||
|
await renderDelegate(writer);
|
||||||
|
|
||||||
|
// Returning a disposed StringCollectionTextWriter is safe.
|
||||||
|
return new HtmlString(writer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (required)
|
else if (required)
|
||||||
{
|
{
|
||||||
// If the section is not found, and it is not optional, throw an error.
|
// If the section is not found, and it is not optional, throw an error.
|
||||||
throw new InvalidOperationException(Resources.FormatSectionNotDefined(name));
|
throw new InvalidOperationException(Resources.FormatSectionNotDefined(sectionName));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -518,7 +570,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
if (RenderBodyDelegate != null && !_renderedBody)
|
if (RenderBodyDelegate != null && !_renderedBody)
|
||||||
{
|
{
|
||||||
// If a body was defined, then RenderBody should have been called.
|
// If a body was defined, then RenderBody should have been called.
|
||||||
throw new InvalidOperationException(Resources.FormatRenderBodyNotCalled("RenderBody"));
|
var message = Resources.FormatRenderBodyNotCalled(nameof(RenderBody));
|
||||||
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -536,7 +589,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
if (PreviousSectionWriters == null)
|
if (PreviousSectionWriters == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatView_MethodCannotBeCalled(methodName));
|
throw new InvalidOperationException(Resources.FormatRazorPage_MethodCannotBeCalled(methodName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
public delegate Task RenderAsyncDelegate(TextWriter writer);
|
||||||
|
}
|
||||||
|
|
@ -153,7 +153,7 @@
|
||||||
<data name="RazorPage_NullModelMetadata" xml:space="preserve">
|
<data name="RazorPage_NullModelMetadata" xml:space="preserve">
|
||||||
<value>The {0} was unable to provide metadata for expression '{1}'.</value>
|
<value>The {0} was unable to provide metadata for expression '{1}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RenderBodyCannotBeCalled" xml:space="preserve">
|
<data name="RazorPage_MethodCannotBeCalled" xml:space="preserve">
|
||||||
<value>{0} can only be called from a layout page.</value>
|
<value>{0} can only be called from a layout page.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RenderBodyNotCalled" xml:space="preserve">
|
<data name="RenderBodyNotCalled" xml:space="preserve">
|
||||||
|
|
@ -163,7 +163,7 @@
|
||||||
<value>Section '{0}' is already defined.</value>
|
<value>Section '{0}' is already defined.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SectionAlreadyRendered" xml:space="preserve">
|
<data name="SectionAlreadyRendered" xml:space="preserve">
|
||||||
<value>{0} has already been called for the section named '{1}'.</value>
|
<value>The section named '{0}' has already been rendered.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SectionNotDefined" xml:space="preserve">
|
<data name="SectionNotDefined" xml:space="preserve">
|
||||||
<value>Section '{0}' is not defined.</value>
|
<value>Section '{0}' is not defined.</value>
|
||||||
|
|
@ -183,7 +183,4 @@
|
||||||
<data name="ViewMustBeContextualized" xml:space="preserve">
|
<data name="ViewMustBeContextualized" xml:space="preserve">
|
||||||
<value>The '{0}' method must be called before '{1}' can be invoked.</value>
|
<value>The '{0}' method must be called before '{1}' can be invoked.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="View_MethodCannotBeCalled" xml:space="preserve">
|
|
||||||
<value>The method '{0}' cannot be invoked by this view.</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -17,6 +17,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
public class RazorPageTest
|
public class RazorPageTest
|
||||||
{
|
{
|
||||||
|
private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = async writer => { };
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task WritingScopesRedirectContentWrittenToViewContextWriter()
|
public async Task WritingScopesRedirectContentWrittenToViewContextWriter()
|
||||||
{
|
{
|
||||||
|
|
@ -135,8 +137,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var viewContext = CreateViewContext();
|
var viewContext = CreateViewContext();
|
||||||
var page = CreatePage(v =>
|
var page = CreatePage(v =>
|
||||||
{
|
{
|
||||||
v.DefineSection("qux", new HelperResult(action: null));
|
v.DefineSection("qux", _nullRenderAsyncDelegate);
|
||||||
v.DefineSection("qux", new HelperResult(action: null));
|
v.DefineSection("qux", _nullRenderAsyncDelegate);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -151,23 +153,22 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public async Task RenderSection_RendersSectionFromPreviousPage()
|
public async Task RenderSection_RendersSectionFromPreviousPage()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new HelperResult(action: null);
|
var expected = "Hello world";
|
||||||
var viewContext = CreateViewContext();
|
var viewContext = CreateViewContext();
|
||||||
HelperResult actual = null;
|
|
||||||
var page = CreatePage(v =>
|
var page = CreatePage(v =>
|
||||||
{
|
{
|
||||||
actual = v.RenderSection("bar");
|
v.Write(v.RenderSection("bar"));
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "bar", expected }
|
{ "bar", writer => writer.WriteAsync(expected) }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await page.ExecuteAsync();
|
await page.ExecuteAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(actual, expected);
|
Assert.Equal(expected, page.RenderedContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -184,7 +185,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await page.ExecuteAsync();
|
await page.ExecuteAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("The method 'RenderSection' cannot be invoked by this view.",
|
Assert.Equal("RenderSection can only be called from a layout page.",
|
||||||
ex.Message);
|
ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,14 +193,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public async Task RenderSection_ThrowsIfRequiredSectionIsNotFound()
|
public async Task RenderSection_ThrowsIfRequiredSectionIsNotFound()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new HelperResult(action: null);
|
|
||||||
var page = CreatePage(v =>
|
var page = CreatePage(v =>
|
||||||
{
|
{
|
||||||
v.RenderSection("bar");
|
v.RenderSection("bar");
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "baz", expected }
|
{ "baz", _nullRenderAsyncDelegate }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -217,7 +217,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
ExceptionAssert.Throws<InvalidOperationException>(() => page.IsSectionDefined("foo"),
|
ExceptionAssert.Throws<InvalidOperationException>(() => page.IsSectionDefined("foo"),
|
||||||
"The method 'IsSectionDefined' cannot be invoked by this view.");
|
"IsSectionDefined can only be called from a layout page.");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -231,9 +231,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.RenderSection("baz");
|
v.RenderSection("baz");
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "baz", new HelperResult(writer => { }) }
|
{ "baz", _nullRenderAsyncDelegate }
|
||||||
};
|
};
|
||||||
page.RenderBodyDelegate = CreateBodyAction("body-content");
|
page.RenderBodyDelegate = CreateBodyAction("body-content");
|
||||||
|
|
||||||
|
|
@ -255,9 +255,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.RenderSection("baz");
|
v.RenderSection("baz");
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "baz", new HelperResult(writer => { }) }
|
{ "baz", _nullRenderAsyncDelegate }
|
||||||
};
|
};
|
||||||
page.RenderBodyDelegate = CreateBodyAction("body-content");
|
page.RenderBodyDelegate = CreateBodyAction("body-content");
|
||||||
|
|
||||||
|
|
@ -278,32 +278,92 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.RenderSection("header");
|
v.RenderSection("header");
|
||||||
v.RenderSection("header");
|
v.RenderSection("header");
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "header", new HelperResult(writer => { }) }
|
{ "header", _nullRenderAsyncDelegate }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("RenderSection has already been called for the section named 'header'.", ex.Message);
|
Assert.Equal("The section named 'header' has already been rendered.", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RenderSectionAsync_ThrowsIfSectionIsRenderedMoreThanOnce()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = new HelperResult(action: null);
|
||||||
|
var page = CreatePage(async v =>
|
||||||
|
{
|
||||||
|
await v.RenderSectionAsync("header");
|
||||||
|
await v.RenderSectionAsync("header");
|
||||||
|
});
|
||||||
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
|
{
|
||||||
|
{ "header", _nullRenderAsyncDelegate }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("The section named 'header' has already been rendered.", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RenderSectionAsync_ThrowsIfSectionIsRenderedMoreThanOnce_WithSyncMethod()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = new HelperResult(action: null);
|
||||||
|
var page = CreatePage(async v =>
|
||||||
|
{
|
||||||
|
v.RenderSection("header");
|
||||||
|
await v.RenderSectionAsync("header");
|
||||||
|
});
|
||||||
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
|
{
|
||||||
|
{ "header", _nullRenderAsyncDelegate }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("The section named 'header' has already been rendered.", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RenderSectionAsync_ThrowsIfNotInvokedFromLayoutPage()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = new HelperResult(action: null);
|
||||||
|
var page = CreatePage(async v =>
|
||||||
|
{
|
||||||
|
await v.RenderSectionAsync("header");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(page.ExecuteAsync);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("RenderSectionAsync can only be called from a layout page.", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EnsureBodyAndSectionsWereRendered_ThrowsIfDefinedSectionIsNotRendered()
|
public async Task EnsureBodyAndSectionsWereRendered_ThrowsIfDefinedSectionIsNotRendered()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new HelperResult(action: null);
|
|
||||||
var page = CreatePage(v =>
|
var page = CreatePage(v =>
|
||||||
{
|
{
|
||||||
v.RenderSection("sectionA");
|
v.RenderSection("sectionA");
|
||||||
});
|
});
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{ "header", expected },
|
{ "header", _nullRenderAsyncDelegate },
|
||||||
{ "footer", expected },
|
{ "footer", _nullRenderAsyncDelegate },
|
||||||
{ "sectionA", expected },
|
{ "sectionA", _nullRenderAsyncDelegate },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -337,35 +397,38 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public async Task ExecuteAsync_RendersSectionsAndBody()
|
public async Task ExecuteAsync_RendersSectionsAndBody()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = @"Layout start
|
var expected = string.Join(Environment.NewLine,
|
||||||
Header section
|
"Layout start",
|
||||||
body content
|
"Header section",
|
||||||
Footer section
|
"Async Header section",
|
||||||
Layout end
|
"body content",
|
||||||
";
|
"Async Footer section",
|
||||||
var page = CreatePage(v =>
|
"Footer section",
|
||||||
|
"Layout end");
|
||||||
|
var page = CreatePage(async v =>
|
||||||
{
|
{
|
||||||
v.WriteLiteral("Layout start" + Environment.NewLine);
|
v.WriteLiteral("Layout start" + Environment.NewLine);
|
||||||
v.Write(v.RenderSection("header"));
|
v.Write(v.RenderSection("header"));
|
||||||
|
v.Write(await v.RenderSectionAsync("async-header"));
|
||||||
v.Write(v.RenderBodyPublic());
|
v.Write(v.RenderBodyPublic());
|
||||||
|
v.Write(await v.RenderSectionAsync("async-footer"));
|
||||||
v.Write(v.RenderSection("footer"));
|
v.Write(v.RenderSection("footer"));
|
||||||
v.WriteLiteral("Layout end" + Environment.NewLine);
|
v.WriteLiteral("Layout end");
|
||||||
|
|
||||||
});
|
});
|
||||||
page.RenderBodyDelegate = CreateBodyAction("body content" + Environment.NewLine);
|
page.RenderBodyDelegate = CreateBodyAction("body content" + Environment.NewLine);
|
||||||
page.PreviousSectionWriters = new Dictionary<string, HelperResult>
|
page.PreviousSectionWriters = new Dictionary<string, RenderAsyncDelegate>
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"footer", new HelperResult(writer =>
|
"footer", writer => writer.WriteLineAsync("Footer section")
|
||||||
{
|
|
||||||
writer.WriteLine("Footer section");
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"header", new HelperResult(writer =>
|
"header", writer => writer.WriteLineAsync("Header section")
|
||||||
{
|
},
|
||||||
writer.WriteLine("Header section");
|
{
|
||||||
})
|
"async-header", writer => writer.WriteLineAsync("Async Header section")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"async-footer", writer => writer.WriteLineAsync("Async Footer section")
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -373,7 +436,7 @@ Layout end
|
||||||
await page.ExecuteAsync();
|
await page.ExecuteAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var actual = ((StringWriter)page.Output).ToString();
|
var actual = page.RenderedContent;
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,7 +462,7 @@ Layout end
|
||||||
await page.ExecuteAsync();
|
await page.ExecuteAsync();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var actual = ((StringWriter)page.Output).ToString();
|
var actual = page.RenderedContent;
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
helper.Verify();
|
helper.Verify();
|
||||||
}
|
}
|
||||||
|
|
@ -410,9 +473,9 @@ Layout end
|
||||||
// Arrange
|
// Arrange
|
||||||
var writer = new Mock<TextWriter>();
|
var writer = new Mock<TextWriter>();
|
||||||
var context = CreateViewContext(writer.Object);
|
var context = CreateViewContext(writer.Object);
|
||||||
var page = CreatePage(p =>
|
var page = CreatePage(async p =>
|
||||||
{
|
{
|
||||||
p.FlushAsync().Wait();
|
await p.FlushAsync();
|
||||||
}, context);
|
}, context);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -429,10 +492,10 @@ Layout end
|
||||||
var expected = @"A layout page cannot be rendered after 'FlushAsync' has been invoked.";
|
var expected = @"A layout page cannot be rendered after 'FlushAsync' has been invoked.";
|
||||||
var writer = new Mock<TextWriter>();
|
var writer = new Mock<TextWriter>();
|
||||||
var context = CreateViewContext(writer.Object);
|
var context = CreateViewContext(writer.Object);
|
||||||
var page = CreatePage(p =>
|
var page = CreatePage(async p =>
|
||||||
{
|
{
|
||||||
p.Layout = "foo";
|
p.Layout = "foo";
|
||||||
p.FlushAsync().Wait();
|
await p.FlushAsync();
|
||||||
}, context);
|
}, context);
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
|
|
@ -449,10 +512,10 @@ Layout end
|
||||||
var page = CreatePage(p =>
|
var page = CreatePage(p =>
|
||||||
{
|
{
|
||||||
p.Layout = "bar";
|
p.Layout = "bar";
|
||||||
p.DefineSection("test-section", new HelperResult(_ =>
|
p.DefineSection("test-section", async _ =>
|
||||||
{
|
{
|
||||||
p.FlushAsync().Wait();
|
await p.FlushAsync();
|
||||||
}));
|
});
|
||||||
}, context);
|
}, context);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -460,7 +523,8 @@ Layout end
|
||||||
page.IsLayoutBeingRendered = true;
|
page.IsLayoutBeingRendered = true;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.DoesNotThrow(() => page.SectionWriters["test-section"].WriteTo(TextWriter.Null));
|
var renderAsyncDelegate = page.SectionWriters["test-section"];
|
||||||
|
await Assert.DoesNotThrowAsync(() => renderAsyncDelegate(TextWriter.Null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -553,14 +617,27 @@ Layout end
|
||||||
|
|
||||||
private static TestableRazorPage CreatePage(Action<TestableRazorPage> executeAction,
|
private static TestableRazorPage CreatePage(Action<TestableRazorPage> executeAction,
|
||||||
ViewContext context = null)
|
ViewContext context = null)
|
||||||
|
{
|
||||||
|
return CreatePage(page =>
|
||||||
|
{
|
||||||
|
executeAction(page);
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static TestableRazorPage CreatePage(Func<TestableRazorPage, Task> executeAction,
|
||||||
|
ViewContext context = null)
|
||||||
{
|
{
|
||||||
context = context ?? CreateViewContext();
|
context = context ?? CreateViewContext();
|
||||||
var view = new Mock<TestableRazorPage> { CallBase = true };
|
var view = new Mock<TestableRazorPage> { CallBase = true };
|
||||||
if (executeAction != null)
|
if (executeAction != null)
|
||||||
{
|
{
|
||||||
view.Setup(v => v.ExecuteAsync())
|
view.Setup(v => v.ExecuteAsync())
|
||||||
.Callback(() => executeAction(view.Object))
|
.Returns(() =>
|
||||||
.Returns(Task.FromResult(0));
|
{
|
||||||
|
return executeAction(view.Object);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
view.Object.ViewContext = context;
|
view.Object.ViewContext = context;
|
||||||
|
|
@ -585,6 +662,15 @@ Layout end
|
||||||
|
|
||||||
public abstract class TestableRazorPage : RazorPage
|
public abstract class TestableRazorPage : RazorPage
|
||||||
{
|
{
|
||||||
|
public string RenderedContent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var writer = Assert.IsType<StringWriter>(Output);
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public HelperResult RenderBodyPublic()
|
public HelperResult RenderBodyPublic()
|
||||||
{
|
{
|
||||||
return base.RenderBody();
|
return base.RenderBody();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public class RazorViewTest
|
public class RazorViewTest
|
||||||
{
|
{
|
||||||
private const string LayoutPath = "~/Shared/_Layout.cshtml";
|
private const string LayoutPath = "~/Shared/_Layout.cshtml";
|
||||||
|
private readonly RenderAsyncDelegate _nullRenderAsyncDelegate = async writer => { };
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RenderAsync_ThrowsIfContextualizeHasNotBeenInvoked()
|
public async Task RenderAsync_ThrowsIfContextualizeHasNotBeenInvoked()
|
||||||
|
|
@ -264,14 +265,14 @@ foot-content";
|
||||||
{
|
{
|
||||||
v.WriteLiteral("body-content");
|
v.WriteLiteral("body-content");
|
||||||
v.Layout = LayoutPath;
|
v.Layout = LayoutPath;
|
||||||
v.DefineSection("head", new HelperResult(writer =>
|
v.DefineSection("head", async writer =>
|
||||||
{
|
{
|
||||||
writer.Write("head-content");
|
await writer.WriteAsync("head-content");
|
||||||
}));
|
});
|
||||||
v.DefineSection("foot", new HelperResult(writer =>
|
v.DefineSection("foot", async writer =>
|
||||||
{
|
{
|
||||||
writer.Write("foot-content");
|
await writer.WriteAsync("foot-content");
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
var layout = new TestableRazorPage(v =>
|
var layout = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
|
|
@ -312,9 +313,9 @@ foot-content";
|
||||||
// Arrange
|
// Arrange
|
||||||
var page = new TestableRazorPage(v =>
|
var page = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.DefineSection("head", new HelperResult(writer => { }));
|
v.DefineSection("head", _nullRenderAsyncDelegate);
|
||||||
v.Layout = LayoutPath;
|
v.Layout = LayoutPath;
|
||||||
v.DefineSection("foot", new HelperResult(writer => { }));
|
v.DefineSection("foot", _nullRenderAsyncDelegate);
|
||||||
});
|
});
|
||||||
var layout = new TestableRazorPage(v =>
|
var layout = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
|
|
@ -374,10 +375,10 @@ body-content";
|
||||||
|
|
||||||
var page = new TestableRazorPage(v =>
|
var page = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.DefineSection("foo", new HelperResult(writer =>
|
v.DefineSection("foo", async writer =>
|
||||||
{
|
{
|
||||||
writer.WriteLine("foo-content");
|
await writer.WriteLineAsync("foo-content");
|
||||||
}));
|
});
|
||||||
v.Layout = "~/Shared/Layout1.cshtml";
|
v.Layout = "~/Shared/Layout1.cshtml";
|
||||||
v.WriteLiteral("body-content");
|
v.WriteLiteral("body-content");
|
||||||
});
|
});
|
||||||
|
|
@ -385,10 +386,7 @@ body-content";
|
||||||
{
|
{
|
||||||
v.Write("layout-1" + Environment.NewLine);
|
v.Write("layout-1" + Environment.NewLine);
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
v.DefineSection("bar", new HelperResult(writer =>
|
v.DefineSection("bar", writer => writer.WriteLineAsync("bar-content"));
|
||||||
{
|
|
||||||
writer.WriteLine("bar-content");
|
|
||||||
}));
|
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
v.Layout = "~/Shared/Layout2.cshtml";
|
v.Layout = "~/Shared/Layout2.cshtml";
|
||||||
});
|
});
|
||||||
|
|
@ -431,12 +429,12 @@ section-content-2";
|
||||||
{
|
{
|
||||||
v.Layout = "layout-1";
|
v.Layout = "layout-1";
|
||||||
v.WriteLiteral("body content" + Environment.NewLine);
|
v.WriteLiteral("body content" + Environment.NewLine);
|
||||||
v.DefineSection("foo", new HelperResult(_ =>
|
v.DefineSection("foo", async _ =>
|
||||||
{
|
{
|
||||||
v.WriteLiteral("section-content-1" + Environment.NewLine);
|
v.WriteLiteral("section-content-1" + Environment.NewLine);
|
||||||
v.FlushAsync().Wait();
|
await v.FlushAsync();
|
||||||
v.WriteLiteral("section-content-2");
|
v.WriteLiteral("section-content-2");
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var layout1 = new TestableRazorPage(v =>
|
var layout1 = new TestableRazorPage(v =>
|
||||||
|
|
@ -475,12 +473,12 @@ section-content-2";
|
||||||
var page = new TestableRazorPage(v =>
|
var page = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.Layout = "layout-1";
|
v.Layout = "layout-1";
|
||||||
v.DefineSection("foo", new HelperResult(_ =>
|
v.DefineSection("foo", async _ =>
|
||||||
{
|
{
|
||||||
v.WriteLiteral("section-content-1" + Environment.NewLine);
|
v.WriteLiteral("section-content-1" + Environment.NewLine);
|
||||||
v.FlushAsync().Wait();
|
await v.FlushAsync();
|
||||||
v.WriteLiteral("section-content-2");
|
v.WriteLiteral("section-content-2");
|
||||||
}));
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var layout1 = new TestableRazorPage(v =>
|
var layout1 = new TestableRazorPage(v =>
|
||||||
|
|
@ -538,11 +536,11 @@ section-content-2";
|
||||||
var expected = @"A layout page cannot be rendered after 'FlushAsync' has been invoked.";
|
var expected = @"A layout page cannot be rendered after 'FlushAsync' has been invoked.";
|
||||||
var page = new TestableRazorPage(v =>
|
var page = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.DefineSection("foo", new HelperResult(writer =>
|
v.DefineSection("foo", async writer =>
|
||||||
{
|
{
|
||||||
writer.WriteLine("foo-content");
|
writer.WriteLine("foo-content");
|
||||||
v.FlushAsync().Wait();
|
await v.FlushAsync();
|
||||||
}));
|
});
|
||||||
v.Layout = "~/Shared/Layout1.cshtml";
|
v.Layout = "~/Shared/Layout1.cshtml";
|
||||||
v.WriteLiteral("body-content");
|
v.WriteLiteral("body-content");
|
||||||
});
|
});
|
||||||
|
|
@ -550,10 +548,7 @@ section-content-2";
|
||||||
{
|
{
|
||||||
v.Write("layout-1" + Environment.NewLine);
|
v.Write("layout-1" + Environment.NewLine);
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
v.DefineSection("bar", new HelperResult(writer =>
|
v.DefineSection("bar", writer => writer.WriteLineAsync("bar-content"));
|
||||||
{
|
|
||||||
writer.WriteLine("bar-content");
|
|
||||||
}));
|
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
v.Layout = "~/Shared/Layout2.cshtml";
|
v.Layout = "~/Shared/Layout2.cshtml";
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ RenderBody content
|
||||||
@section content
|
@section content
|
||||||
{
|
{
|
||||||
@{
|
@{
|
||||||
FlushAsync().Wait();
|
await FlushAsync();
|
||||||
WaitService.WaitForClient();
|
WaitService.WaitForClient();
|
||||||
}
|
}
|
||||||
<span>Content that takes time to produce</span>
|
<span>Content that takes time to produce</span>
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ RenderBody content
|
||||||
@section content
|
@section content
|
||||||
{
|
{
|
||||||
@{
|
@{
|
||||||
FlushAsync().Wait();
|
await FlushAsync();
|
||||||
WaitService.WaitForClient();
|
WaitService.WaitForClient();
|
||||||
}
|
}
|
||||||
@Component.InvokeAsync("ComponentThatSetsTitle").Result
|
@await Component.InvokeAsync("ComponentThatSetsTitle")
|
||||||
<span>Content that takes time to produce</span>
|
<span>Content that takes time to produce</span>
|
||||||
}
|
}
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
WaitService.WaitForClient();
|
WaitService.WaitForClient();
|
||||||
}
|
}
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
@RenderSection("content")
|
@await RenderSectionAsync("content")
|
||||||
@{
|
@{
|
||||||
WaitService.NotifyClient();
|
WaitService.NotifyClient();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
WaitService.WaitForClient();
|
WaitService.WaitForClient();
|
||||||
}
|
}
|
||||||
@await Html.PartialAsync("_PartialThatSetsTitle")
|
@await Html.PartialAsync("_PartialThatSetsTitle")
|
||||||
@RenderSection("content")
|
@await RenderSectionAsync("content")
|
||||||
@{
|
@{
|
||||||
WaitService.NotifyClient();
|
WaitService.NotifyClient();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue