diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs index 7e8ade6beb..3b724dbc1f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs @@ -155,8 +155,12 @@ namespace Microsoft.AspNet.Mvc.Razor var viewStart = ViewStartPages[i]; context.ExecutingFilePath = viewStart.Path; - // Copy the layout value from the previous view start (if any) to the current. - viewStart.Layout = layout; + // If non-null, copy the layout value from the previous view start to the current. Otherwise leave + // Layout default alone. + if (layout != null) + { + viewStart.Layout = layout; + } await RenderPageCoreAsync(viewStart, context); @@ -170,8 +174,11 @@ namespace Microsoft.AspNet.Mvc.Razor context.ExecutingFilePath = oldFilePath; } - // Copy the layout value from the view start page(s) (if any) to the entry page. - RazorPage.Layout = layout; + // If non-null, copy the layout value from the view start page(s) to the entry page. + if (layout != null) + { + RazorPage.Layout = layout; + } } private async Task RenderLayoutAsync( diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs index 92d62b3ce2..b2bf80dfc9 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; @@ -359,6 +358,102 @@ namespace Microsoft.AspNet.Mvc.Razor activator.Verify(); } + [Fact] + public async Task RenderAsync_ExecutesDefaultLayout() + { + // Arrange + var path = "/Views/Home/Index.cshtml"; + var layoutPath = "/Views/_Shared/_Layout.cshtml"; + var page = new TestableRazorPage(p => { }) + { + Path = path, + // Initialize Layout property when instantiated. + Layout = layoutPath, + }; + var layoutExecuted = false; + var layout = new TestableRazorPage( + p => + { + layoutExecuted = true; + p.RenderBodyPublic(); + }) + { + Path = layoutPath, + }; + + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(engine => engine.GetPage(path, layoutPath)) + .Returns(new RazorPageResult(layoutPath, layout)); + + var view = new RazorView( + viewEngine.Object, + Mock.Of(), + new IRazorPage[0], + page, + new HtmlTestEncoder()); + var context = CreateViewContext(view); + + // Act + await view.RenderAsync(context); + + // Assert + Assert.True(layoutExecuted); + } + + [Fact] + public async Task RenderAsync_ExecutesDefaultLayout_WithViewStart() + { + // Arrange + var path = "/Views/Home/Index.cshtml"; + var layoutPath = "/Views/_Shared/_Layout.cshtml"; + var viewStartPath = "/Views/_ViewStart.cshtml"; + + var viewStart = new TestableRazorPage(p => { }) + { + Path = viewStartPath, + }; + var page = new TestableRazorPage(p => { }) + { + Path = path, + // Initialize Layout property when instantiated. + Layout = layoutPath, + }; + + var layoutExecuted = false; + var layout = new TestableRazorPage( + p => + { + layoutExecuted = true; + p.RenderBodyPublic(); + }) + { + Path = layoutPath, + }; + + var viewEngine = new Mock(MockBehavior.Strict); + viewEngine + .Setup(engine => engine.GetAbsolutePath(viewStartPath, /* pagePath */ null)) + .Returns(null); + viewEngine + .Setup(engine => engine.GetPage(path, layoutPath)) + .Returns(new RazorPageResult(layoutPath, layout)); + + var view = new RazorView( + viewEngine.Object, + Mock.Of(), + new[] { viewStart }, + page, + new HtmlTestEncoder()); + var context = CreateViewContext(view); + + // Act + await view.RenderAsync(context); + + // Assert + Assert.True(layoutExecuted); + } + [Fact] public async Task RenderAsync_ThrowsIfLayoutPageCannotBeFound_MessageUsesGetPageLocations() {