Build Community with a Discussion Forum: Part I

Getting Started

Bipin Joshi

October 30, 2009

12 Min Read
ITPro Today logo

CodeTalk

LANGUAGES: C#

ASP.NETVERSIONS: 3.5

 

Build Community with a Discussion Forum: Part I

Getting Started

 

By Bipin Joshi

 

Community. This simple word has received serious attentionfrom most leading software companies and even from non-software companies. Indeed,the importance of building a community around one s products and services hasbecome a popular trend these days. To that end, discussion forum software playsa vital role in building such a community.

 

There are several discussion forum applications (free andcommercial) that can help you with your own, customized communities. Most ofthem are loaded with dozens of features. However, there is a downside to this;many of these applications are bulky. They require too many resources in termsof database tables, graphics, and other system requirements. At times, you needsomething that is lightweight, yet meets your requirements especially whenyour community consists of a small group of people and you don t need too many richfeatures. It simply makes sense to quickly roll out something on your own; thisseries of articles will show you how.

 

Functional Requirements

Let s first jot down the functional requirements ourdiscussion forum application should meet:

  • The application should allow you to createmultiple discussion forums (each for a specific purpose).

  • Users should be able to start a new thread ofdiscussion by posting a new question, or contribute to an existing thread byreplying to a question.

  • The discussion forums must be accessible only toauthenticated users (to avoid any SPAM and marketing messages).

  • A post made by a user must be moderated beforeit appears on the forum.

  • For better user experience, the applicationshould be AJAX-enabled.

  • To make the application lightweight, it shoulduse as few resources as possible (resources here include database tables, Webforms, components, etc.).

 

Software Requirements

We ll use ASP.NET 3.5 to build our discussion forum. Thedatabase used for storing application data is SQL Server 2005. We ll also use theAJAX Control Toolkit in some places. And although we ll use SQL Data Sourcewhile developing this application, you also can use Object Data Source. Ofcourse, you must develop additional classes if you opt for Object Data Source.For designing and developing the Web forms, we ll use Visual Studio 2008(Visual Web Developer Express Edition is fine, too).

 

Database Tables

One requirement for our discussion forum is that it shoulduse minimum resources, such as database tables. Keeping this requirement inmind, we ll create only two tables in the database. The first table, namedForumCategories, stores information about different forums available; the second,named ForumThreads, stores forum posts and replies.

 

We first need to create a new database in SQL Server 2005.To do so, open SQL Server Management Studio and create a new database namedForumDb. Figure 1 shows the New Database dialog box of SQL Server ManagementStudio.

 


Figure 1: Create a new databaseusing SQL Server Management Studio.

 

Once the ForumDb database is created, add two tables (ForumCategoriesand ForumThreads, as shown in Figure 2). The download accompanying this articlecontains the database (.mdf) files, which you can attach directly in your SQLServer (see end of article for download details).

 


Figure 2: The ForumCategories andForumThreads tables.

 

As you can see from Figure 2, both tables contain anidentity column that acts as a primary key. The ForumCategories table stores CategoryID,Name, and Description of one or more forums. The ForumThreads table storesdetails of posts in terms of Title, Description, PostedBy, and PostedOncolumns. One peculiar feature of our discussion forum is that it stores posts andtheir replies in the same table. The ParentId column plays an important role inour application. For all the posts (i.e., the original question), the ParentIdwill be 0; for all the replies to that post, the ParentId will be the Id of thepost. For example, if we have a post with Id as 100, that record will have Idas 100 and ParentId as 0. All the replies to that post will have ParentId as100. This way, we easily can track one particular thread. We then can sort themessages belonging to a single thread as per their posted date and time toarrive at a particular discussion. The IsApproved bit column decides whethera message will be displayed in the forum or not. By default, IsApprovedcontains a value of 0, indicating that the message is not yet approved.

 

Configuring the Database for Application Services

Our discussion forum is authenticated; only authenticatedusers can read or post messages. We ll use the Forms-based authentication ofASP.NET, along with membership and roles services. Before we use membership androles services, however, we need to configure the ForumDb database to supportthese features. You enable these features using the aspnet_regsql.exe tool.Running this tool from Visual Studio s Command Prompt starts a wizard thatguides you through the configuration process. After successfully completing thewizard, you should see the tables shown in Figure 3 (those starting withaspnet_) in the ForumDb database.

 


Figure 3: Tables created by the aspnet_regsql.exetool.

 

Creating the Web Site

Now that we created and configured the ForumDb database,let s create a new Web site. Begin by creating a new ASP.NET Web Site in VisualStudio (see Figure 4).

 


Figure 4: Create a new Web site.

 

Make sure to choose Visual C# as your programminglanguage. Once the Web site is created, add a new master page to it. This masterpage will be used with all the other Web forms, and simply contains a graphicallogo and copyright notice. Drag and drop a ScriptManager control on the masterpage. Because many of our Web forms use AJAXfunctionality, it makes sense to add a ScriptManager control in the master page(rather than individual Web forms). Figure 5 shows the master page in designmode.

 


Figure 5: The master page in designmode.

 

Configuring Membership and Roles Providers

