Introducing "Razor" –a new view engine for ASP.net
One of the things my team has been working in has been a new view engine option for asp.net.
asp.net MVC has always supported the concept of "view engines" –which are the pluggable modules that implement different Template syntax options. The "default" view engine for ASP.net MVC today uses the same. aspx/.ascx/.master file templates as asp.net Web Forms. Other popular ASP.net MVC view engines used today include Spark and Nhaml.
The new view-engine option we ' ve been working ' is optimized around HTML generation using a code-focused templating Ach. The codename for this new view engine is "Razor", and we'll be shipping the the the ' the ' the ' the ' I public beta ' it shortly. Design Goals
We had several design goals in mind as we prototyped and evaluated "Razor":
Compact, expressive, and Fluid: Razor minimizes the number of characters and keystrokes required in a file, and E Nables a fast, fluid coding workflow. Unlike most template syntaxes, you don't need to interrupt the your coding to explicitly denote server blocks within your HTM L. The parser is smart enough to infer this from your code. This enables a really compact and expressive syntax which are clean, fast and fun to type.
Easy to Learn: Razor are easy to Learn and enables for you to quickly of being productive with a minimum of concepts. Use the all your existing language and HTML skills.
is not a new language: We consciously chose not to create a new imperative language with Razor. Instead We wanted to enable developers to use their existing c#/vb (or other) language skills with Razor, and deliver a te Mplate markup syntax that enables a awesome HTML construction workflow with your language of choice.
Works with any Text Editor: Razor doesn ' t require a specific tool and enables your to is productive in any plain O LD text Editor (Notepad works great).
has great Intellisense: While Razor has been designed to not require a specific tool or code Editor, it would have Awesome statement completion support within Visual Studio. WE ll be updating Visual Studio and visual Web Developer to have full editor IntelliSense for it.
Unit testable: The new view engine implementation would support the ability to unit test views (without requiring A controller or web-server, and can is hosted in the any unit test Project–no special App-domain).
We ' ve spent the last few months building applications with it and doing lots of usability to it with a studies of Volunteers (including several groups of non-.net Web developers). The feedback so far from people using it has been really great. Choice and Flexibility
One of the best things about asp.net is this most things in it are pluggable. If you find something doesn ' t work the way your want it to, you can swap it out for something else.
The next release of ASP.net MVC would include a new "Add->view" dialog that makes it easy for your to choose the syntax y ou want to use when you create a new view template file. It'll allow you to easily select any of the available view engines your have installed on your machine–giving you th E choice to use whichever view approach feels most natural to you:
Razor'll be one of the "View engine options We ship Built-into asp.net MVC." All view helper methods and programming model features'll is available with both Razor and the. ASPX view engine.
You'll also be able to mix and match view templates written using multiple view-engines within a single application or sit E. For example, your could write some views using. aspx files, some with. cshtml or. vbhtml files (the file-extensions for Razor files–c# and VB respectively), and some with Spark or Nhaml. You can also have a view template using one view-engine the use of a partial view template written in another. ' ll have full choice and flexibility. Hello World Sample with Razor
Razor enables to start with static HTML (or any textual content) and then make it dynamic by adding server code to it. One of the core design goals behind Razor are to make this coding process fluid, and to enable your to quickly integrate SE RVer code into the your HTML markup with a minimum of keystrokes.
To the A quick example of this let's create a simple "Hello World", sample that outputs a:
Building it with. ASPX Code Nuggets
If we were to builds the above "Hello World" sample using ASP. NET ' s existing. ASPX markup syntax, we might write it using <%=%> blocks to indicate ' code nuggets ' within our HTML markup like so:
One observation to make about this ' Hello World ' sample is ' that ' each code nugget block requires 5 characters (<%=%> To denote the start and stop of the code sequence. Some of characters (in particular the% Key–which are center top on most keyboards) aren ' t the easiest to Touch-typ E.
Building it with Razor Syntax
You denote the "start of" a code block with Razor using a @ character. Unlike <%%> code nuggets, Razor does not require to explicitly close the Code-block:
The Razor parser has semantic knowledge of C#/VB code used within Code-blocks–which is why we didn ' t need to explicitly Close the code blocks above. Razor is able to identify the above statements as self-contained code blocks, and implicitly closed for us.
Even in this trivial "Hello World" example we ' ve managed to save ourselves a keystrokes over what we had to type before. The @ character is also easier to reach on the keyboard than the% character which makes it faster and more fluid to type. Loops and Nested HTML Sample
Let's look in another simple scenario where we want to list some products (and the price for each product beside it):
Building it with. ASPX Code Nuggets
If we were to implement the this using ASP. NET ' s existing. ASPX markup syntax, we might write the below code to dynamically generate a <ul> list with <li> items for each Product inside it:
Building it with Razor Syntax
Below is you to generate the equivalent output using Razor:
Notice above how we started a ' foreach ' Loop using the @ symbol, and then contained a line of HTML content with code block s within it. Because the Razor parser understands the C # semantics in our code block, it is able to determine the <li> cont ENT should be contained within the foreach and treated as-content that should is looped. It also recognized that the trailing} terminated the foreach statement.
Razor is also smart enough to identify the @p.name and @p.price statements the <li> element as server within and execute them each time through the loop. Notice How Razor is smart enough to automatically close the @p.name and @p.price code blocks by inferring how the HTML D code is being used together.
The ability to code like this without has to add lots of open/close markers throughout your templates ends up making th E Whole coding process really fluid and fast. If-blocks and multi-line statements
Below are a few examples of other common scenarios:
If statements
Like we foreach example above, can embed content within if statements (or any other C # or VB language construct), wit Hout has to is explicit about the code block ' s begin/end. For example:
Multi-line statements
Can denote multiple lines of code by wrapping it within a @{code} blocks like so:
Notice above how variables can span multiple server code blocks–the ' message ' variable defined within the multi-line @{ block, for example, are also being used within the @message code block. This is conceptually the same as the <%%> and <%=%> syntax. aspx within files.
Multi-token statements
The @ () syntax enables a code block to have multiple tokens. For example, we could re-write the above code to concatenate a string and the number together within a @ (code) Block:
integrating Content and Code
The Razor parser has a lot of language smarts Built-into it–enabling to rely in it to do the heavily lifting, as Opp Osed to you have to explicitly do it yourself.
Does it break with emails addresses and other usages's @ in HTML?
Razor ' s language parser is clever enough in most cases to infer whether a @ character within a template was being used for Code or static content. For example, below I ' m using a @ character as part of the email address:
When parsing a file, Razor examines the content on the right-hand side all @ character and attempts to determine whethe R It is C # code (if it is a CSHTML file) or VB code (if it's a vbhtml file) or whether it is just static content. The above code would output the following HTML (where the email address is output as static content and the @DateTime. Now I s evaluated as code:
In cases where the content is valid as code as WEII (and you want to treat it as content), can explicitly escape characters by typing @@.
Identifying Nested Content
When nesting HTML content within a if/else, foreach or other blocks statement, you should look to wrap the inner content W Ithin an HTML or XML element to better identify, it is the beginning of a content block.
For example, below I ' ve wrapped a multi-line content blocks (which includes a code-nugget) with a <span> element:
This would render the below content to the client–note that it includes the <span> tag:
Can optionally wrap nested content with a <text> blocks for cases where your have content that you want to render To the Clientwithout a wrapping tag:
The above code would render the below content to the client–note which it does not include any wrapping tag:
HTML Encoding
By default content emitted the using a @ block are automatically HTML encoded to better protect the XSS against attack. Layout/masterpage scenarios–the Basics
It is important to have a consistent look and feel across all of the pages within your. ASP.net 2.0 introduced the concept of "master Pages" which helps the enable this when using. aspx based pages or templates. Razor also supports this concept using ' layout pages ' –which allow you to define a common site template, and then inherit Its look and feel across the views/pages on your site.
Simple Layout Example
Below is a simple example of the a layout Page–which we ' ll save in a file called "sitelayout.cshtml". It can contain any static HTML content we want to include in it, as as as the dynamic server code. We'll then add a call to the "Renderbody ()" helper method at the location in the template where we want to "fill in" Speci FIC body content for a requested URL:
We can then create a view template called "home.cshtml" that contains only the content/code necessary to construct the SPE Cific body of a requested page, and which relies on the layout template for it outer content:
Notice above how we are explicitly setting the ' layoutpage ' property in code within our home.cshtml file. This indicates so we want to use the sitelayout.cshtml template as the layout for this view. We could alternatively indicate the layout file we want to use within a asp.net MVC Controller invoking home.cshtml as a V Iew template, or by configuring it as the default layout "to" in which case we can specify it in one file In our project and have all view templates pick it up automatically).
When we render home.cshtml as a view-template, it would combine the content from the layout and sub-page and send the Follo Wing content to the client:
Compact, clean, expressive Code
One of the things to notice in the code above was that syntax for defining layouts and using them from Views/pages is C Lean and minimal. The code screen-shots above of the sitelayout.cshtml and home.cshtml files containliterally all of the content in the two . cshtml Files–there is no extra configuration or additional tags, no <%@ page%>, prefix any other nor or PR Operties that need to is set.
We are trying to keep the code for your write compact, easy and fluid. We also want to enable anyone with a-text editor to is able to open, edit and easily tweak/customize them. No code generation or IntelliSense required. layout/masterpage scenarios–adding Section Overrides
Layout pages Optionally support the ability to define different "sections" within them this view templates based on the LA Yout can then override and "fill-in" with custom content. This enables your to easily override/fill-in discontinuous content regions within a layout page, and provides your with a lo T of layout flexibility for your site.
For example, we could return to our sitelayout.cshtml file and define two sections within we layout this view Templat Es within our site can optionally choose to fill-in. We ' ll name these sections "menu" and "footer" –and indicate, they are optional (and not required) within my Site by Passing an optional=true parameter to the rendersection () helper call (we are doing this using the newc# optional R syntax that I ' ve previously blogged about).
Because these two sections are marked as "optional", I am not required to define them I within file. My site would continue to work fine if they aren ' t there.
Let's go back to home.cshtml, though, and define a custom Menu and Footer section for them. The below screenshot Containsall of the content in home.cshtml–there be nothing else required in the file. Note:i moved setting the Layoutpage to be a site wide Setting–which are why it is no longer there.
We custom "menu" and "Footer" section overrides are being defined within named @section {} blocks within the file. We chose require you to wrap the "main/body" content within a section and instead to just keep it inline (which bot H saves keystrokes and enables to easily add sections to your layout pages without have to go back through all your Existing pages changing their syntax).
When we render home.cshtml as a view-template again, it'll now combine the content from the layout and sub-page, Integra Ting the two new custom section overrides in it, and send down the following content to the client:
encapsulation and Re-Use with HTML Helpers
We ' ve covered how to maintain a consistent site-wide look and feel using layout pages. Let's now look in how we can also create re-usable "HTML helpers" which enable us to cleanly encapsulate HTML generation Fu Nctionality into libraries so we can re-use across our site–or even across multiple and different sites.
Code Based HTML Helpers
asp.net MVC today has the concept of "HTML Helpers" –which are methods this can be invoked within, and code-blocks Encapsulate generating HTML. These are implemented are using pure code today (typically as extension methods). All of the existing HTML extension methods built with ASP.net MVC (both ones we ' ve built and ones built by others) 'll wo RK using the "Razor" View engine (no code changes required):
Declarative HTML Helpers
Generating HTML output using a code-only class approach works–but is not ideal.
One of the features we are looking to enable with Razor are an easy way to create re-usable HTML helpers using a more DECLA rative approach. We are to enable the Define reusable helpers using a @helper {} declarative syntax like below.
You'll be able to place cshtml files, contain, helpers into a views\helpers directory and then re-use Any view or page in your site (no extra steps required):
Note above how we productlisting () helper is able to define arguments and parameters. This is enables to the parameters you want to them (and take full advantage the existing languages features like Opti Onal parameters, nullable types, generics, etc). You'll also get debugging support for them within Visual Studio.
Note:the @helper syntax won ' t being in the ' the ' of the ' razor–but are something we hope we are enabled with the next drop . Code-based helpers would work with the the
Passing Inline Templates as Parameters
One other useful (and extremely powerful) feature we are enabling with Razor are the ability to pass "inline template" para Meters to helper methods. These "inline templates" can contain both HTML and code, and can is invoked on-demand by helper methods.
Below is a example the ' This feature ' in action using a ' Grid ' HTML Helper that renders a DataGrid to the client:
The Grid.render () method call above is C #. We are using the new C # named parameter syntax to pass strongly-typed arguments to the Grid.render Method-which we Get full statement completion/intellisense and compile-time checking for the above syntax.
The "format" parameter we are passing when defining columns was an "inline template" –which contains both custom HTML and Code, and which we can use to customize the format of the data. What is powerful about this are that the Grid helper can invoke we inline template as a delegate method, and invoke it as Needed and as many times as it wants. In the scenario above it'll call it all time it renders a row at the Grid–and pass in the "item" This our template CA n use to display the appropriate response.
This capability would enable much richer HTML helper methods to be developed. You'll be able to implement them using both a code approach (like the way your build extension methods today) as OK as us ing the declarative @helper {} approach. Visual Studio Support
As I mentioned earlier, one of our goals with Razor are to minimize typing,