From 75c6327b2ee30e75a80fe1cf54c973a656ca1f2e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Wed, 15 Oct 2014 12:33:28 -0700 Subject: [PATCH] Layout property needs to be propogated between nested view starts Fixes #1364 --- src/Microsoft.AspNet.Mvc.Razor/RazorView.cs | 10 ++- .../ViewEngineTests.cs | 22 +++++- .../RazorViewTest.cs | 74 +++++++++++++++++++ .../Controllers/NestedViewStartsController.cs | 15 ++++ .../NestedViewStarts/Index.cshtml | 1 + .../NestedViewStarts/Layout.cshtml | 2 + .../NestedViewStarts/_ViewStart.cshtml | 4 + .../Views/NestedViewStarts/_viewstart.cshtml | 3 + 8 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 test/WebSites/RazorWebSite/Controllers/NestedViewStartsController.cs create mode 100644 test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Index.cshtml create mode 100644 test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml create mode 100644 test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/_ViewStart.cshtml create mode 100644 test/WebSites/RazorWebSite/Views/NestedViewStarts/_viewstart.cshtml diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs index 2ea9e674f6..2631b9cdc0 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs @@ -150,13 +150,17 @@ namespace Microsoft.AspNet.Mvc.Razor { var viewStarts = _viewStartProvider.GetViewStartPages(_razorPage.Path); + string layout = null; foreach (var viewStart in viewStarts) { + // Copy the layout value from the previous view start (if any) to the current. + viewStart.Layout = layout; await RenderPageCoreAsync(viewStart, context); - - // Copy over interesting properties from the ViewStart page to the entry page. - _razorPage.Layout = viewStart.Layout; + layout = viewStart.Layout; } + + // Copy over interesting properties from the ViewStart page to the entry page. + _razorPage.Layout = layout; } private async Task RenderLayoutAsync(ViewContext context, diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs index 142f6acd6b..1eb11b9bf1 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ViewEngineTests.cs @@ -196,5 +196,25 @@ component-content"; // Assert Assert.Equal(expected, body.Trim()); } + + [Fact] + public async Task LayoutValueIsPassedBetweenNestedViewStarts() + { + // Arrange + var expected = string.Join(Environment.NewLine, + "viewstart-value", + "", + "~/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml", + "index-content"); + var server = TestServer.Create(_provider, _app); + var client = server.CreateClient(); + + // Act + var body = await client.GetStringAsync("http://localhost/NestedViewStarts"); + + // Assert + Assert.Equal(expected, body.Trim()); + } } -} \ No newline at end of file +} + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs index 018e69444e..72f329ca88 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewTest.cs @@ -714,6 +714,80 @@ section-content-2"; Assert.True(executed); } + [Fact] + public async Task RenderAsync_CopiesLayoutPropertyFromViewStart() + { + // Arrange + var expectedViewStart = "Layout1"; + var expectedPage = "Layout2"; + string actualViewStart = null; + string actualPage = null; + var page = new TestableRazorPage(v => + { + actualPage = v.Layout; + // Clear it out because we don't care about rendering the layout in this test. + v.Layout = null; + }); + var viewStart1 = new TestableRazorPage(v => + { + v.Layout = expectedViewStart; + }); + var viewStart2 = new TestableRazorPage(v => + { + actualViewStart = v.Layout; + v.Layout = expectedPage; + }); + var pageFactory = Mock.Of(); + + var view = new RazorView(pageFactory, + Mock.Of(), + CreateViewStartProvider(viewStart1, viewStart2)); + view.Contextualize(page, isPartial: false); + var viewContext = CreateViewContext(view); + + // Act + await view.RenderAsync(viewContext); + + // Assert + Assert.Equal(expectedViewStart, actualViewStart); + Assert.Equal(expectedPage, actualPage); + } + + [Fact] + public async Task ResettingLayout_InViewStartCausesItToBeResetInPage() + { + // Arrange + var expected = "Layout"; + string actual = null; + + var page = new TestableRazorPage(v => + { + Assert.Null(v.Layout); + }); + var viewStart1 = new TestableRazorPage(v => + { + v.Layout = expected; + }); + var viewStart2 = new TestableRazorPage(v => + { + actual = v.Layout; + v.Layout = null; + }); + var pageFactory = Mock.Of(); + + var view = new RazorView(pageFactory, + Mock.Of(), + CreateViewStartProvider(viewStart1, viewStart2)); + view.Contextualize(page, isPartial: false); + var viewContext = CreateViewContext(view); + + // Act + await view.RenderAsync(viewContext); + + // Assert + Assert.Equal(expected, actual); + } + private static TextWriter CreateBufferedWriter() { var mockWriter = new Mock(); diff --git a/test/WebSites/RazorWebSite/Controllers/NestedViewStartsController.cs b/test/WebSites/RazorWebSite/Controllers/NestedViewStartsController.cs new file mode 100644 index 0000000000..3e0ac10a83 --- /dev/null +++ b/test/WebSites/RazorWebSite/Controllers/NestedViewStartsController.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace RazorWebSite.Controllers +{ + public class NestedViewStartsController : Controller + { + public ViewResult Index() + { + return View("NestedViewStarts/Index"); + } + } +} \ No newline at end of file diff --git a/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Index.cshtml b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Index.cshtml new file mode 100644 index 0000000000..8d329d16e3 --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Index.cshtml @@ -0,0 +1 @@ +index-content \ No newline at end of file diff --git a/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml new file mode 100644 index 0000000000..0e70e16819 --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml @@ -0,0 +1,2 @@ +@ViewData["title"] +@RenderBody() \ No newline at end of file diff --git a/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/_ViewStart.cshtml b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/_ViewStart.cshtml new file mode 100644 index 0000000000..38bed97bd1 --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/NestedViewStarts/NestedViewStarts/_ViewStart.cshtml @@ -0,0 +1,4 @@ +@{ + ViewData["Title"] = "viewstart-value"; +} +@Layout diff --git a/test/WebSites/RazorWebSite/Views/NestedViewStarts/_viewstart.cshtml b/test/WebSites/RazorWebSite/Views/NestedViewStarts/_viewstart.cshtml new file mode 100644 index 0000000000..f9a46cb429 --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/NestedViewStarts/_viewstart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "~/Views/NestedViewStarts/NestedViewStarts/Layout.cshtml"; +} \ No newline at end of file