Discussion Forum Board - Beta 1
Add Comment| Download File | SDK |
| forum1.zip (29kb) | Beta1 |
Introduction
I had received a few requests for
building an ASP.NET Forum. So I decided to build a ASP.NET forum
board which has support of HTML message posting. This is a beta
release of the forum and has very few features (more shall come when I have time
:) ). Mahesh Chand (of C# Corner) has helped me out with the database design. This
example use C# scripting with ADO.NET to build a ASP.NET Web
Application. You will get to learn a lot of ADO.NET in this example.
Explanation
This example consists of 3 pages.
1) forum.aspx - The Main Forum page. It lists all the topics in a
DataGrid object with Paging enabled. It also contains a form to post new
entries.
2) reply.aspx - This page is called from the forum page when you
click on any topic. It contains the details of the topic as well as
all replies made to the topic. This page contains the form to reply
to the topic.
3) postmessage.aspx - This page is called whenever a form is posted.
It stores the posted data into the Database.
Requirements
1) .NET SDK beta 1 (Note: This example may not work with future
versions of the SDK).
2) Ms Access 2000 (Optional, only if you want to edit the database).
3) ASP.NET support on your web server.
Database Structure
| Table Name - newpost / This table will contain the new topics posted. | ||
| Column Name | Data Type | Description |
| postid | Integer | The primary key field. The unique id for each new topic. |
| name | Text | The name of the author of the message. |
| Text | E-mail address of the author. | |
| subject | Text | Subject of the message. |
| ip | Text | IP address of the author. |
| date | Text | Date / Time of the Post |
| message | Memo | Message posted. |
| replies | Integer | Number of replies to the post (if any) |
| views | Integer | Number of times the message has been viewed. |
| Table Name- reply / This table will contain the replies made to the new topics. | ||
| Column Name | Data Type | Description |
| replyid | Integer | The primary key field. The unique id for each reply. |
| name | Text | Name of the author. |
| Text | E-mail address of the author. | |
| subject | Text | Subject of the post |
| ip | Text | IP of the author. |
| date | Text | Date / Time of post. |
| message | Memo | Message posted. |
| postid | Integer | postid from the "newpost" table for which this message is a reply. |
Code
1) forum.aspx :- The main
forum
page.
<%@ Page Language="C#" Debug="true" %> <%@ Assembly Name="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System" %> <html><head> <title>Welcome to My Forum!</title> <script language="C#" runat="server" > //execute this script when the page loads void Page_Load(Object Src, EventArgs E) { //Call the Method to DataBind the DataGrid Binding() ; } //This Method Connects to the Database, and DataBinds the Database //to the DataGrid public void Binding() { //String to connect to the database, //If your Database is in some other directory then change the path //To the Database below string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ; Data Source="+Server.MapPath(".\\db\\board.mdb") ; //Make a Connection to the Database ADOConnection myConn = new ADOConnection(strConn) ; //String to select records from the Database. //I have used "ORDER BY postid DESC" since I want to show the //latest post on the top. If you remove this clause then //the oldest message will be shown first string strCom = "SELECT postid ,subject ,name ,replies ,views "; strCom += ",date FROM newpost ORDER BY postid DESC" ; //Open the Connection, Always remember to Open the connection //before doing anything else myConn.Open(); DataSet myDataSet = new DataSet(); //Create a ADODataSetCommand and a DataSet ADODataSetCommand myCommand =new ADODataSetCommand(strCom,myConn); //Fill the DataSet myCommand.FillDataSet(myDataSet,"newpost") ; //Connection is closed myConn.Close(); //Set the DataView of the Table "newpost" contained in the //DataSet for the DataGrid DataGrid1.DataSource = myDataSet.Tables["newpost"].DefaultView ; //DataBind the DataGrid DataGrid1.DataBind(); } //This method is called when the DataGrid is Paged //(i.e. when you change from Page 1 to Page 2 etc.. ) public void DataGrid_Updt(Object sender, DataGridPageChangedEventArgs e) { //Call the Method to Databind Binding(); } //This Method is called when the form is submitted to make a new Post public void Submit_Click(Object sender, EventArgs e) { //proceed only if all the required fields are filled-in if(Page.IsValid&&name.Text!=""&&subject.Text!=""&&email.Text!=""){ //Get the Current Date and Time DateTime now = DateTime.Now ; errmess.Text="" ; //building a custom query, used to call postmessage.aspx //Encode the query into UTF8 format. //Get all the fields from the form and encode them string req="name="+System.Web.HttpUtility.UrlEncodeToString(name.Text, System.Text.Encoding.UTF8); req+="&&email="+System.Web.HttpUtility.UrlEncodeToString(email.Text, System.Text.Encoding.UTF8); req+="&&subject="+System.Web.HttpUtility.UrlEncodeToString(subject.Text, System.Text.Encoding.UTF8); //Get the HostAddress of the Author req+="&&ip="+System.Web.HttpUtility.UrlEncodeToString( Request.UserHostAddress.ToString(),System.Text.Encoding.UTF8); req+="&&date="+System.Web.HttpUtility.UrlEncodeToString(now.ToString(), System.Text.Encoding.UTF8); req+="&&message="+System.Web.HttpUtility.UrlEncodeToString(message.Text, System.Text.Encoding.UTF8); //A 'yes' is used below to tell the postmessage page //that this is a new topic post req+="&&newpost="+System.Web.HttpUtility.UrlEncodeToString("yes", System.Text.Encoding.UTF8); //call the postmessage.aspx page and append the query to it. Page.Navigate("postmessage.aspx?" + req); } else { errmess.Text="Fill in all the Required Fields before Posting!"; } } </script> <LINK href="mystyle.css" type=text/css rel=stylesheet></head> <body topmargin="0" leftmargin="0" rightmargin="0"> <!-- #Include File="header.inc" --> <center> <asp:label id="errmess" text="" style="COLOR:#ff0000" runat="server" /> <asp:Label class=fodark text="<font color=#00000 > Welcome to My Discussion Forum</font>" runat=server /> <br> <br> <form method="post" runat="server" ID=Form1> <%-- The DataGrid settings. Its very interesting how much you can play with it --%> <asp:DataGrid id=DataGrid1 runat="server" ForeColor="Black" PagerStyle-Mode="NumericPages" OnPageIndexChanged="DataGrid_Updt" PageSize="20" AllowPaging="True" width="80%" autogeneratecolumns="False"> <property name="PagerStyle"> <asp:DataGridPagerStyle BackColor="Coral" Mode="NumericPages"> </asp:DataGridPagerStyle> </property> <property name="AlternatingItemStyle"> <asp:TableItemStyle BorderColor="#FFC080" BackColor="#FF9966"> </asp:TableItemStyle> </property> <property name="FooterStyle"> <asp:TableItemStyle ForeColor="White" BackColor="DarkOrange"> </asp:TableItemStyle> </property> <property name="ItemStyle"> <asp:TableItemStyle BackColor="Moccasin"> </asp:TableItemStyle> </property> <property name="HeaderStyle"> <asp:TableItemStyle Font-Bold="True" ForeColor="White" BackColor="Coral"> </asp:TableItemStyle> </property> <%-- I am setting up the Individual columns using Templates --%> <property name="Columns"> <%-- Manipulate the subject entry so that it contains a link to the reply page --%> <asp:TemplateColumn HeaderText="Subject" itemstyle-width=50%> <template name="ItemTemplate" > <asp:Label runat="server" Text='<%#"<a href=reply.aspx?postid=" +DataBinder.Eval(Container, "DataItem.postid")+">" +DataBinder.Eval(Container, "DataItem.subject")+"</a>" %>' ID=Label2> </asp:Label> </template> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="Author Name" itemstyle-width=20%> <template name="ItemTemplate"> <asp:Label runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.name") %>' ID=Label3> </asp:Label> </template> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="Replies" itemstyle-width=10%> <template name="ItemTemplate"> <asp:Label runat="server" width=10% Text='<%# DataBinder.Eval(Container, "DataItem.replies") %>' ID=Label4> </asp:Label> </template> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="Views" itemstyle-width=10%> <template name="ItemTemplate"> <asp:Label runat="server" width=10% Text='<%# DataBinder.Eval(Container, "DataItem.views") %>' ID=Label5> </asp:Label> </template> </asp:TemplateColumn> <asp:TemplateColumn HeaderText="Date of Post" itemstyle-width=10%> <template name="ItemTemplate"> <asp:Label runat="server" width=10% Text=' <%# DataBinder.Eval(Container, "DataItem.date").ToString(). ToDateTime().ToShortDateString()%>' ID=Label6></asp:Label> </template> </asp:TemplateColumn> </property> </asp:DataGrid> <br> <br> <asp:Label class=fodark text="<font color=#00000 >Post New Topic</font>" runat=server /> <br> <table border="0" width="80%" align="center"> <tr > <td class="fohead" colspan=2><b>Post New Topic</b></td> </tr> <tr class="folight" > <td>Name :</td> <td ><asp:textbox text="" id="name" runat="server" /> <font color=#ff0000>*</font></td> </tr> <tr class="folight"> <td>E-Mail :</td> <td><asp:textbox text="" id="email" runat="server"/> <font color=#ff0000>*</font></td> </tr> <tr class="folight"> <td> Subject:</td> <td><asp:textbox test="" id="subject" width=200 runat="server"/> <font color=#ff0000>*</font> </td></tr> <tr class="folight"> <td>Message :</td> <td> <asp:TextBox id=message runat="server" Columns="30" Rows="15" TextMode="MultiLine"></asp:TextBox></td> </tr> <tr class=folight> <td colspan=2> <asp:Button class=fodark id=write onClick=Submit_Click runat="server" Text="Submit"> </asp:Button></td></tr> </table> </form> </center> <!-- #Include File="footer.inc" --> </body></html> |
2) reply.aspx : The topic viewing and replying page.
<%@ Page Language="C#" EnableSessionState="False" Debug="True" %> <%@ Import Namespace="System" %> <%@ Assembly Name="System.Data" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <html><head> <title>Post New Topic.</title> <%-- These are the imported assemblies and namespaces needed --%> <script Language="C#" runat="server"> DataSet ds ,rs; DataRow dr ; string postid ; public void Page_Load(object sender , EventArgs e) { //Check if the page is Post Back if(!Page.IsPostBack) { //Get the postid from the Query string postid = Request.Params["postid"] ; if(postid!=null) { //Database connection string. Change the path to //the database file if you have some other path where //you are saving your Database file string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ; Data Source="+Server.MapPath(".\\db\\board.mdb") ; //Make a connection to the Database ADOConnection myConn = new ADOConnection(strConn) ; //string to select the records from the newpost table string strCon ="SELECT subject, name, email, message ,date "; strCon+="FROM newpost WHERE postid="+postid ; //set a ADODataSetCommand ADODataSetCommand myCommand =new ADODataSetCommand(strCon,myConn); ds = new DataSet(); //Don't ever forget to open the Connection myConn.Open(); //Fill the DataSet myCommand.FillDataSet(ds,"newpost") ; //Get the Row at position '0' and store it in a DataRow object //Why row at position '0'? //Since there can only be one record with the given postid remember! //Why put into a DataRow ? Its easy to access data from a DataRow dr = ds.Tables["newpost"].Rows[0] ; //Get the "subject" from the DataRow and set it up in the post //reply form's subject field subject.Text="Re:"+dr["subject"].ToString() ; //Select the replies to the post from the reply table strCon ="SELECT name , email, subject, message ,date"; strCon+= "FROM reply WHERE postid="+postid ; //Make a new ADODataSetCommand and DataSet for the reply table ADODataSetCommand myCommand2 =new ADODataSetCommand(strCon,myConn); rs = new DataSet() ; //fill the DataSet myCommand2.FillDataSet(rs, "reply") ; //Code to update the "views" field for the newpost Table //Select the views field from the table for a given postid strCon ="SELECT views FROM newpost WHERE postid = "+postid ; //Make a ADOCommand here since we want a ADODataReader later ADOCommand vicomm = new ADOCommand(strCon, myConn) ; ADODataReader reader ; //execute the statement and create a ADODataReader vicomm.Execute(out reader) ; //Read the First record (there can only be one record remember ) reader.Read() ; //Get a "Int32" value from the first Column (we have one column //in the reader, check the select statement above) int i = reader.GetInt32(0) ; //Increase the views count i++ ; reader.Close() ; //Update the newpost table with the new views value strCon ="UPDATE newpost SET views = "+i+" WHERE (postid= "+postid+")" ; //since we are using the same ADOCOmmand object //for this statement too to set the CommandText property vicomm.CommandText = strCon ; //Since this statement will result in no resultset //use "ExecuteNonQuery()" vicomm.ExecuteNonQuery() ; //close the connection myConn.Close(); } } } // This method is called when the submit button is clicked public void Submit_Click(Object sender, EventArgs e) { //Get the postid postid = Request.Params["postid"] ; //proceed only if all the required fields are filled-in if(Page.IsValid&&name.Text!=""&&subject.Text!=""&&email.Text!="") {DateTime now = DateTime.Now ; errmess.Text="" ; //We have to call the postmessage.aspx page with a //query to post the data to the Database. //Hence we have to first build the custom query from the Data //posted by the user also since we are using a query we have to //encode the data into UTF8 format string req = "name="+ System.Web.HttpUtility.UrlEncodeToString(name.Text, System.Text.Encoding.UTF8); req+="&&email="+ System.Web.HttpUtility.UrlEncodeToString(email.Text, System.Text.Encoding.UTF8); req+="&&subject="+System.Web.HttpUtility.UrlEncodeToString(subject.Text, System.Text.Encoding.UTF8); req+="&&ip="+System.Web.HttpUtility.UrlEncodeToString( Request.UserHostAddress.ToString(),System.Text.Encoding.UTF8); req+="&&date="+ System.Web.HttpUtility.UrlEncodeToString(now.ToString(), System.Text.Encoding.UTF8); req+="&&message="+ System.Web.HttpUtility.UrlEncodeToString(message.Text, System.Text.Encoding.UTF8); //Encode "no" to indicate that the post is not a new //post but its a reply to a earlier message req+="&&newpost="+ System.Web.HttpUtility.UrlEncodeToString("no", System.Text.Encoding.UTF8); req+="&&previd="+ System.Web.HttpUtility.UrlEncodeToString(postid, System.Text.Encoding.UTF8); //Call the postmessage page with our custom query Page.Navigate("postmessage.aspx?" + req); } else { errmess.Text="Fill in all the Required Fields !" ; } } </script> <LINK href="mystyle.css" type=text/css rel=stylesheet></head> <body topmargin="0" leftmargin="0" rightmargin="0"> <%-- Include a header file 'header.inc' --%> <!-- #Include File="header.inc" --> <br> <div align=center> <table border=0 width=80% cellspacing=2> <tr class=fohead><th width=20%>Author Name</th> <th width=80%>Message</th></tr> <%-- Below I am encapsulating the email of the author over the name of the author so that when you click on the author a e-mail gets sent to him Also I am getting the DateTime from the DataBase and Displaying the Date and Time separately --%> <tr class=folight><td rowspan=2 align="center"> <%= "<a href=mailto:"+dr["email"]+">"+dr["name"]+"</a>" %><br> <font size=1> <%= dr["date"].ToString().ToDateTime().ToShortDateString() %> <br> <%= dr["date"].ToString().ToDateTime().ToShortTimeString() %> </font> </td> <td><b>Subject: </b><%=dr["subject"] %></td></tr> <tr class=folight> <td><pre><%=dr["message"] %></pre> </td> </tr> <%-- Get all the replies to the Original post and show them --%> <% int no = rs.Tables["reply"].Rows.Count ; if(no>0) { for(int j=0 ;j<no ; j++) { DataRow rd = rs.Tables["reply"].Rows[j] ; %> <tr class=fodark> <td align="center"> <%="<a href=mailto:"+rd["email"]+">"+rd["name"]+"</a>" %><br> <font size=1> <%= rd["date"].ToString().ToDateTime().ToShortDateString() %><br> <%= rd["date"].ToString().ToDateTime().ToShortTimeString() %></font> </td> <td><pre><%=rd["message"] %></pre> </td> </tr> <% } } %> </table> </div> <h3 align="center" class="fodark"><a href=forum.aspx>Click Here</a> to go to back to Forum. <br>Reply to the Above Post.</h3> <br> <asp:label id="errmess" text="" style="COLOR:#ff0000" runat="server" /> <form runat="server"> <table border="0" width="80%" align="center"> <tr > <td class="fohead" colspan=2><b>Reply to the Post</b></td> </tr> <tr class="folight" > <td>Name :</td> <td ><asp:textbox text="" id="name" runat="server" /> <font color=#ff0000>*</font></td> </tr> <tr class="folight"> <td>E-Mail :</td> <td><asp:textbox text="" id="email" runat="server"/> <font color=#ff0000>*</font></td> </tr> <tr class="folight"> <td> Subject:</td> <td><asp:textbox test="" id="subject" width=200 runat="server"/> <font color=#ff0000>*</font> </td></tr> <tr class="folight"> <td>Message :</td> <td> <asp:TextBox id=message runat="server" Columns="30" Rows="15" TextMode="MultiLine"></asp:TextBox></td> </tr> <tr class=folight> <td colspan=2> <asp:Button class=fodark id=write onClick=Submit_Click runat="server" Text="Submit"></asp:Button></td></tr> </table> </form><br> <br><!-- #Include File="footer.inc" --> </body></html> |
3) postmessage.aspx : The page to save the posted data to the database.
<%@ Import Namespace="System" %> <%@ Assembly Name="System.Data" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.ADO" %> <%@ Page Language="C#" Debug="true" %> <html> <head> <title>Thank You for Posting !</title> <script language="C#" runat="server" > //execute this script when the page loads void Page_Load(Object Src, EventArgs E) { //if the page is called from another page if (!Page.IsPostBack) { //Get all the Parameters from the Query string string name = Request.Params["name"] ; string email = Request.Params["email"] ; string subject = Request.Params["subject"] ; string ip = Request.Params["ip"] ; string date = Request.Params["date" ]; string message = Request.Params["message"] ; bool newmess =true ; string previd ="1"; //Check if the post is a New topic or a reply to a new topic if(Request.Params["newpost"].Equals("no")) { //if its a reply then get the postid called as previd here newmess =false ; previd = Request.Params["previd"] ; } //If the post is a new topic then follow the below routine if(newmess) { //The string for the path to the database , if your //database is in some other directory then edit the path //of this variable string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ; Data Source="+Server.MapPath(".\\db\\board.mdb") ; //Get a ADOConnection to the database ADOConnection myConn = new ADOConnection(strConn) ; //The SQL Select statement string strCom = "Select postid from newpost" ; //Create a ADOCommand since we want a ADODataReader later ADOCommand myCommand =new ADOCommand(strCom,myConn); //Open the connection myConn.Open(); ADODataReader reader; //Execute the command and get the Data into "reader" myCommand.Execute(out reader) ; int i=1 ; //Get the current number of records present in the database. while(reader.Read()) { i++ ; } reader.Close() ; //build the SQL statement to insert into the Database string insertStr =" INSERT INTO newpost VALUES (" +i +", '" +name+"', '" +email+"', '" +subject+"', '" +ip+"', '" +date+"', '" +message+"',0, 0)" ; myCommand.CommandText =insertStr ; //Since the SQL statement does not return any //output use "ExecuteNonQuery() method myCommand.ExecuteNonQuery() ; //Close the connection myConn.Close() ; } else { //If the posted data is a reply to a topic then follow //the below procedure string for the path to the database, //if your database is stored in some other directory then //edit the path here string strConn=@"Provider=Microsoft.Jet.OLEDB.4.0 ; Data Source="+Server.MapPath(".\\db\\board.mdb") ; ADOConnection myConn = new ADOConnection(strConn) ; //SQL statement to select the replyid string strCom = "Select replyid from reply" ; //create a ADOCommand ADOCommand myCommand =new ADOCommand(strCom,myConn); //Open the Connection myConn.Open(); ADODataReader reader; //Execute the command and get the Data into "reader" myCommand.Execute(out reader) ; int i=1 ; //Get the current number of records present in the database. while(reader.Read()) { i++ ; } reader.Close() ; //Build a statement to insert the values into the reply table string insertStr =" INSERT INTO reply VALUES (" +i +", '" +name+"', '" +email+"', '" +subject+"', '" +ip+"', '" +date+"', '" +message+"', " +previd+")"; myCommand.CommandText =insertStr ; //ExecuteNonQuery - since the command does not return anything myCommand.ExecuteNonQuery() ; //string to get the replies column from the newpost table string replyno = "SELECT replies FROM newpost WHERE postid =" +previd ; myCommand.CommandText =replyno ; //Execute command and get the reader myCommand.Execute(out reader) ; //read the first record (remember there can only be one record //in the reader since postid is unique) reader.Read(); //Get the "Int16" value of the number of replies from the replies //column in the newpost table int rep =reader.GetInt16(0) ; reader.Close() ; rep++ ; //SQL statement to update the replies field in the newpost table string updtStr ="UPDATE newpost SET replies = "+rep +" WHERE (postid = "+previd+")" ; myCommand.CommandText = updtStr; //ExecuteNonQuerry why ?? I guess U should know by now ! myCommand.ExecuteNonQuery(); myConn.Close() ; } //get the different Parameters from the query string and store it //to respective Labels NameLabel.Text = name; EmailLabel.Text= email ; SubjectLabel.Text=subject; MessageLabel.Text=message ; } else { //else display an error errmess.Text="This Page Cannot be called directly. It has to be called from the Form posting page.<br>" ; } } </script> <LINK href="mystyle.css" type=text/css rel=stylesheet> </head> <body topmargin="0" leftmargin="0" rightmargin="0"> <!-- #Include File="header.inc" --> <center> <asp:label id="errmess" text="" style="color:#FF0000" runat="server" /> <h2 class="fodark"><b>Thank You , for posting on the Message Board. </b></h2> <table align=center width=60% border=0 cellspacing=2 cellpadding=1 > <tr class="fohead"><td colspan="2">The information You Posted!</td></tr> <tr class="folight"> <td>Name :</td> <td><asp:label id="NameLabel" text="" runat="server" /></td> </tr> <tr class="folight"> <td>E-Mail :</td> <td><asp:label id="EmailLabel" text="" runat="server" /></td> </tr> <tr class="folight"> <td>Subject :</td> <td><asp:label id="SubjectLabel" text="" runat="server" /></td> </tr> <tr class="folight"> <td>Message :</td> <td><asp:label id="MessageLabel" text="" runat="server" /></td> </tr> </table> <br> <h4 class="fodark"><a href="forum.aspx">Click here </a> to go back to the Forum.<br> <%-- A little work to show the link to return back to the page if, the post was a reply --%> <% if(Request.Params["previd"]!=null) { %> <a href='reply.aspx?postid=<%=Request.Params["previd"] %>'> Click here </a>to go back where you came from. <% } %> </h4> </center> <!-- #Include File="footer.inc" --> </body> </html> |

