Examining the Generated cs File for a cshtml View

Cshtml files are compiled by Razor into C# files. To track down some errors (or just to understand Razor) it might be useful to examine the C# code generated.

For testing I created a small Razor view in an MVC4 project.

@{
    string someString = "somestring";
    var someBool = false;
    //-
}
 
<h1>Header</h1>
 
Some other text and @someString.
 
@if(someBool)
{
    <p>Yeps!</p>
}
else
{
    <p>Nope!</p>
}

The easiest way to view the generated C# code is by introducing a compile error to bring up the compilation error page. I uncommented the – on line 4 (which obviously is incorrect C# code). In the bottom of the error page, there is a link to display the compilation source.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
 #pragma checksum "c:\temp\MvcApplication1\Views\Home\Index.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "F5D4970B00EF8FDAA849DEADF3F83414B9E573C1"
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
 //     Runtime Version:4.0.30319.18052
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
 //     the code is regenerated.
 // </auto-generated>
//------------------------------------------------------------------------------
 
namespace ASP {
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Web;
    using System.Web.Helpers;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.WebPages;
    using System.Web.Mvc;
    using System.Web.Mvc.Ajax;
    using System.Web.Mvc.Html;
    using System.Web.Optimization;
    using System.Web.Routing;
 
 
    public class _Page_Views_Home_Index_cshtml : System.Web.Mvc.WebViewPage<dynamic> {
 
#line hidden
 
        public _Page_Views_Home_Index_cshtml() {
        }
 
        protected ASP.global_asax ApplicationInstance {
            get {
                return ((ASP.global_asax)(Context.ApplicationInstance));
            }
        }
 
        public override void Execute() {
 
            #line 1 "c:\temp\MvcApplication1\Views\Home\Index.cshtml"
 
    string someString = "somestring";
    var someBool = false;
    -
 
 
            #line default
            #line hidden
BeginContext("~/Views/Home/Index.cshtml", 78, 43, true);
 
WriteLiteral("\r\n\r\n<h1>Header</h1>\r\n\r\nSome other text and ");
 
EndContext("~/Views/Home/Index.cshtml", 78, 43, true);
 
BeginContext("~/Views/Home/Index.cshtml", 122, 10, false);
 
 
            #line 9 "c:\temp\MvcApplication1\Views\Home\Index.cshtml"
               Write(someString);
 
 
            #line default
            #line hidden
EndContext("~/Views/Home/Index.cshtml", 122, 10, false);
 
BeginContext("~/Views/Home/Index.cshtml", 132, 5, true);
 
WriteLiteral(".\r\n\r\n");
 
EndContext("~/Views/Home/Index.cshtml", 132, 5, true);
 
 
            #line 11 "c:\temp\MvcApplication1\Views\Home\Index.cshtml"
 if(someBool)
{
 
 
            #line default
            #line hidden
BeginContext("~/Views/Home/Index.cshtml", 155, 18, true);
 
WriteLiteral("    <p>Yeps!</p>\r\n");
 
EndContext("~/Views/Home/Index.cshtml", 155, 18, true);
 
 
            #line 14 "c:\temp\MvcApplication1\Views\Home\Index.cshtml"
}
else
{
 
 
            #line default
            #line hidden
BeginContext("~/Views/Home/Index.cshtml", 185, 18, true);
 
WriteLiteral("    <p>Nope!</p>\r\n");
 
EndContext("~/Views/Home/Index.cshtml", 185, 18, true);
 
 
            #line 18 "c:\temp\MvcApplication1\Views\Home\Index.cshtml"
}
 
            #line default
            #line hidden
        }
    }
}

The interesting stuff starts at line 30, where a class is declared. Each razor view is compiled into an own class which derives from System.Web.Mvc.WebViewPage<ModelType>. In this case I didn’t use @model to specify the type of the model, so it is interpreted as dynamic but for strongly typed views, this is where the model type ends up.

The contents of the view file are located inside the Execute() method starting at line 43. Anything that is identified as C# code by the Razor compiler is copied as is into this function (including the incorrect – at line 49 that I used to trigger the compilation error page).

Everything that is not C# code is output to the resulting page by calls to WriteLiteral. An embedded expression (@someString) is output with the Write. The difference between them is that Write html encodes the output, while WriteLiteral doesn’t.

BeginContext and EndContext

The call to WriteLiteral on line 56 is surrounded by calls to BeginContext and EndContext. The documentation is not exactly clear on what they are for:

This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.

When the documentation doesn’t provide any insight, there’s only one thing to do:

Use the source Luke!

Fortunately MVC is open sourced so there is not even any need use IL Spy to reverse compile the code, the actual code is directly available. Unfortunately the MVC code is written to be very flexible with regards to unit testing, which makes it somewhat hard to read.

After a few layers of indirection and depency injection and (obfuscation?) through the use of a dynamic type it looks like the BeginContext call will result in calling the BeginContext method on any attached PageExecutionListener which resides in the System.Web.Instrumentation name space. It is built in support for instrumentation and profiling.

That might be handy, but on the other hand – if a razor view has performance problems in the actual view rendering something else is broken: the view should not contain any logic that can take considerable time. That kind of logic should go into the view model.

1 comment

  1. Unfortunately the MVC code is written to be very flexible with regards to unit testing. =)

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.