Basic ASP.NET web page structure
This is the second article in my series on writing a simple ASP.NET web page that resembles a simple PHP file. My first article discussed how encodings are handled in PHP.NET
In this second article, I will discuss the code structure.
The Single-File Page Model structure
Microsoft describes the single-file page model where the page’s markup and the programming code is in the same physical .aspx
file. This is exactly the same model that ASP.NET’s predecessor, classical ASP was build upon, and it is also the model that PHP uses.
In my first article, I described my requirements as being quite simple. All I needed to do was to add simple functionality to a pre-exisiting web page (static HTML file). The single-file page model was the obvious place to start.
The following is a bird’s-eye view of Microsoft’s example;
[vbnet]
‘ Controller code to set the text on Label1
‘ in response to a click on Button1
‘ View code in plain HTML with tags indicating the locations
‘ of Label1 and Button1
[/vbnet]
Let’s see how I added the functionality that I required onto this structure.
Encoding links easily
My objective is to create a helper function that generates url-encoded links.
Suppose I want to have links to a query results page. The query that we want to send is;
[ruby]
reactivity: “Bovine(ウシ)”
[/ruby]
Using an online url encoder, we can see that “Bovine(ウシ)” should be url encoded to “Bovine%ef%bc%88%e3%82%a6%e3%82%b7%ef%bc%89” (if we use UTF-8). Hence the link should look like the following;
[html]
Bovine(ウシ)
[/html]
We could always use the online url encoder and then paste the results to a static HTML file. However it would be difficult to manage the file because the urlencoded URL is incomprehensible to human beings.
What we need is a link
function that will take non-ASCII arguments and create the url encoded link for us.
The code that I came up with is shown here;
[vbnet]
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
‘ initialization stuff to do immediately after page load
End Sub
Private Function urlEncodeUtf8(myString As String) As String
urlEncodeUtf8 = HttpUtility.UrlEncode(myString, new System.Text.UTF8Encoding)
End Function
Public Function link(label As String, endpoint As String, query As String(,)) as String
Dim tuples As New ArrayList()
Dim i As Integer
For i = LBound(query) To UBound(query)
tuples.Add(query(i, 0) & “=” & urlEncodeUtf8(query(i, 1)))
Next
Dim href As String = “http://api.example.com/api.php?ep=” & endpoint & “&” & Join(tuples.ToArray(), “&”)
link = “” & label + “”
End Function
‘…
‘…
‘…
[/vbnet]
Virtual Basic syntax itself is quite simple and easy to grasp. However, without an ASP.NET nor Visual Basic background, there were a quite a few concepts that I initially had difficulty with.
Code/Render blocks in ASP.NET
In PHP, you have <?php>
tags that you can put anywhere in the page. Inside these tags, you place PHP code. There is no limit to what code you can insert and all the tags function identically. However, this is not the case for ASP.NET. ASP.NET .aspx
files have distinct blocks of code that are called code blocks and render blocks. These two are intended to be used in discrete ways.
The code blocks are the regions surrounded by <script runat="server">
tags. Here you define global variables and functions. On the other hand, you cannot directly write code that will be executed; you can only write definitions. If you want to write code that will be executed, you have to write it inside the Page_Load
function which is the event handler that is called immediately after the page is loaded.
Render blocks are surrounded by <% %>
or <%= %>
tags and are executed when the page is rendered. At first glance, they look exactly like the tags in classic ASP or the <?php ?>
tags in PHP; you embed code inside HTML. There is a big difference though. You cannot declare functions or subroutines inside these render blocks. You can however declare variables.
So basically, you define your functions in the code blocks and render your results in render blocks. I suppose the idea is to make sure that you don’t mix too much code with your HTML.
In my example, we defined all our functions (Page_Load
, urlEncodeUtf8
and link
) at the top of the page inside a code block (<script>
). In the render block (<%= %>
), we simply called the link
function.
Passing complex data as arguments in Visual Basic
For the link
function, we want to pass the query as a data structure (not a string). In PHP, the natural choice would be to use associative arrays. Hence the syntax for calling the link
function would look like this;
[php]
<?php echo link(“Bovine(ウシ)”, “endpoint.php”,
array (“type” => “Whole IgG”,
“reactivity” => “Bovine(ウシ)”,
“title” => “Bovine Whole IgG secondary-antibodies”)) %>
[/php]
PHP 5.4 has added a short array syntax which makes it even more convenient to write the arguments for this function;
[php]
<?php echo link(“Bovine(ウシ)”, “endpoint.php”,
[“type” => “Whole IgG”,
“reactivity” => “Bovine(ウシ)”,
“title” => “Bovine Whole IgG secondary-antibodies”]) %>
[/php]
Ruby also has a simple syntax for associative arrays or hashes;
[ruby]
“Whole IgG”,
“reactivity” => “Bovine(ウシ)”,
“title” => “Bovine Whole IgG secondary-antibodies” %>
[/ruby]
Ruby 1.9 took this one step further and made it this simple;
[ruby]
[/ruby]
I am emphasizing the terseness of the argument syntax because this code is going to sit inside the HTML. Verbose code would completely interupt the HTML and make it harder to understand. Hence if we are going to insert Visual Basic code into the view at all, we should try to make it simple.
Now Virtual Basic has collections like ArrayList
, Hashtable
, SortedList
, NameValueCollection
and others. A Hashtable
or a NameValueCollection
would be ideal for the arguments that we want to pass. In fact, the Request.QueryString
property that is used to retrieve GET
parameters returns a NameValueCollection
.
The problem is that the NameValueCollection
and all the other collections do not have a terse syntax for populating it with values. There apparently is a new From
keyword available from .NET Framework 4 that addresses this, but it doesn’t seem to be widely used.
If we were to use a NameValueCollection
, the traditional syntax (without “From”) would be like this;
[vbnet]
‘
[/vbnet]
This is totally ridiculous.
The exception is a Visual Basic Array. Visual Basic provides a relatively terse syntax to initialize arrays.
[vbnet]
Dim myArray() As String = {“first_element”, “second_element”}
[/vbnet]
and you can do multi-dimension arrays like so;
[vbnet]
Dim myArray() As String(,) = {{“1-1”, “1-2”}, {“2-1”, “2-2”}}
[/vbnet]
Because the only terse way was to use multi-dimension arrays, we ended up using the following argument structure for the link
function.
[vbnet]
[/vbnet]
To sum up, we gave up on the more desirable collections like NameValueCollection
because it would be ridiculously verbose. Instead we used multi-dimensional arrays. I would say that the result is pretty OK, but it is troubling how Visual Basic seems to be indifferent to making code concise.
Solution for .NET 4.0
If we are on .NET 4.0, we can use the from keyword to use collections and still keep the code concise (official documentation);
[vbnet]
[/vbnet]
This is much better, but unfortunately doesn’t work on .NET 2.0. It’s unfortunate that Microsoft doesn’t promote this more on their documentation for the collection objects, because I think it’s a very important feature. I was initially bewildered that the NameValueCollection
class couldn’t take a Visual Basic Array as an argument on its constructor method, but I suppose that that was due to compatibility concerns with C#. The corresponding syntax in C# is simpler and actually looks as if we are passing an array to the constructor, although that isn’t what is happening behind the scenes.
Summary
In this article, I showed how we used the single-file page structure to add simple code to a web page.
Although this was a very simple exercise, we learnt that we can’t place functions anywhere we want in ASP.NET. We have to place them inside a code block. We also learnt that sending complex arguments to a function can be a bit difficult.
In the next article, I will show how to reuse code for the link
function in other pages, which was again quite a surprise for me.
Other articles in this series
- Understanding how ASP.NET handles source file encoding. (part 1)
- Basic ASP.NET web page (
.aspx
) structure. (part 2)
- Making Visual Basic function calls as terse as possible in the view code. (part 2)
- Ways to reuse code in ASP.NET. (part 3)