# Sunday, 10 November 2013

A few years ago Microsoft introduced a new ASP.Net feature called ASP.Net Web Pages. I found the light use of control tags intriguing, but I didn't see any reason to use it instead of the standard ASP.Net Web Forms style of developing web sites. It also didn't help that Microsoft seemed like it was talking about Razor as a side component to be used with ASP.Net MVC another new feature which I wasn't too keen on. But recently as I sat down to take a look at Razor once more, it finally dawned on me what Razor is actually good for. So make yourself a drink and come back to the longest code snippet filled article ever written by me on this site. (This is the second time I'm typing this actually because the Blog Engine puked on all the code formatting in the previous case)

To be able to follow this article properly you would need to have intermediate knowledge of ASP.Net Web Forms and HTML, it will also help if you had some understanding of the various Javascript libraries such as JQuery.

We'll start off by looking at a simple ASP.Net Web Forms page.

   1: <%@ Page Language="VB" %>
   2: <!DOCTYPE html>
   3:  
   4: <script runat="server" >
   5:     Protected Sub btnGreet_Click(sender As Object, e As EventArgs)
   6:         lblGreeting.Text = "Hello " & txtUsername.Text
   7:     End Sub
   8: </script>
   9:  
  10: <html xmlns="http://www.w3.org/1999/xhtml">
  11: <head runat="server">
  12:     <title></title>
  13: </head>
  14: <body>
  15:     <form id="form1" runat="server">
  16:     <div>        
  17:         <div>
  18:             Username : <asp:TextBox runat="server" ID="txtUsername"></asp:TextBox> 
  19:             <asp:button runat="server" ID="btnGreet" Text="Greet" OnClick="btnGreet_Click" />
  20:         </div>
  21:         <div><asp:Label runat="server" ID="lblGreeting"></asp:Label></div>        
  22:     </div>
  23:     </form>
  24: </body>
  25: </html>

The function of the page is simple, a name is entered into the txtUsername textbox (line 18) and when the btnGreet button (line 19) is clicked, the click handler at line 5 is executed, which creates a string saying "Hello [txtusername.text]" and drops it into the label called lblGreeting to be displayed to the user.

Noticed how at no time did we need to deal with any of the HTML constructs, all the elements and code are very straight forward and easily understood. It's this abstraction of HTML which reduced the barrier of entry for making a web site which makes ASP.Net Web Forms so powerful and inviting to anyone starting web developement.

Now let's look at the same page, which does the exact same thing but this time using Razor.

   1: @Code
   2:     Dim Greeting As String
   3:     
   4:     If (IsPost) Then
   5:         If String.IsNullOrEmpty(Request.Form("btnGreet")) = False Then
   6:             Greeting = "Hello " & Request.Form("txtUsername")
   7:         End If
   8:     End If
   9: End Code
  10:  
  11: <!DOCTYPE html>
  12: <html>
  13:     <head>
  14:         <title>Some Razor Test</title>
  15:     </head>
  16:     <body>
  17:         <form method="post">
  18:             <div>
  19:                 <div>
  20:                     Username : <input name="txtUsername" value="@Request.Form("txtUsername")" />
  21:                     <button type="submit" name="btnGreet" value="btnGreet">Greet</button>
  22:                 </div>
  23:                 <div>@Greeting</div>        
  24:             </div>
  25:         </form>
  26:     </body>
  27: </html>

At first glance it looks exactly the same, you still have an textbox called txtUsername (line 20) and a button called btnGreet (line 21), but notice this time that they are now plain HTML elements instead of some special control tag. This is because Razor chooses has no abstraction of HTML elements in it, you're pretty much going back to basics when you're trying to make a website using Razor.

Now for those of you who have no clue what's actually happening in the @Code chunk where all the click detection is done, here's a quick summary

  • The code needs to know wheter the page actually had anything posted to it, this is done via the IsPost command at line 4
  • HTML form posting actually has no notion of a button, that's why you just test (line 5) for the presence of the value (line 21) which the button is supposed to send to determine which button was clicked.
  • Because Razor just relies on emitting plain HTML, in order to display the output back to the user, the message is set into a variable (line 6) and the variable is then emitted to the page on line 23.

Without the abstraction of HTML like in Web Forms, attempting to write a web page in Razor would require the developer to have a full and proper understanding of HTML in order to get things done properly. Heck, look closely at Line 20 where it says @Request.Form("txtUsername") with Razor, you have to go the extra mile to make sure that the previously submitted value actually appears back in the text box. So if Razor seems to take so much additional effort to learn and deal with why would we want to use Razor?

Because we don't make web pages like this anymore.

The previous examples were of a very traditional webpage, you click a button, it posts form data back to the server which sends over a new page to you. That was how things worked since the beginning. But nowadays, we have finally arrived to a point that nearly every device that can access a web page is able to handle AJAX properly so we need to re-examine our sample then.