Now that we have a master page, let s configure the authenticationscheme for our site, along with membership and roles providers. Open theweb.config file (if it doesn t exist already, add one to your Web site) and addto it the markup shown in Figure 6.

 

 

 

Figure 6:Configuring authentication scheme.

 

The tag configures the Web site touse Forms authentication. It also configures the log-in page to be Login.aspx(we ll create Login.aspx later). The section deniesaccess to the anonymous users. This ensures that only authenticated users canaccess Web forms.

 

The membership and roles providers are configured suchthat they store user and role information in the ForumDb database. This callsfor adding a connection string in the section.

 

Figure 7: Storing adatabase connection string in the configuration file.

 

The membership and roles providers are then configuredusing and sections, respectively (Figure8).

 

 

       type="System.Web.Security.SqlMembershipProvider"/>            type="System.Web.Security.SqlRoleProvider"/> Figure 8:Configuring membership and roles providers.   The membership provider uses the built-inSqlMembershipProvider class to manage membership information, whereas the rolesprovider uses the built-in SqlRoleProvider class to manage application-specificroles. Note that the enabled attribute of the tag must beset to true in order to use roles-based security.  Creating a Log-in and Registration Page We need to create a Web form wherein new users canregister and existing users can log in. To develop this Web page, add a new Webform to the Web site and name it Login.aspx. Make sure to attach the masterpage we created earlier (see Figure 9).  
