Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

ASP.NET Guestbook Application

, 26 Jan 2002 CPOL
A one-to-one ASP to ASP.NET port of a simple guestbook application using ASP and an Access database
aspnet_guestbook.zip
guestbook.mdb
<%@ Page Language="C#"%>
<%@ Import Namespace="System.Data"%>
<%@ Import Namespace="System.Data.OleDb"%>

<script runat=server>

// #################################################################
// #
// # file:
// # 	guestbook/index.asp
// #
// # description:
// # 	guestbook application.
// #
// # author:
// # 	Uwe Keim, uk@zeta-software.de
// # 	zeta software GbR, Germany (www.zeta-software.de)
// #
// # history:
// # 	2002-01-26 Uwe Keim   converted for use with ASP.NET and C#.
// # 	2002-01-26 Uwe Keim   fixed some suggestions from CodeProject comments.
// # 	2000-01-13 Uwe Keim   fixed typo when deleting from the database.
// # 	2000-01-13 Uwe Keim   added count-down.
// # 	                      created resource strings.
// # 	1999-12-30 Uwe Keim   added admin mode.
// # 	                      added multiple pages and other stuff.
// # 	1999-11-24 Uwe Keim   file created.
// #
// #################################################################

// #################################################################
// configuration.

string DB_STR { get { return "Provider=Microsoft.Jet.OLEDB.4.0; Persist Security Info=False; Data Source=" + Server.MapPath("guestbook.mdb"); } }

// how many entries are being displayed on one page.
// normally you would specify here something between 20 and 50.
int HITS_PER_PAGE = 5;

// string resources, used by other parts of the page.
// used in order to separate code from content.
//-todo: add more.
string IDS_ANONYMOUS     = "Anonymous";
string IDS_FIELDSMISSING = "Not all required fields were filled out. Entry was not created.";
string IDS_ERRORINSERT   = "Error inserting entry.";
string IDS_ERRORDELETE   = "Error deleting entry.";
string IDS_MAIL          = "Send e-mail to";
string IDS_ERROR         = "Error occured.";

// #################################################################

</script>

<%
// #################################################################
// #################################################################
// #################################################################
// #################################################################
// "main function" and html code.

// set the global variable Mode.
Mode = Request["mode"]==null?MODE_NORMAL:Convert.ToInt32(Request["mode"]);

// new entry.
if ( HasMode(MODE_INSERT) )
{
	try
	{
		InsertEntry();
	}
	catch ( OleDbException e )
	{
		Response.Redirect( ErrorUrl(IDS_ERRORINSERT + " : " + e.Message), true );
		return;
	}
	catch ( Exception e )
	{
		Response.Redirect( ErrorUrl(IDS_FIELDSMISSING), true );
		return;
	}

	Response.Redirect( NormalUrl(), true );
	return;
}

// delete entry.
if ( HasMode(MODE_DELETE) )
{
	try
	{
		DeleteEntry();
	}
	catch ( Exception e )
	{
		Response.Redirect( ErrorUrl(IDS_ERRORDELETE + " : " + e.Message), true );
		return;
	}

	Response.Redirect( NormalUrl(), true );
	return;
}

// #################################################################

// query table and count the total number of entries.
DataTable Table = Execute( "SELECT * FROM Guestbook ORDER BY [Date] DESC" );

int sum_cnt = Table.Rows.Count;

// #################################################################
// calculate: pages, start, end, etc.

int cur_page;
if ( Request["pg"]==null )
	cur_page = 0;
else
	cur_page = Convert.ToInt32(Request["pg"]);

//int total_pages = sum_cnt/HITS_PER_PAGE;
int total_pages = sum_cnt/HITS_PER_PAGE;
if ( sum_cnt%HITS_PER_PAGE>0 && sum_cnt>HITS_PER_PAGE )
	total_pages++;

if ( total_pages<=0 ) 
	total_pages=1;

// the # of the displayed hits.
int hit_display_start = 1+cur_page*HITS_PER_PAGE;
int hit_display_end   = hit_display_start+Math.Min(sum_cnt,HITS_PER_PAGE)-1;
if ( hit_display_end>sum_cnt ) hit_display_end=sum_cnt;

// ---------------------------------
// the numbers must be displayed descending.

int cntdwn_start = sum_cnt-hit_display_start+1;
int cntdwn_end   = sum_cnt-hit_display_end+1;

// #################################################################
// navigation flags.

// whether there exists a previous or a next page.
bool can_prev_page       = cur_page>0;
bool can_next_page       = cur_page<total_pages-1;
bool can_prevornext_page = can_prev_page || can_next_page;

// ---------------------------------

// whether there exists a first and a last page.
bool can_first_page = can_prevornext_page && cur_page>0;
bool can_last_page  = can_prevornext_page && cur_page<total_pages-1;

// #################################################################

// "navigate" to start-recordset.
int table_index = hit_display_start-1;

// end of the pure asp-part.
// #################################################################
// #################################################################
// #################################################################
%>

<%// here starts the mixed html/asp part %>

