diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
index 174f0ecf00..2d17448aec 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/Resources.Designer.cs
@@ -267,7 +267,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
}
///
- /// Section '{0}' is not defined in path '{1}'.
+ /// The layout page '{0}' cannot find the section '{1}' in the content page '{2}'.
///
internal static string SectionNotDefined
{
@@ -275,11 +275,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor
}
///
- /// Section '{0}' is not defined in path '{1}'.
+ /// The layout page '{0}' cannot find the section '{1}' in the content page '{2}'.
///
- internal static string FormatSectionNotDefined(object p0, object p1)
+ internal static string FormatSectionNotDefined(object p0, object p1, object p2)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("SectionNotDefined"), p0, p1);
+ return string.Format(CultureInfo.CurrentCulture, GetString("SectionNotDefined"), p0, p1, p2);
}
///
diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs
index 1d6b565403..4def724109 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPage.cs
@@ -443,7 +443,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
// null or false. Consequently defer the prefix generation until we encounter the attribute value.
if (attributeValuesCount != 1)
{
- WritePositionTaggedLiteral(writer, prefix, prefixOffset);
+ WritePositionTaggedLiteral(writer, prefix, prefixOffset);
}
}
@@ -800,7 +800,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor
else if (required)
{
// If the section is not found, and it is not optional, throw an error.
- throw new InvalidOperationException(Resources.FormatSectionNotDefined(sectionName, Path));
+ var message = Resources.FormatSectionNotDefined(
+ ViewContext.ExecutingFilePath,
+ sectionName,
+ ViewContext.View.Path);
+ throw new InvalidOperationException(message);
}
else
{
diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
index f227993316..6c36f0d352 100644
--- a/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
+++ b/src/Microsoft.AspNetCore.Mvc.Razor/Resources.resx
@@ -166,7 +166,7 @@
{0} invocation in '{1}' is invalid. The section '{2}' has already been rendered.
- Section '{0}' is not defined in path '{1}'.
+ The layout page '{0}' cannot find the section '{1}' in the content page '{2}'.
The following sections have been defined but have not been rendered by the page at '{0}': '{1}'.
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorViewLocationSpecificationTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorViewLocationSpecificationTest.cs
index 450ae78d85..517bf01dd7 100644
--- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorViewLocationSpecificationTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorViewLocationSpecificationTest.cs
@@ -4,6 +4,7 @@
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
+using System.Net;
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
{
@@ -93,5 +94,21 @@ Non Shared Partial
// Assert
Assert.Equal(expected, body.Trim(), ignoreLineEndingDifferences: true);
}
+
+ [Fact]
+ public async Task PartialLayout_ThrowsIfRequiredSectionMissing()
+ {
+ // Arrange
+ var path = "http://localhost/PartialViewEngine/ViewPartialMissingSection";
+
+ // Act
+ var content = await (await Client.GetAsync(path)).Content.ReadAsStringAsync();
+
+ // Assert
+ Assert.Contains(
+ "The layout page '/Views/Shared/_PartialLayout.cshtml' cannot find the section " +
+ "'section' in the content page '/Views/PartialViewEngine/PartialMissingSection.cshtml'.",
+ WebUtility.HtmlDecode(content));
+ }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs
index 64fe22948a..b9646a956e 100644
--- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/RazorPageTest.cs
@@ -284,11 +284,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor
public async Task RenderSection_ThrowsIfRequiredSectionIsNotFound()
{
// Arrange
+ var context = CreateViewContext(viewPath: "/Views/TestPath/Test.cshtml");
+ context.ExecutingFilePath = "/Views/Shared/_Layout.cshtml";
var page = CreatePage(v =>
{
- v.Path = "/Views/TestPath/Test.cshtml";
v.RenderSection("bar");
- });
+ }, context: context);
page.PreviousSectionWriters = new Dictionary
{
{ "baz", _nullRenderAsyncDelegate }
@@ -296,7 +297,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
// Act & Assert
var ex = await Assert.ThrowsAsync(() => page.ExecuteAsync());
- Assert.Equal("Section 'bar' is not defined in path '/Views/TestPath/Test.cshtml'.", ex.Message);
+ var message = $"The layout page '/Views/Shared/_Layout.cshtml' cannot find the section 'bar'" +
+ " in the content page '/Views/TestPath/Test.cshtml'.";
+ Assert.Equal(message, ex.Message);
}
[Fact]
@@ -1188,7 +1191,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
return view.Object;
}
- private static ViewContext CreateViewContext(TextWriter writer = null)
+ private static ViewContext CreateViewContext(TextWriter writer = null, string viewPath = null)
{
writer = writer ?? new StringWriter();
var httpContext = new DefaultHttpContext();
@@ -1200,9 +1203,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor
httpContext,
new RouteData(),
new ActionDescriptor());
+ var viewMock = new Mock();
+ if (!string.IsNullOrEmpty(viewPath))
+ {
+ viewMock.Setup(v => v.Path).Returns(viewPath);
+ }
return new ViewContext(
actionContext,
- Mock.Of(),
+ viewMock.Object,
new ViewDataDictionary(new EmptyModelMetadataProvider()),
Mock.Of(),
writer,
diff --git a/test/WebSites/RazorWebSite/Controllers/PartialViewEngineController.cs b/test/WebSites/RazorWebSite/Controllers/PartialViewEngineController.cs
index 484f052997..d7fe08f716 100644
--- a/test/WebSites/RazorWebSite/Controllers/PartialViewEngineController.cs
+++ b/test/WebSites/RazorWebSite/Controllers/PartialViewEngineController.cs
@@ -42,5 +42,10 @@ namespace RazorWebSite.Controllers
};
return PartialView(model);
}
+
+ public IActionResult ViewPartialMissingSection()
+ {
+ return View();
+ }
}
}
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/PartialViewEngine/PartialMissingSection.cshtml b/test/WebSites/RazorWebSite/Views/PartialViewEngine/PartialMissingSection.cshtml
new file mode 100644
index 0000000000..70604444b4
--- /dev/null
+++ b/test/WebSites/RazorWebSite/Views/PartialViewEngine/PartialMissingSection.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "_PartialLayout";
+}
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/PartialViewEngine/ViewPartialMissingSection.cshtml b/test/WebSites/RazorWebSite/Views/PartialViewEngine/ViewPartialMissingSection.cshtml
new file mode 100644
index 0000000000..12619d26bf
--- /dev/null
+++ b/test/WebSites/RazorWebSite/Views/PartialViewEngine/ViewPartialMissingSection.cshtml
@@ -0,0 +1,4 @@
+@{
+ Layout = null;
+}
+@Html.Partial("PartialMissingSection")
\ No newline at end of file
diff --git a/test/WebSites/RazorWebSite/Views/Shared/_PartialLayout.cshtml b/test/WebSites/RazorWebSite/Views/Shared/_PartialLayout.cshtml
new file mode 100644
index 0000000000..89eeeec8cc
--- /dev/null
+++ b/test/WebSites/RazorWebSite/Views/Shared/_PartialLayout.cshtml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+ @RenderBody()
+
+ @{
+ try
+ {
+ RenderSection("section");
+ }
+ catch (InvalidOperationException ex)
+ {
+ @ex.Message
+ }
+ }
+
+