Here's a Razor page that does what the previous was doing but by using AJAX techniques this time.

   1: <!DOCTYPE html>
   2: <html>
   3:     <head>
   4:         <title>AJAX Test</title>
   5:         <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
   6:         <script>
   7:             $(function(){
   8:                 $("#btnGreet").click(function () {
   9:                     $.post("process.aspx",
  10:                         {username:$("#txtUsername").val()},
  11:                         function (retData) {
  12:                             $("#divGreeting").text(retData);
  13:                         },"json")
  14:                 });
  15:             })
  16:         </script>
  17:     </head>
  18:     <body>
  19:          <div>
  20:                 <div>
  21:                     Username : <input id="txtUsername" />
  22:                     <button type="button" id="btnGreet">Greet</button>
  23:                 </div>
  24:                 <div id="divGreeting"></div>        
  25:             </div>
  26:     </body>
  27: </html>

What the code above is doing is that when the btnGreet button is clicked (line 8) JQuery will be used to post an AJAX request to a page for processing (line 9) and the results would then be stuffed into the divGreeting HTML tag (line 12) Now let's take a quick look at the code in the process.aspx page.

   1: <%@ Page Language="VB" %>
   2: <script runat="server">
   3:     Sub page_load(sender As Object, e As EventArgs) Handles Me.Load
   4:         Dim Greeting = "Hello " & Request.Form("username")
   5:         
   6:         'Return the string in simple JSON form
   7:         Dim oSerial As New Script.Serialization.JavaScriptSerializer
   8:         Response.Write(oSerial.Serialize(Greeting))
   9:         Response.End()
  10:     End Sub
  11: </script>

It's pretty simple, it takes the input posted from the client page, and creates the greeting string and writes it as a JSON string as a response.

Through the use of JQuery, it's much more straight forward to write code to send a request to the server and put the response into a tag for display. If you have yet to know about the awesomeness that is JQuery please learn about it at it's website.

For those of you who do know about JQuery and HTML in general you might have noticed something, The Razor page which I showed above, DOESN'T contain any code at all other than plain HTML and Javascript.

And you'd be right about that, because just performing simple AJAX functionalities do not require any backend code at all. Let's examine a scenario in which we would require the features of backend code, such as when we need to have a common layout, it is also through this scenario that we can also see why Web Forms don't work well for creating modern Web Pages.

Here is a Web Forms master page.

   1: <%@ Master Language="VB" %>
   2: <!DOCTYPE html>
   3:  
   4: <html xmlns="http://www.w3.org/1999/xhtml">
   5: <head runat="server">
   6:     <title></title>
   7:     <asp:ContentPlaceHolder id="head" runat="server">
   8:     </asp:ContentPlaceHolder>
   9: </head>
  10: <body>
  11:     <form id="form1" runat="server">
  12:         <h1>Web Forms Master Page</h1>
  13:     <div>
  14:         <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
  15:         
  16:         </asp:ContentPlaceHolder>
  17:     </div>
  18:     </form>
  19: </body>
  20: </html>

And here's a page which uses the master page.

   1: <%@ Page Title="" Language="VB" MasterPageFile="~/masterpage/webform.master" %>
   2:  
   3: <script runat="server">
   4:     Protected Sub btnGreet_Click(sender As Object, e As EventArgs)
   5:         lblGreeting.Text = "Hello " & txtUsername.Text
   6:     End Sub
   7: </script>
   8:  
   9: <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
  10:     <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
  11: </asp:Content>
  12: <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
  13:     <div>        
  14:         <div>
  15:             Username : <asp:TextBox runat="server" ID="txtUsername" ></asp:TextBox> 
  16:             <asp:button runat="server" ID="btnGreet" Text="Greet" OnClick="btnGreet_Click" />
  17:         </div>
  18:         <div><asp:Label runat="server" ID="lblGreeting"></asp:Label></div>        
  19:     </div>
  20: </asp:Content>
  21:  

Then we have the Razor master page (which they call the layout page)

   1: @Code
   2:     Layout = "razormaster.vbhtml"
   3:     
   4:     Dim Greeting As String
   5:     PageData("Title") = "Hello From Razor"
   6:     If (IsPost) Then
   7:         If String.IsNullOrEmpty(Request.Form("btnGreet")) = False Then
   8:             Greeting = "Hello " & Request.Form("txtUsername")
   9:         End If
  10:     End If
  11: End Code
  12:  
  13: @Section head
  14:     <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
  15: End Section
  16:  
  17: <form method="post">
  18:     <div>
  19:         <div>
  20:             Username :
  21:             <input name="txtUsername" value="@Request.Form("txtUsername")" />
  22:             <button type="submit" name="btnGreet" value="btnGreet">Greet</button>
  23:         </div>
  24:         <div>@Greeting</div>
  25:     </div>
  26: </form>