<%// #################################################################%>
<%// #################################################################%>
<%// #################################################################%>
<%// #################################################################%>
<%// write error.%>

<% if ( HasMode(MODE_ERROR) ) { %>
	<p><font color="#FF0000"><b><%=IDS_ERROR + " : " + Request["error"]%></b></font><p>
<% } %>

<%// #################################################################%>
<%// link to insert. %>
<%// since the insert formular is at the bottom of the page, %>
<%// the user could not find it. therefore the link at the to. %>

<p><a href="#insert">Create new entry</a></p>

<%// #################################################################%>
<%// diplay information %>

<p><b><%=sum_cnt%></b> Entries found. 
	Page <b><%=cur_page+1%></b> of <b><%=total_pages%></b>, 
	entries <b><%=cntdwn_start%></b> to <b><%=cntdwn_end%></b>.</p>

<%// display top navigation buttons %>
<p> 
	<% if ( can_first_page ) { %><a href="<%=NaviUrl(0)            %>">First page</a><br>   <%}%>
    <% if ( can_prev_page  ) { %><a href="<%=NaviUrl(cur_page-1)   %>">Previous page</a><br><%}%>
	<% if ( can_next_page  ) { %><a href="<%=NaviUrl(cur_page+1)   %>">Next page</a><br>    <%}%>
	<% if ( can_last_page  ) { %><a href="<%=NaviUrl(total_pages-1)%>">Last page</a><br>    <%}%></p>

<p>
	<%
	// display discrete pages to jump directly to.
	for ( int i=1; i<total_pages; ++i )
	{
	%>

		<a href="<%=NaviUrl(i-1)%>">Page <%=i%></a>&nbsp

	<%
	}
	%>
</p>

<%
// #################################################################
// output all entries.

int cntdwn = cntdwn_start;

int cnt = 0;
while ( table_index<Table.Rows.Count && cnt<HITS_PER_PAGE )
{
	cnt++;

	DataRow row = Table.Rows[table_index];

	bool e = row["EMail"]!=null;
%>

	<%// one guestbook entry %>
	<hr size="1" color="#C0C0C0">

	<p><b><%=cntdwn%>.</b>&nbsp;<%if ( e ) {%><a title="<%=IDS_MAIL +" "+ row["EMail"]%>"
		href="mailto:<%=row["EMail"]%>"><%}%><%=row["Name"]%><%if ( e ) {%></a><%}%>, 
		<%=row["Date"]%>
		<%if ( HasMode(MODE_ADMIN) ) {%>&nbsp;<a href="<%=DeleteUrl(Convert.ToInt32(row["No"]))%>">Delete entry</a><%}%>
		</p>

	<p><%=FmtText(Convert.ToString(row["Text"]))%></p>
	<%//---------------------%>

<%
	cntdwn--;
	table_index++;
}
%>

<%// #################################################################%>
<%// separator line. %>

<p><br><hr size="1" color="#C0C0C0"><br></p>

<%// #################################################################%>
<%// output the entry-form. %>

<p><a name="insert"></a><b>Create new entry</b></p>

<p>Here you can create a new entry to the guestbook.</p>

<p>
	<form action="<%=InsertUrl()%>" method="post">
		Name:<br>
		<input type="text" name="gb_name" size="40"><br>

		<br>E-Mail:<br>
		<input type="text" name="gb_email" size="40"><br>

		<br>Text:<br>
		<textarea rows="10" name="gb_text" cols="40"></textarea><br>

		<br><input type="submit" value="Insert" name="gb_submit"><br>

		<input type="hidden" name="insert" value="true">
	</form>
</p>

<p>In your text, you can use the following HTML-tags: &lt;u&gt; &lt;i&gt;
&lt;b&gt; &lt;em&gt; (in lower-case)</p>

<%// #################################################################%>
<%// #################################################################%>
<%// #################################################################%>
<%// #################################################################%>
<%// here come the functions and constants.%>

<script runat="server">

// #################################################################
// global constants/variables.

// there is a global mode for the guestbook.
// depending on that mode, this page behaves different.
// you therefore don//t need different pages do to things like
// e.g. inserting or deleting.

// supported modes.
int MODE_NORMAL = 1;		// normal viewing of the guestbook.
int MODE_ERROR  = 2;		// an error occured and is displayed.
int MODE_INSERT = 4;		// inserting of a item into the guestbook.
int MODE_DELETE = 8;		// deleting of an item of the guestbook.
int MODE_ADMIN  = 16;		// administration-mode: allows deletion of articles.

// read mode. default to normal.
int Mode;

// #################################################################
// general helper functions.

// replaces \n with <br>.
string FmtMl( string in_str )
{
	if ( in_str==null || in_str.Length==0 )
		return "";

	string str;
	str = in_str.Replace( "\r\n", "\n" );
	str = str   .Replace( "\r"  , "\n" );
	str = str   .Replace( "\n"  , "<br>" );

	return str;
}

