SLaks.Blog

Making the world a better place, one line of code at a time

Dissecting Razor, part 6: Function Blocks

Posted on Friday, February 18, 2011, at 2:46:00 AM UTC

After looking at how Razor’s Execute() method is generated, we will turn to class-level features.

C# Razor pages can define class members inside of @functions { ... } blocks.  These are Razor’s equivalent of <script runat="server"> blocks in ASPX pages.  VBHTML pages use @Functions ... End Functions instead.

Functions blocks are emitted directly into top of the generated class, regardless of their location in the original source.  Unlike code blocks, function blocks cannot contain markup.

Here is a simple example:

<!DOCTYPE html>
<html>
    <body>
        @functions{
            public int GetPageLength() {
                //Don't try this in production.
                return ((StringWriter)this.Output).ToString().Length;
            }
        }
        @GetPageLength() characters have been written so far.
    </body>
</html>
@{ #error }

Note that functions blocks can be defined anywhere, even in the middle of the markup.  The location of the block is totally irrelevant.

Here is the generated C# source, with a comment indicating where the block used to be.

public class _Page_Razor_Functions_cshtml : System.Web.WebPages.WebPage {

#line hidden
#line 4 "...\Functions.cshtml"

    public int GetPageLength() {
        //Don't try this in production.
        return ((StringWriter)this.Output).ToString().Length;
    }

#line default
#line hidden

    public _Page_Razor_Functions_cshtml() {
    }

    protected ASP.global_asax ApplicationInstance {
        get {
            return ((ASP.global_asax)(Context.ApplicationInstance));
        }
    }

    public override void Execute() {
        WriteLiteral("<!DOCTYPE html>\r\n<html>\r\n    <body>\r\n        ");
//Here was the functions block
        WriteLiteral("\r\n        ");

#line 10 "...\Functions.cshtml"
        Write(GetPageLength());
#line default
#line hidden
        WriteLiteral(" characters have been written so far.\r\n    </body>\r\n</html>\r\n");

#line 13 "...\Functions.cshtml"
#error

#line default
#line hidden
        WriteLiteral("     ");
    }
}

The contents of the functions block is inserted at the very top of the class, with the familiar #line directives to pretend that it comes from the CSHTML.

Notice that none of the whitespace around the functions block is stripped; you can see the newline and indentation in the @functions line in the first WriteLiteral string, and the newline and indentation after the closing } in the second WriteLiteral string.

Sure enough, the rendered HTML contains an extra blank like:

<!DOCTYPE html>
<html>
    <body>
        
        55 characters have been written so far.
    </body>
</html>

This means that putting a functions block before the <!DOCTYPE> will cause the HTML to start with an ugly blank line.  Therefore, it’s best to put functions blocks at the end of the source, where the blank lines won’t matter.

Next Time: Helpers

Categories: razor, asp.net, dissecting-razor, .net Tweet this post

comments powered by Disqus