And then the Razor page which consumes the master page above.

   1: @Code
   2:     Layout = "razormaster.vbhtml"
   3:     
   4:     Dim Greeting As String
   5:     PageData("Title") = "Hello From Razor"
   6:     If (IsPost) Then
   7:         If String.IsNullOrEmpty(Request.Form("btnGreet")) = False Then
   8:             Greeting = "Hello " & Request.Form("txtUsername")
   9:         End If
  10:     End If
  11: End Code
  12:  
  13: @Section head
  14:     <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
  15: End Section
  16:  
  17: <form method="post">
  18:     <div>
  19:         <div>
  20:             Username :
  21:             <input name="txtUsername" value="@Request.Form("txtUsername")" />
  22:             <button type="submit" name="btnGreet" value="btnGreet">Greet</button>
  23:         </div>
  24:         <div>@Greeting</div>
  25:     </div>
  26: </form>

And then let's see the resulting output of using a Web Forms master page.

   1: <!DOCTYPE html>
   2:  
   3: <html xmlns="http://www.w3.org/1999/xhtml">
   4: <head><title>
   5:  
   6: </title>
   7:     <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
   8: </head>
   9: <body>
  10:     <form method="post" action="webform.aspx" id="form1">
  11: <div class="aspNetHidden">
  12: <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="fVV0awxto46HEX7xLDm+lDpI6nFMe1PPeFWSzKmf2poIAjdHXPAgTmFgvpC+YZvUCY5s/9IguEKGO9JMPrau4wFxigGwnrlSeLEluBUeq7U=" />
  13: </div>
  14:  
  15: <div class="aspNetHidden">
  16:  
  17:     <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="ZPtG7DBpp5mvTE/LJjZSigEiI2CgfjpBUUQfyfo/kX+aLvP87f8YCTdUvvnVugm1CD5l2BbhJCccDeUUVbF8mT0dcFTxreXdDxhLSIrHdIUJl7FQMRX+XEouJsSHIGGVoOZ5TvLp5nI7+eNQIYfmnQ==" />
  18: </div>
  19:         <h1>Web Forms Master Page</h1>
  20:     <div>
  21:         
  22:     <div>        
  23:         <div>
  24:             Username : <input name="ctl00$ContentPlaceHolder1$txtUsername" type="text" id="ContentPlaceHolder1_txtUsername" /> 
  25:             <input type="submit" name="ctl00$ContentPlaceHolder1$btnGreet" value="Greet" id="ContentPlaceHolder1_btnGreet" />
  26:         </div>
  27:         <div><span id="ContentPlaceHolder1_lblGreeting"></span></div>        
  28:     </div>
  29:  
  30:     </div>
  31:     </form>
  32: </body>
  33: </html>

This is when you can see some interesting things happen to the page, the main thing being that the id property of our controls have been changed from their originally declared names like txtUsername and btnGreet to ContentPlaceHolder1_txtUsername and ContentPlaceHolder1_btnGreet. This is because as mentioned previously ASP.Net Web Forms abstracts and hides the need to understand HTML constructs and renaming the controls when they're in a master page or some other container is just how it works. If you're familiar with Javascript programming you'd realize that having such unpredictable things happen to your IDs would cause your code to fail if you're not careful, and indeed the way this abstraction works does cause a lot of people to feel that ASP.Net Web Forms is not compatible with the modern AJAX concept.

It's not that it's not compatible it's just that it's tedious and takes much more time and understanding to get it to work in with all the AJAX frameworks available out there.

Now let's take a look at the results of using a Razor layout page.

   1: <!DOCTYPE html>
   2: <html>
   3:     <head>
   4:         <title>Hello From Razor</title>        
   5:         <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js" type="text/javascript"></script>
   6:     </head>
   7:     <body>
   8:         <h1>Razer Master Page</h1>        
   9: <form method="post">
  10:     <div>
  11:         <div>
  12:             Username :
  13:             <input name="txtUsername" value="" />
  14:             <button type="submit" name="btnGreet" value="btnGreet">Greet</button>
  15:         </div>
  16:         <div></div>
  17:     </div>
  18: </form>
  19:  
  20:     </body>
  21: </html>

The results from using a Razor method is that everything is exactly as how they were defined in the pages themselves, the fact that Razor doesn't contain any sort of HTML abstraction and is just exists to provide server side code to generate HTML means that the resulting pages are much more predictable and easier to integrate with any modern client side/HTML5/Javascript/MVC framework such as KnockoutJS or AngularJS.

And that's it, an initial answer to why you should use Razor in a modern ASP.Net web site and the article is really just barely scratching the surface of the new ASP.Net web stack for modern web sites. A more in depth example would include the use of multiple elements together such as Razor, WebAPI, JQuery and AngularJS. But this article is already long enough as it is.

This post might not have been the most clear cut post of all, takes some time to digest what was written and try it out yourself in VS2012/2013 or Web Matrix.

In summary what you should understand from reading this is that while ASP.Net Web Forms is great for making traditional post back style pages (and STILL is) you should be looking towards Razor to create any page that relies on modern Javascript libraries.


Note that you can Post As GUEST as well.
blog comments powered by Disqus