Variables in layout with Script view pages

I’m converting a small projected from netcore2.1 to netcore3, but it used Razor, which no longer picks up file changes without restarting the application.

So, I thought I’d try the #Scripts templates.

Basically, I have the following:

/Views/_layout.html

<html>
<head>
</head>
<body>

1: {{ mydata |> raw }}

2: {{ page }}

3: {{ mydata |> raw }}

</body>
</html>

IndexPageresponse.html

{{#raw appendTo mydata}}
TEXT
{{/raw}}

BODY

This results in:

1:

2. BODY

3: TEXT

Essentially, any variables inserted before {{ page }} is used are ignored.

Is this how it works?

I can’t find the documentation for “page” but from the few examples I could find online, it looks like it is a replacement for RenderBody(). Is this the right way?

Yes, this is documented in Arguments, only static page arguments <!-- --> or arguments defined in PageResult and ScriptContext are available before the page is evaluated.

It’s akin to RenderBody() in Razor, i.e. a placeholder for where the page contents should be written.

Yes, this is documented in Arguments, only static page arguments <!-- --> or arguments defined in PageResult and ScriptContext are available before the page is evaluated.

Thanks. I guess I’m asking about #raw appendTo variables, is that the same? Aren’t they set by the page that would then be available in the _layout?

Sorry, I just not understanding, as this seems it would make the concept of layouts impossible, as you can’t reference a section until after the page has been parsed…but you would expect the page to get parsed first and then the layout.

Do you have any links to more sophisticated examples that show replicating Razor? That might help me understand.

Or, how would you code the equivalent of:

_Layout.cshtml

<html>
<head>
:
@RenderSection("metadata", false)
:
</head>
<body>
@RenderBody()
</body>
</html>

PageResponse.cshtml

@{
  Layout = "_Layout";
}

@section metadata
{
  <meta foo1="bar1">
  <meta foo2="bar2">
  <meta foo3="bar3">
}

<div>page content</div>

Is the issue with Razor cshtml pages not being updating within the debugger in netcore3.0 a bug or nothing you can do?

Parsed isn’t the issue, all pages are parsed into a cached AST before they’re run.

The page needs to be evaluated which it isn’t done until {{ page }}, exactly the same as it is for partials (or any other code), i.e. you cannot access modified values from code that hasn’t been run yet. When it’s evaluated it’s written directly to the output stream after where any of its side-effects (i.e. modified values) can be accessed within _layout or any other subsequent partials.

You wont be able to access variables from the page in your layout before it’s rendered. You’d need to either pass it in as arguments from the Service or your layout page can embed a separate partial or static file. If it’s static you can utilize page arguments like:

page:

<!--
meta: {foo1:"bar1",foo2:"bar2"}
-->

_layout:

{{#each eval(meta) }}
  <meta {{it.Key}}="{{it.Value}}">
{{/each}}

All Sharp Apps and Gist Desktop Apps are built exclusively with #Script, a larger #Script website is https://sharpscript.net itself which is available from https://github.com/ServiceStack/sharpscript although it’s not a typical website as it needs to embed live code fragments and uses GitHub’s markdown renderer HTTP API for its syntax highlighting.

The /server directory in World Validation contains Server #Script which you can compare against 9 different view engine options.

We’re using MVC’s APIs to implement SS.Razor, how Razor pages are executed is out of our control.

Appreciate the response. One last question, I think.

I can see what you did, but I guess my example was too simplistic.

Is there a way to put multi-line, dynamic code into the attributes at the top?

Say my section was more complicated:

@section meta
{
  <script src="some.js" />
  <script>
    // javascript code
  </script>
  <style>
    // css styles
  </style> 
  @Html.Function("to", "inject", "some", "code", Model.Property)
}

Can #script do this and keep it in the html file? Unfortunately, this is common in some of the code I’m trying to migrate.

Your script references should ideally be at the bottom of the page and you can use {{#raw apppendTo scripts}} to append any scripts after the layout script references. Your style includes don’t need to be in the head section as long as they’re at the start of your page it will minimize the number of redraws browsers needs to do.

No it’s not possible to access any values within the page before it’s rendered, the options I’ve mentioned in my previous comment are still the only ones.

Ok, thanks. Style, scripts and so on, I was just trying to give examples of a mix of logic and static content that needs to be near the top. It’s a shame {#raw appendTo …} can’t append to the head section, or anything before the {{ page }} tag appears.

As both includeFile and partial allow you to specify relative references, you can include relative references to the static file (includeFile) or partial next to the page you want to dynamically render, e.g:

page:

<!--
meta: _meta-partial.html
-->

_layout:

{{#if meta}}{{ meta | partial }}{{/if}}