// allow several html codes, but not all.
string FmtText( string txt )
{
	// first encode all.
	txt = Server.HtmlEncode(txt);

	// then decode the allowed tags.
	txt = txt.Replace( Server.HtmlEncode("<u>"), "<u>" );
	txt = txt.Replace( Server.HtmlEncode("</u>"), "</u>" );

	txt = txt.Replace( Server.HtmlEncode("<i>"), "<i>" );
	txt = txt.Replace( Server.HtmlEncode("</i>"), "</i>" );

	txt = txt.Replace( Server.HtmlEncode("<b>"), "<b>" );
	txt = txt.Replace( Server.HtmlEncode("</b>"), "</b>" );

	txt = txt.Replace( Server.HtmlEncode("<em>"), "<em>" );
	txt = txt.Replace( Server.HtmlEncode("</em>"), "</em>" );

	return FmtMl(txt);
}

// #################################################################
// url functions.

// these functions should be used whenever you need a <a href="...">
// tag. instead of specifying an asp page and adding some cryptic
// parameters, you call one of these functions.
// with this approach, you can centralize the url-parameters
// in one place.

// the url of this page.
// automatically adds admin mode if currently active.
string MyselfUrl( int mode_ )
{
	if ( (Mode & MODE_ADMIN)!=0 )
		mode_ = mode_ | MODE_ADMIN;

	return Request.ServerVariables["SCRIPT_NAME"] + "?mode=" + mode_;
}

// url for viewing the guestbook in normal mode.
string NormalUrl()
{
	return MyselfUrl(MODE_NORMAL);
}

// url for displaying an error.
string ErrorUrl( string error_text )
{
	return MyselfUrl(MODE_ERROR) + "&error=" + Server.UrlEncode(error_text);
}

// url for inserting a new entry to the guestbook.
string InsertUrl()
{
	return MyselfUrl(MODE_INSERT);
}

// url for deleting an entry from the guestbook.
string DeleteUrl( int id )
{
	return MyselfUrl(MODE_DELETE) + "&id=" + Server.UrlEncode(id.ToString());
}

string NaviUrl( int page )
{
	return MyselfUrl(MODE_NORMAL) + "&pg=" + page;
}

// #################################################################
// special helper functions.

// insert a new entry to the guestbook.
void InsertEntry()
{
	// read parameters.
	string name  = Request["gb_name"];
	string email = Request["gb_email"];
	string text  = Request["gb_text"];

	// check parameters.
	if ( name==null ) name = IDS_ANONYMOUS;
	if ( text==null ) throw new Exception( "Text to insert not specified" );

	// --
	// full code to write the new entry to the database.

	OleDbConnection     conn = new OleDbConnection( DB_STR );
	OleDbDataAdapter    da   = new OleDbDataAdapter( "SELECT * FROM Guestbook", conn );
	OleDbCommandBuilder cb   = new OleDbCommandBuilder( da );

	// this is important, since the database contains reserved SQL keywords (Date and Text).
	cb.QuotePrefix = "[";
	cb.QuoteSuffix = "]";

	DataSet ds = new DataSet();
	da.Fill( ds );

	DataTable table = ds.Tables[0];

	DataRow row = table.NewRow();
	row["Date"]  = DateTime.Now;
	row["Name"]  = name;
	row["EMail"] = email;
	row["Text"]  = text;
	table.Rows.Add( row );

	da.Update( ds );

	conn.Close();
}

// delete an entry from the guestbook.
void DeleteEntry()
{
	// check parameters.
	if ( Request["id"]==null )
		throw new Exception( "ID to delete no specified" );
	
	// read parameters.
	int id = Convert.ToInt32(Request["id"]);

	// actually delete the entry.
	ExecuteNonQuery( "DELETE FROM Guestbook WHERE [No]=" + id );
}

// check, whether a mode is currently active.
bool HasMode( int mode_chk )
{
	return (Mode & mode_chk)!=0;
}

// #################################################################
// helper routines for the database.

// single-line-shortcut for executing a query that returns NO results.
void ExecuteNonQuery( string sql )
{
	OleDbConnection	conn = new OleDbConnection( DB_STR );
	conn.Open();
	OleDbCommand    cmd  = new OleDbCommand( sql, conn );
	cmd.ExecuteNonQuery();

	conn.Close();
}

// opens the recordset with the query.
DataTable Execute( string sql )
{
	OleDbConnection	 conn = new OleDbConnection( DB_STR );
	OleDbCommand     cmd  = new OleDbCommand( sql, conn );

	OleDbDataAdapter da   = new OleDbDataAdapter();
	da.SelectCommand = cmd;

	DataSet ds = new DataSet();
	da.Fill( ds );

	conn.Close();

	return ds.Tables[0];
}

// #################################################################

</script>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Uwe Keim
Chief Technology Officer Zeta Producer Desktop CMS
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

In his free time, he does climbing, running and mountain biking. Recently he became a father of a cute boy.

Some cool, free software from us:

German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans. Download now!  
Homepage erstellen - Intuitive, very easy to use. Download now!  
Send large Files online for free by Email
Offline-Homepage-Baukasten
Follow on   Twitter   Google+   LinkedIn

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150414.1 | Last Updated 27 Jan 2002
Article Copyright 2002 by Uwe Keim
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid