Andrew Ashbacher
Andrew Ashbacher

Reputation: 989

ASP.NET MVC - Set variable in layout template from partial or body

Question

In ASP.NET MVC (and specifically with Razor), how does one set the value of a variable within a partial (or "sub-template") and access that value within a master (or layout) template?

Goal

I would like to maintain lists of assets (stylesheets and JavaScript files) and be able to add to the lists from within partials. The assets should then be accessible within the master layout to be included in the <head/> (stylesheets) or near the end of the <body/> (JavaScript files) of the page. This provides an elegant means of storing modules in partials that include all necessary assets.

My Attempt

Below is what I have tried for stylesheets. The intended result is that both global.css and view_post.css would be included in the header, but only global.css is showing up. It is my understanding that this occurs because the layout is rendered before the template.

Helpers/AssetHelper.cs

namespace MyApp.Helpers
{
    public static class AssetHelper
    {

        private static SortedSet<string> StyleSheets(this HtmlHelper helper)
        {
            if (helper.ViewBag._styleSheets == null)
                  helper.ViewBag._styleSheets = new SortedSet<string> ();
            return helper.ViewBag._stylesheets as SortedSet<string>;
        }

        public static MvcHtmlString AddStyleSheet(this HtmlHelper helper, string styleSheet) {
            helper.StyleSheets().Add(styleSheet);
            return new MvcHtmlString("");
        }

        public static MvcHtmlString RenderStyles(this HtmlHelper helper)
        {
            StringBuilder output = new StringBuilder();
            string template = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />";

            foreach (string styleSheet in helper.StyleSheets())
                output.Append(String.Format(template, styleSheet));

            return new MvcHtmlString(output.ToString());
        }

    }
}

Views/Shared/Layout.cshtml

@using MyApp.Helpers

<html>
  <head>
    ...
    @Html.AddStyleSheet("global.css")
    @Html.RenderStyles()
  </head>
  <body>
    ...
    @RenderBody
    ...
  </body>
</html>

Views/Posts/View.cshtml

@using MyApp.Helpers
@Html.AddStyleSheet("view_post.css")

<h2>...</h2>
<p>...</p>

Upvotes: 1

Views: 5988

Answers (1)

Erik Funkenbusch
Erik Funkenbusch

Reputation: 93444

You can't. Layout templates are rendered before your partials. Any variable you set in a partial will be set too late for the layout to know it's there.

This seems like an over complex solution. Why don't you just use the WebOptimization tools that MVC provides?

Upvotes: 4

Related Questions