Dissecting Razor, part 4: Anatomy of a Razor Page

After looking at the various assemblies in the WebPages framework, we will drill into the inner workings of Razor pages.

Razor Side

An ordinary CSHTML page is transformed into a class which inherits the WebPage class.  The generator overrides the abstract Execute() method from the to render the page to the HTTP response stream.

Except for class-level directives and constructs (which will be discussed later), all ordinary content in a Razor page end up in the Execute method. 

There are three types of normal content: Literals, Code Blocks, and Code Nuggets.

Literals include any normal text. Razor compiles literal text into calls to the WriteLiteral method, with the text as a (correctly-escaped) string parameter.  Razor expects this method to write its parameter to the page.

Code Blocks include @{ ... } blocks, as well as control structures.  They’re Razor’s equivalent of <% ... %> blocks.  The contents of a code block are emitted as-is in the Execute method.  Code blocks must contain complete statements, or they’ll result in C# syntax errors.

VBHTML pages use @Code ... End Code blocks instead.

Code Nuggets are @-blocks.  They’re Razor’s equivalent of <%: ... %> blocks in an ASPX page.  Scott Guthrie describes how these blocks are tokenized.  The contents of a code nugget are passed to the Write method, which is expected to HTML-escape its parameter and print it.

WebPages Side

The WebPages framework’s  Write method (which comes from the WebPageBase class) takes a parameter of type Object, allowing one to put any expression in a code nugget.  It passes its parameter to HttpUtility.HtmlEncode, which will call ToString() and HTML-escape the output.  If the parameter is an IHtmlString, HtmlEncode will return its ToHtmlString() method without escaping.

The base class, method names, and default namespaces can be configured in the RazorEngineHost.  In addition, custom RazorEngineHosts can override the PostProcessGeneratedCode method to make arbitrary modifications to the generated code.

The WebRazorHostFactory in System.Web.WebPages.Razor.dll can also read default namespaces, a default base type, and a custom host from the <system.web.webPages.razor> section in Web.config:

    <host factoryType="MyProject.MyWebPageRazorHost" />
    <pages pageBaseType="MyProject.CustomWebPage">
            <add namespace="MyProject.SomeNamespace" />

Next Time: Looking at the generated page


Post a Comment