From df9d5c48755497ef10a5ee25072d782f30060b5e Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 31 Mar 2014 12:37:17 -0700 Subject: [PATCH] Adding support for Render Section Initial draft for DefineSection \ RenderSection. This change is based on changes to the Razor parser to enable Razor to generate HelperResults for section instead of void delegates. --- .../MvcSample.Web/Views/Shared/MyView.cshtml | 25 +++++++++++- .../MvcSample.Web/Views/Shared/_Layout.cshtml | 2 + .../Properties/Resources.Designer.cs | 32 +++++++++++++++ src/Microsoft.AspNet.Mvc.Razor/RazorView.cs | 40 +++++++++++++++++++ src/Microsoft.AspNet.Mvc.Razor/Resources.resx | 6 +++ 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/samples/MvcSample.Web/Views/Shared/MyView.cshtml b/samples/MvcSample.Web/Views/Shared/MyView.cshtml index fe8b6cb9ab..655d8d89ab 100644 --- a/samples/MvcSample.Web/Views/Shared/MyView.cshtml +++ b/samples/MvcSample.Web/Views/Shared/MyView.cshtml @@ -12,6 +12,29 @@ }; } +@section header { + +} + +@section footer { + + +} + @functions { public async Task AsyncValueRetrieval() { @@ -32,7 +55,7 @@

Hello @Model.Name! Happy @Model.Age birthday.

-

This value was retrieved asynchronously: @(await AsyncValueRetrieval())

+

This value was retrieved asynchronously: @(await AsyncValueRetrieval())

Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)

Render Partial Async (Custom model): @{ await RenderHelloWorldPartial(new User() { diff --git a/samples/MvcSample.Web/Views/Shared/_Layout.cshtml b/samples/MvcSample.Web/Views/Shared/_Layout.cshtml index a7f385b52c..2b22ef3017 100644 --- a/samples/MvcSample.Web/Views/Shared/_Layout.cshtml +++ b/samples/MvcSample.Web/Views/Shared/_Layout.cshtml @@ -5,6 +5,7 @@ @ViewBag.Title - My ASP.NET Application + @RenderSection("header") + @RenderSection("footer") diff --git a/src/Microsoft.AspNet.Mvc.Razor/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Razor/Properties/Resources.Designer.cs index e114e5d827..ee5d5f7fe5 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Properties/Resources.Designer.cs @@ -106,6 +106,38 @@ namespace Microsoft.AspNet.Mvc.Razor return GetString("RenderBodyCannotBeCalled"); } + /// + /// Section '{0}' is already defined. + /// + internal static string SectionAlreadyDefined + { + get { return GetString("SectionAlreadyDefined"); } + } + + /// + /// Section '{0}' is already defined. + /// + internal static string FormatSectionAlreadyDefined(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("SectionAlreadyDefined"), p0); + } + + /// + /// Section '{0}' is not defined + /// + internal static string SectionNotDefined + { + get { return GetString("SectionNotDefined"); } + } + + /// + /// Section '{0}' is not defined + /// + internal static string FormatSectionNotDefined(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("SectionNotDefined"), p0); + } + /// /// The partial view '{0}' was not found. The following locations were searched:{1} /// diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs index 3a742c98a8..2bb0bd077c 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorView.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; using System.Text; @@ -36,8 +37,13 @@ namespace Microsoft.AspNet.Mvc.Razor private string BodyContent { get; set; } + private Dictionary SectionWriters { get; set; } + + private Dictionary PreviousSectionWriters { get; set; } + public virtual async Task RenderAsync([NotNull] ViewContext context) { + SectionWriters = new Dictionary(StringComparer.OrdinalIgnoreCase); Context = context; var contentBuilder = new StringBuilder(1024); @@ -82,12 +88,22 @@ namespace Microsoft.AspNet.Mvc.Razor throw new InvalidOperationException(message); } + layoutView.PreviousSectionWriters = SectionWriters; layoutView.BodyContent = bodyContent; await layoutView.RenderAsync(context); } public abstract Task ExecuteAsync(); + public void DefineSection(string name, HelperResult action) + { + if (SectionWriters.ContainsKey(name)) + { + throw new InvalidOperationException(Resources.FormatSectionAlreadyDefined(name)); + } + SectionWriters[name] = action; + } + public virtual void Write(object value) { WriteTo(Output, value); @@ -242,5 +258,29 @@ namespace Microsoft.AspNet.Mvc.Razor } return new HtmlString(BodyContent); } + + public HelperResult RenderSection(string name) + { + return RenderSection(name, required: false); + } + + public HelperResult RenderSection(string name, bool required) + { + HelperResult action; + if (PreviousSectionWriters.TryGetValue(name, out action)) + { + return action; + } + else if (required) + { + // If the section is not found, and it is not optional, throw an error. + throw new InvalidOperationException(Resources.FormatSectionNotDefined(name)); + } + else + { + // If the section is optional and not found, then don't do anything. + return null; + } + } } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/Resources.resx b/src/Microsoft.AspNet.Mvc.Razor/Resources.resx index d0604cb9a4..684beb7909 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Razor/Resources.resx @@ -135,6 +135,12 @@ RenderBody can only be called from a layout page. + + Section '{0}' is already defined. + + + Section '{0}' is not defined + The partial view '{0}' was not found. The following locations were searched:{1}