Introduction
Call me a luddite, but I usually look for the most low-level, versatile way to solve a problem that doesn't require learning the idiosyncrasies of some new framework. I often prefer the command line to a GUI, I prefer a text editor to a WYSIWYG editor for web pages, and I used to program mainly in C. With respect to programming, I finally caved and realized the benefits of C#. So, now I'm using it for desktop applications and web development. This naturally leads to using ASP.NET.
There are some things I like about ASP.NET and some I hate.
What I like:
- the .NET Framework
- C#
- code render blocks
<% %>
(for outputting HTML without having to concatenate string literals)
- automatic compilation when source code changes (so I can drop a .aspx file into a directory and it instantly becomes viewable in a web browser)
What I hate:
- Microsoft's web controls (for example:
<asp:Button>
, <asp:TextBox>
, and <asp:DataGrid>
) that add new complications to HTML I already know
- most states of Microsoft's page life cycle (because load, render, and unload are all the states I want an API to manage without my control)
After using web controls for a little while, recently I wanted to make a simple web page that took some user input and produced some dynamic output, and I wanted to avoid most of that complexity. I wanted to use a plain HTML <form>
element (i.e., without runat="server"
), and I wanted to use HTTP GET and POST variables instead of ASP.NET event callback functions, but I still wanted to use .NET, C#, and code render blocks. Included are a couple simple pages that do this.
Note
Do not mistake that many states of the page life cycle are still running in these pages. I even hook Page_Load
(and I have hooked Page_Unload
in a page I'm writing right now). The point is that by avoiding web controls and by avoiding any special mechanisms of the Page
class, I can concentrate on raw HTML/HTTP, and most states of the page life cycle become irrelevant.
I should say more about this term, the "page life cycle". When I think of the "page life cycle" in my mind, I don't think about the Page_Load
event, rendering the page, or the Page_Unload
event. I don't tend to be pedantic about terminology. Those three states are common sense to me. Every module commonly initializes itself, runs, and then shuts down.
When I think of the "page life cycle", what I'm thinking of is the seemingly extraneous and/or redundant states like Page_PreInit
, Page_Init
, Page_InitComplete
, Page_PreLoad
, Page_LoadComplete
, Page_PreRender
, and Page_SaveStateComplete
. I'm also thinking of the setting of the IsPostBack
flag, view state, and control events. I lop together in my mind all these things that I think make ASP.NET ugly, and I think of them as the "page life cycle". What I've tried to do here is avoid as many of these ugly bits as I can and preserve the parts that, to me, are nice and easy to understand.
The code
In the GET example, the user input becomes part of the URL and can be persisted through hidden form fields. The key .NET mechanisms are Request.QueryString
for input and Response.Write
for output.
The POST example is almost exactly the same as GET with minor differences. Of course, the URL does not store the input. Instead of Request.QueryString
, Request.Form
is used to access it. Finally, instead of the method
attribute of the form being get
, it is post
. Input can still be persisted through hidden form fields (or cookies, but I didn't use this method).
HTTP GET:
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<head>
<title>HTTP GET test</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script runat="server" language="C#">
private string prev_first_name;
private string first_name;
private string prev_last_name;
private string last_name;
private void Page_Load()
{
prev_first_name = Request.QueryString["prev_first_name"];
first_name = Request.QueryString["first_name"];
prev_last_name = Request.QueryString["prev_last_name"];
last_name = Request.QueryString["last_name"];
}
private void WriteDisplay()
{
Response.Write(
Environment.NewLine +
"Previous first name entered: \"" + prev_first_name +
"\"<br/>"
);
Response.Write(
Environment.NewLine +
"First name entered: \"" +
first_name + "\"<br/>"
);
Response.Write(
Environment.NewLine +
"Previous last name entered: \"" +
prev_last_name + "\"<br/>"
);
Response.Write(
Environment.NewLine +
"Last name entered: \"" + last_name +
"\"<br/>"
);
}
private void WritePersistentVars()
{
WriteHiddenFormVar("prev_first_name", first_name);
WriteHiddenFormVar("prev_last_name", last_name);
}
private void WriteHiddenFormVar(string name, string value)
{
if(value != null)
{
Response.Write(
Environment.NewLine +
"<input " + "name=\"" + name + "\"" +
" type=\"hidden\"" +
" value=\"" + value + "\"" +
"/>"
);
}
}
</script>
</head>
<body>
<p><% WriteDisplay(); %></p>
<form action="<% Response.Write(Request.Url.AbsolutePath); %>"
method="get">
<br/>
First name: <input name="first_name"/><br/>
Last name: <input name="last_name"/><br/>
<% WritePersistentVars(); %>
<p><input type="submit" value="Enter"/></p>
</form>
</body>
</html>
HTTP POST:
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<head>
<title>HTTP POST test</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script runat="server" language="C#">
private string prev_first_name;
private string first_name;
private string prev_last_name;
private string last_name;
private void Page_Load()
{
prev_first_name = Request.Form["prev_first_name"];
first_name = Request.Form["first_name"];
prev_last_name = Request.Form["prev_last_name"];
last_name = Request.Form["last_name"];
}
private void WriteDisplay()
{
Response.Write(
Environment.NewLine +
"Previous first name entered: \"" + prev_first_name +
"\"<br/>"
);
Response.Write(
Environment.NewLine +
"First name entered: \"" + first_name +
"\"<br/>"
);
Response.Write(
Environment.NewLine +
"Previous last name entered: \"" +
prev_last_name + "\"<br/>"
);
Response.Write(
Environment.NewLine +
"Last name entered: \"" + last_name +
"\"<br/>"
);
}
private void WritePersistentVars()
{
WriteHiddenFormVar("prev_first_name", first_name);
WriteHiddenFormVar("prev_last_name", last_name);
}
private void WriteHiddenFormVar(string name, string value)
{
if(value != null)
{
Response.Write(
Environment.NewLine +
"<input " + "name=\"" + name + "\"" +
" type=\"hidden\"" +
" value=\"" + value + "\"" +
"/>"
);
}
}
</script>
</head>
<body>
<p><% WriteDisplay(); %></p>
<form action="<% Response.Write(Request.Url.AbsolutePath); %>"
method="post">
<br/>
First name: <input name="first_name"/><br/>
Last name: <input name="last_name"/><br/>
<% WritePersistentVars(); %>
<p><input type="submit" value="Enter"/></p>
</form>
</body>
</html>
Using the code
To use this code, install the IIS (Internet Information Server) web server that comes on the Windows installation CD, or get access to a server that runs it, install the .NET Framework, get IIS and the .NET Framework to work together (which may take a web search), drop raw_get.aspx or raw_post.aspx into one of the server's publicly accessible directories, and view them in a web browser with URLs such as http://localhost/raw_get.aspx or http://localhost/raw_post.aspx.
History
- Revision 0: initial
- Revision 1: separated script from rendering of page
- Revision 2: moved script into head
- Revision 3: attempted to clarify the meanings of "without" and "avoiding" especially with respect to the page life cycle