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);
|
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)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Features;
|
using Microsoft.AspNet.Http.Features;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
|
|
@ -35,7 +36,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
/// <param name="htmlEncoder">The HTML encoder.</param>
|
/// <param name="htmlEncoder">The HTML encoder.</param>
|
||||||
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
/// <param name="isPartial">Determines if the view is to be executed as a partial.</param>
|
||||||
/// pages</param>
|
/// pages</param>
|
||||||
public RazorView(IRazorViewEngine viewEngine,
|
public RazorView(
|
||||||
|
IRazorViewEngine viewEngine,
|
||||||
IRazorPageActivator pageActivator,
|
IRazorPageActivator pageActivator,
|
||||||
IViewStartProvider viewStartProvider,
|
IViewStartProvider viewStartProvider,
|
||||||
IRazorPage razorPage,
|
IRazorPage razorPage,
|
||||||
|
|
@ -170,7 +172,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
RazorPage.Layout = layout;
|
RazorPage.Layout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RenderLayoutAsync(ViewContext context,
|
private async Task RenderLayoutAsync(
|
||||||
|
ViewContext context,
|
||||||
IBufferedTextWriter bodyWriter)
|
IBufferedTextWriter bodyWriter)
|
||||||
{
|
{
|
||||||
// A layout page can specify another layout page. We'll need to continue
|
// 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);
|
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
|
// Notify the previous page that any writes that are performed on it are part of sections being written
|
||||||
// in the layout.
|
// in the layout.
|
||||||
previousPage.IsLayoutBeingRendered = true;
|
previousPage.IsLayoutBeingRendered = true;
|
||||||
|
|
|
||||||
|
|
@ -200,4 +200,7 @@
|
||||||
|
|
||||||
@{3} "{4}, {5}"</value>
|
@{3} "{4}, {5}"</value>
|
||||||
</data>
|
</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>
|
</root>
|
||||||
|
|
@ -8,7 +8,6 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Features;
|
using Microsoft.AspNet.Http.Features;
|
||||||
using Microsoft.AspNet.Http.Internal;
|
using Microsoft.AspNet.Http.Internal;
|
||||||
using Microsoft.AspNet.Mvc.Actions;
|
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.PageExecutionInstrumentation;
|
using Microsoft.AspNet.PageExecutionInstrumentation;
|
||||||
using Microsoft.Framework.WebEncoders.Testing;
|
using Microsoft.Framework.WebEncoders.Testing;
|
||||||
|
|
@ -568,11 +567,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await v.RenderSectionAsync("sectionA");
|
await v.RenderSectionAsync("sectionA");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
nestedLayout.Path = "NestedLayout";
|
||||||
var baseLayout = new TestableRazorPage(v =>
|
var baseLayout = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.HtmlEncoder = htmlEncoder;
|
v.HtmlEncoder = htmlEncoder;
|
||||||
v.RenderSection("sectionB");
|
v.RenderSection("sectionB");
|
||||||
});
|
});
|
||||||
|
baseLayout.Path = "Layout";
|
||||||
|
|
||||||
var viewEngine = new Mock<IRazorViewEngine>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "NestedLayout"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "NestedLayout"))
|
||||||
|
|
@ -784,6 +785,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
v.Layout = "~/Shared/Layout2.cshtml";
|
v.Layout = "~/Shared/Layout2.cshtml";
|
||||||
});
|
});
|
||||||
|
layout1.Path = "~/Shared/Layout1.cshtml";
|
||||||
|
|
||||||
var layout2 = new TestableRazorPage(v =>
|
var layout2 = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.HtmlEncoder = htmlEncoder;
|
v.HtmlEncoder = htmlEncoder;
|
||||||
|
|
@ -791,6 +794,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.Write(v.RenderSection("bar"));
|
v.Write(v.RenderSection("bar"));
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
});
|
});
|
||||||
|
layout2.Path = "~/Shared/Layout2.cshtml";
|
||||||
|
|
||||||
var viewEngine = new Mock<IRazorViewEngine>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
||||||
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", layout1));
|
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", layout1));
|
||||||
|
|
@ -812,6 +817,87 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
Assert.Equal(expected, viewContext.Writer.ToString());
|
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]
|
[Fact]
|
||||||
public async Task RenderAsync_ExecutesNestedLayoutsWithNestedSections()
|
public async Task RenderAsync_ExecutesNestedLayoutsWithNestedSections()
|
||||||
{
|
{
|
||||||
|
|
@ -848,6 +934,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
await writer.WriteLineAsync(htmlEncoder.HtmlEncode(v.RenderSection("foo").ToString()));
|
await writer.WriteLineAsync(htmlEncoder.HtmlEncode(v.RenderSection("foo").ToString()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
nestedLayout.Path = "~/Shared/Layout2.cshtml";
|
||||||
|
|
||||||
var baseLayout = new TestableRazorPage(v =>
|
var baseLayout = new TestableRazorPage(v =>
|
||||||
{
|
{
|
||||||
v.HtmlEncoder = htmlEncoder;
|
v.HtmlEncoder = htmlEncoder;
|
||||||
|
|
@ -855,6 +943,8 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
v.RenderBodyPublic();
|
v.RenderBodyPublic();
|
||||||
v.Write(v.RenderSection("foo"));
|
v.Write(v.RenderSection("foo"));
|
||||||
});
|
});
|
||||||
|
baseLayout.Path = "~/Shared/Layout1.cshtml";
|
||||||
|
|
||||||
var viewEngine = new Mock<IRazorViewEngine>();
|
var viewEngine = new Mock<IRazorViewEngine>();
|
||||||
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
viewEngine.Setup(p => p.FindPage(It.IsAny<ActionContext>(), "~/Shared/Layout1.cshtml"))
|
||||||
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", nestedLayout));
|
.Returns(new RazorPageResult("~/Shared/Layout1.cshtml", nestedLayout));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue