parent
c79469c3b3
commit
887ab64d75
|
|
@ -446,6 +446,22 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("CouldNotResolveApplicationRelativeUrl_TagHelper"), p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A circular layout reference was detected when rendering '{0}'. The layout page '{1}' has already been rendered.
|
||||
/// </summary>
|
||||
internal static string LayoutHasCircularReference
|
||||
{
|
||||
get { return GetString("LayoutHasCircularReference"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A circular layout reference was detected when rendering '{0}'. The layout page '{1}' has already been rendered.
|
||||
/// </summary>
|
||||
internal static string FormatLayoutHasCircularReference(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("LayoutHasCircularReference"), p0, p1);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
|
@ -35,7 +36,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
/// <param name="htmlEncoder">The HTML encoder.</param>
|
||||
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
||||
/// pages</param>
|
||||
public RazorView(IRazorViewEngine viewEngine,
|
||||
public RazorView(
|
||||
IRazorViewEngine viewEngine,
|
||||
IRazorPageActivator pageActivator,
|
||||
IViewStartProvider viewStartProvider,
|
||||
IRazorPage razorPage,
|
||||
|
|
@ -170,7 +172,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
RazorPage.Layout = layout;
|
||||
}
|
||||
|
||||
private async Task RenderLayoutAsync(ViewContext context,
|
||||
private async Task RenderLayoutAsync(
|
||||
ViewContext context,
|
||||
IBufferedTextWriter bodyWriter)
|
||||
{
|
||||
// A layout page can specify another layout page. We'll need to continue
|
||||
|
|
@ -192,6 +195,15 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
var layoutPage = GetLayoutPage(context, previousPage.Layout);
|
||||
|
||||
if (renderedLayouts.Count > 0 &&
|
||||
renderedLayouts.Any(l => string.Equals(l.Path, layoutPage.Path, StringComparison.Ordinal)))
|
||||
{
|
||||
// If the layout has been previously rendered as part of this view, we're potentially in a layout
|
||||
// rendering cycle.
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatLayoutHasCircularReference(previousPage.Path, layoutPage.Path));
|
||||
}
|
||||
|
||||
// Notify the previous page that any writes that are performed on it are part of sections being written
|
||||
// in the layout.
|
||||
previousPage.IsLayoutBeingRendered = true;
|
||||
|
|
|
|||
|
|
@ -200,4 +200,7 @@
|
|||
|
||||
@{3} "{4}, {5}"</value>
|
||||
</data>
|
||||
<data name="LayoutHasCircularReference" xml:space="preserve">
|
||||
<value>A circular layout reference was detected when rendering '{0}'. The layout page '{1}' has already been rendered.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -8,7 +8,6 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Actions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.PageExecutionInstrumentation;
|
||||
using Microsoft.Framework.WebEncoders.Testing;
|
||||
|
|
@ -568,11 +567,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
await v.RenderSectionAsync("sectionA");
|
||||
});
|
||||
});
|
||||
nestedLayout.Path = "NestedLayout";
|
||||
var baseLayout = new TestableRazorPage(v =>
|
||||
{
|
||||
v.HtmlEncoder = htmlEncoder;
|
||||
v.RenderSection("sectionB");
|
||||
});
|
||||
baseLayout.Path = "Layout";
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>();
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "NestedLayout"))
|
||||
|
|
@ -784,6 +785,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
v.RenderBodyPublic();
|
||||
v.Layout = "~/Shared/Layout2.cshtml";
|
||||
});
|
||||
layout1.Path = "~/Shared/Layout1.cshtml";
|
||||
|
||||
var layout2 = new TestableRazorPage(v =>
|
||||
{
|
||||
v.HtmlEncoder = htmlEncoder;
|
||||
|
|
@ -791,6 +794,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
v.Write(v.RenderSection("bar"));
|
||||
v.RenderBodyPublic();
|
||||
});
|
||||
layout2.Path = "~/Shared/Layout2.cshtml";
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>();
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
||||
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", layout1));
|
||||
|
|
@ -812,6 +817,87 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
Assert.Equal(expected, viewContext.Writer.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_Throws_IfLayoutPageReferencesSelf()
|
||||
{
|
||||
// Arrange
|
||||
var expectedMessage = "A circular layout reference was detected when rendering " +
|
||||
"'Shared/Layout.cshtml'. The layout page 'Shared/Layout.cshtml' has already been rendered.";
|
||||
var page = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = "_Layout";
|
||||
});
|
||||
var layout = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = "_Layout";
|
||||
v.RenderBodyPublic();
|
||||
});
|
||||
layout.Path = "Shared/Layout.cshtml";
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>();
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "_Layout"))
|
||||
.Returns(new RazorPageResult("_Layout", layout));
|
||||
|
||||
var view = new RazorView(viewEngine.Object,
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
CreateViewStartProvider(),
|
||||
page,
|
||||
new CommonTestEncoder(),
|
||||
isPartial: false);
|
||||
var viewContext = CreateViewContext(view);
|
||||
|
||||
// Act and Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => view.RenderAsync(viewContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_Throws_IfNestedLayoutPagesResultInCyclicReferences()
|
||||
{
|
||||
// Arrange
|
||||
var expectedMessage = "A circular layout reference was detected when rendering " +
|
||||
"'/Shared/Layout2.cshtml'. The layout page 'Shared/_Layout.cshtml' has already been rendered.";
|
||||
var page = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = "_Layout";
|
||||
});
|
||||
var layout1 = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = "_Layout2";
|
||||
v.RenderBodyPublic();
|
||||
});
|
||||
layout1.Path = "Shared/_Layout.cshtml";
|
||||
|
||||
var layout2 = new TestableRazorPage(v =>
|
||||
{
|
||||
v.Layout = "_Layout";
|
||||
v.RenderBodyPublic();
|
||||
});
|
||||
layout2.Path = "/Shared/Layout2.cshtml";
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>();
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "_Layout"))
|
||||
.Returns(new RazorPageResult("_Layout", layout1));
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "_Layout2"))
|
||||
.Returns(new RazorPageResult("_Layout2", layout2));
|
||||
|
||||
var view = new RazorView(viewEngine.Object,
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
CreateViewStartProvider(),
|
||||
page,
|
||||
new CommonTestEncoder(),
|
||||
isPartial: false);
|
||||
var viewContext = CreateViewContext(view);
|
||||
|
||||
// Act and Assert
|
||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(() => view.RenderAsync(viewContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RenderAsync_ExecutesNestedLayoutsWithNestedSections()
|
||||
{
|
||||
|
|
@ -848,6 +934,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
await writer.WriteLineAsync(htmlEncoder.HtmlEncode(v.RenderSection("foo").ToString()));
|
||||
});
|
||||
});
|
||||
nestedLayout.Path = "~/Shared/Layout2.cshtml";
|
||||
|
||||
var baseLayout = new TestableRazorPage(v =>
|
||||
{
|
||||
v.HtmlEncoder = htmlEncoder;
|
||||
|
|
@ -855,6 +943,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
v.RenderBodyPublic();
|
||||
v.Write(v.RenderSection("foo"));
|
||||
});
|
||||
baseLayout.Path = "~/Shared/Layout1.cshtml";
|
||||
|
||||
var viewEngine = new Mock<IRazorViewEngine>();
|
||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
||||
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", nestedLayout));
|
||||
|
|
|
|||
Loading…
Reference in New Issue