Figure 9: Attaching a master page toLogin.aspx.   Then drag and drop two UpdatePanel controls and twoUpdateProgress controls to the Web form. The UpdatePanel controls enablepartial page rendering to the Web forms so that, instead of causing full pagepost backs, only a small region will be updated. The first UpdatePanel containsa Login control, the second UpdatePanel control contains a CreateUserWizardcontrol. The UpdateProgress controls display a progress indicator for theUpdatePanel controls. The UpdateProgress controls are attached with theUpdatePanel controls using the AssociatedUpdatePanelID property. Figure 10shows the Login.aspx in design mode.  
Figure 10: Login.aspx in design mode.   Run the Login.aspx Web form we just created and registerat least two users. Notice that the UpdatePanel controls provide partial pagerendering. Also, observe the progress indicator message appearing in theUpdateProgress controls. Figure 11 shows a sample run of the Web form whiletrying to log in.  
Figure 11: The UpdatePanel causing partialpage rendering.  Creating Application-specific Roles The forum has two types of users: those who can read andpost messages and those who can moderate the messages. Because moderators alsocan read and post messages, defining a single role is sufficient. To createthis role, invoke the Web Site Administration Tool from the Website | ASP.NETConfiguration menu option. Then, using the Security tab, create a role namedModerator. Figure 12 shows this tool with the Moderator role defined.  
Figure 12: Creating roles using the WebSite Administration Tool.   Once you create the Moderator role, you need to assignthis role to one or more users. This can be done using the manage users optionfrom the Security tab. Figure 13 shows the relevant page.  
Figure 13: Assigning roles to a user.  Creating a Helper Web Service We used UpdatePanel and UpdateProgress controls to AJAX-enablethe Web form in Login.aspx. ASP.NET AJAX also lets you consume Web servicesfrom the client-side script. This feature can be of great help to increase the richnessof your application. We ll use this feature in our forum application at someplaces, so we need to create a Web service that can be called from the client-sidescript.   Begin by adding to the Web site a new Web service (WebService.asmx).Once the Web service is added, modify the Web service class definition shown inFigure 14.  ...using System.Web.Script.Services; ... [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class WebService : System.Web.Services.WebService{...}Figure 14:Creating a script-callable Web service. Take note of a couple of things in the code shown inFigure 14. The Web service class (WebService) is decorated with the[ScriptService] attribute. A Web service marked with the [ScriptService]attribute can be called from the client-side script. The [ScriptService]attribute resides in the System.Web.Script.Services namespace. We need four Webmethods in our Web service (see Figure 15).   Web Method Description GetForumDetails Returns a string containing forum description and total number of posts. GetForumDetailsForModerator Returns a string containing forum description, total number of posts, and details of the latest post made. ApprovePost Approves a post; i.e., set the IsApproved column value of the ForumThreads table to 1. RejectPost Deletes a post from the ForumThreads table. Figure 15: Webmethods that will be called from client-side script.   Let s now examine these Web methods one by one. Figure 16shows the GetForumDetails Web method.   [WebMethod] public string GetForumDetails(int contextKey) { stringstrConn=ConfigurationManager.ConnectionStrings["connstr"].  ConnectionString;  SqlConnection cnn = newSqlConnection(strConn);  cnn.Open(); SqlCommand cmd = newSqlCommand("select description from ForumCategorieswhere CategoryId=@id", cnn);  cmd.Parameters.AddWithValue("@id", contextKey);  object obj =cmd.ExecuteScalar(); cmd.CommandText ="select count(*) from ForumThreads where categoryid=@id andIsApproved=1";  object postCount =cmd.ExecuteScalar(); cmd.CommandText ="select count(*) from ForumThreads where categoryid=@id andParentId=0 and IsApproved=1";  object threadCount =cmd.ExecuteScalar(); cnn.Close(); return obj.ToString() +"
" + "Total " + postCount.ToString() +" posts in " + threadCount.ToString() +" threads!"; }Figure 16: Gettingforum details for users.   The GetForumDetails Web method accepts an integer-representingforum category ID and returns a string containing the information about theforum. Note that the signature of this Web method must match, as shown inFigure 16, because later we ll use this Web method with the PopupControlExtendercontrol of the AJAX Control Toolkit. Inside, we simply fetch a description ofthe forum, total posts, and threads active on the forum. These details are tobe displayed in a client-side popup, so we ll format the string as HTML markup.Notice the use of the ConfigurationManager class to retrieve the databaseconnection string from the web.config file. Figure 17 shows the GetForumDetailsForModeratorWeb method.   [WebMethod] public string GetForumDetailsForModerator(int contextKey) { string strConn =ConfigurationManager.ConnectionStrings["connstr"].  ConnectionString;  SqlConnection cnn = newSqlConnection(strConn);  string retVal ="";  cnn.Open(); SqlCommand cmd = newSqlCommand("select description from ForumCategorieswhere CategoryId=@id", cnn);  cmd.Parameters.AddWithValue("@id",contextKey);  object obj =cmd.ExecuteScalar(); retVal = obj.ToString() +"
";  cmd.CommandText ="select count(*) from ForumThreads where categoryid=@id andIsApproved=1";  object postCount =cmd.ExecuteScalar(); cmd.CommandText ="select count(*) from ForumThreads where categoryid=@id andParentId=0 and IsApproved=1";  object threadCount =cmd.ExecuteScalar(); retVal += "Total" + postCount.ToString() + " posts in "  + threadCount.ToString()+ " threads!" + "
";  cmd.CommandText ="select top 1 title,postedby,postedon from ForumThreads wherecategoryid=@id and ParentId=0 and IsApproved=1 order bypostedon desc";  SqlDataReader reader =cmd.ExecuteReader(); if (reader.HasRows)  {    reader.Read();   retVal += "LatestPost : " + reader.GetString(0)    + "
"+ " by " + reader.GetString(1) + " on "    +reader.GetDateTime(2).ToString(); }  reader.Close(); cnn.Close(); return retVal; }Figure 17: Gettingforum details for moderators.   The GetForumDetailsForModerator Web method is similar toGetForumDetails, but it returns some additional information. In addition to a descriptionof the forum, total posts, and threads, it returns the title of the latest post,along with user information and post date. This method is intended to be calledfrom administrative pages, which will be accessed only by the moderators.   Later, when we develop a Web form for moderating the posts,we ll allow the moderator to approve or reject individual messages. TheApprovePost and RejectPost Web methods do this, respectively. These Web methodsare shown in Figure 18.   [WebMethod] public void ApprovePost(int postId) {string strConn =ConfigurationManager.ConnectionStrings["connstr"] .ConnectionString; SqlConnection cnn = new SqlConnection(strConn); cnn.Open();SqlCommand cmd = new SqlCommand("update ForumThreads setIsApproved=1 where Id=@id", cnn); cmd.Parameters.AddWithValue("@Id", postId); cmd.ExecuteNonQuery();cnn.Close();} [WebMethod] public void RejectPost(int postId) {string strConn =ConfigurationManager.ConnectionStrings["connstr"] .ConnectionString; SqlConnection cnn = new SqlConnection(strConn); cnn.Open();SqlCommand cmd = new SqlCommand("delete from ForumThreadswhere Id=@id", cnn); cmd.Parameters.AddWithValue("@Id", postId); cmd.ExecuteNonQuery();cnn.Close();}Figure 18:Approving and rejecting posts.   The ApprovePost Web method accepts the ID of the post tobe approved. Inside, it simply sets to 1 the IsApproved column of that post.All the requests to retrieve posts for displaying on the forum will have aWHERE clause that filters only the posts, with the IsApproved column valueequal to 1. The RejectPost Web method accepts a post ID to be rejected andsimply deletes that post from the ForumThreads table.   This completes our Web service. We are now ready todevelop several Web forms for displaying and moderating posts. We ll continueour development in PartII.  Conclusion A discussion forum is a very common way to build communityaround your products and services. In this series of articles we ll develop anAJAX-enabled discussion forum that is lightweight, yet meets our requirements.In this first part we created a database with two tables. We also configuredour Web site for ASP.NET application services. We then created a log-in pagethat makes use of UpdatePanel and UpdateProgress controls. Finally, we createda Web service that will be called from client-side script to enhance the userexperience.   The source codeaccompanying this article is available for download.  Bipin Joshi is theproprietor of BinaryIntellect Consulting (http://www.binaryintellect.com)where he conducts premier training programs on a variety of .NET technologies.He wears many hats, including software consultant, mentor, prolific author, Webmaster,Microsoft MVP, and member of ASPInsiders. Having adopted Yoga as a way of life,Bipin also teaches Kriya Yoga. He can be reached via his blog at http://www.bipinjoshi.com.      

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like