If you are a webmaster or an administrator of the website, you must have came across a situation where you need to change the description or introduction of the page time to time or you need to add some extra lines or a special offers details based on the circumstances or importance of the page.
In normal case, these static texts create a lot of hassle of changing the contents of the file and uploading it on the server again and again.
Here, I am going to explain a quick and easy solution without compromising the performance of the page a lot. This solution is database driven but I am not going to hit the database every time a page is requested from the website. This is going to be a custom server control so performance is a bonus here.
The good thing is that this works with dynamic urls of the website too (The url that is created using HttpHandlers) and you can use HTML tags in the description to format the text as you would have done while manually editing the page. In this article, I am using description word instead of introduction of the page.
In process of creating dynamically writing page description control, we are going to do following things.
• Create a database table named “tblPageDescription” and five Stored Procedures to manipulate data.
• Create admin pages to Insert, Update, Delete records (basic pages).
• Create Custom Server Control (PageDescription.cs).
Complete ready to use downloadable project with source code is available, your may prefer to download it from top-right side link. However, I am going to cover each step briefly.
Let’s create this control and its related things step-wise
Step – 1
Create a table into the database
Create a database table named “tblPageDescription” with fields as displayed in the picture below
AutoID – AutoEncrement
PageName – Varchar(50)
PageDescription – Varchar(500)
Active - Bit
Now create five stored procedures for inserting, updating, deleting and loading data.
spInsertData used to insert records into database
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[spInsertData]
(
@PageName varchar(50),
@PageDescription varchar(500),
@Active bit
)
AS
INSERT INTO tblPageDescription (PageName, PageDescription, Active) VALUES
(@PageName, @PageDescription, @Active)
RETURN
spUpdateData used to update record into database
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[spUpdateData]
(
@AutoID int,
@PageName varchar(50),
@PageDescription varchar(500),
@Active bit
)
AS
UPDATE tblPageDescription SET PageName = @PageName, PageDescription = @PageDescription,
Active = @Active WHERE AutoID = @AutoID
RETURN
spDeleteData used to delete record from database
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[spDeleteData]
(
@AutoID int
)
AS
DELETE FROM tblPageDescription WHERE AutoID = @AutoID
RETURN
spGetData used to load all records from database
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[spGetData]
AS
SELECT * FROM tblPageDescription ORDER BY PageName
RETURN
spGetPagesDescription used to load only active records from database
CREATE PROCEDURE [dbo].spGetPagesDescription
AS
BEGIN
SELECT * FROM tblPageDescription WHERE Active = 1 ORDER BY PageName
END
GO
Step – 2
Create admin pages to manipulate description of the pages
First I am going to create a Blank solution and will add a website. I will have two pages named default.aspx (to insert records into database) and ListPage.aspx (to list and manipulate pages description records).
/admin/Default.aspx Insert records into tblPageDescription database tatble
/admin/ListPage.aspx Allow you to update, delete records from database.
Step – 3
Creating Custom Server Control
Now I am going to create few pages in my demo project so that we can test if the dynamic page description control is working fine or not. In this project I have a MasterPage.master, Default.aspx, Page1.aspx, Page2.aspx, Page3.aspx as displayed in the picture below.
So, till now our ingredients for creating, managing and testing our dynamically writing page description control is ready, now let’s create our Custom Server Control that will be placed in the master pages (If you don’t have master page, you can place this control in .aspx pages).
Add a new project (Windows Class Library) named MyControls and create a new class file named PageDescription.cs. Write following using statement at the top of the page besides existing using statement and inherit base Control class.
using System.Web.UI;
using System.Configuration;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
Sometimes based on your installation and version you may not be able to work with System.Web and related namespaces directly and while compiling it may throw error. To overcome this error, you may need to add reference of System.Web by right clicking the References of the project and selecting System.Web from the .NET Tab. Below is the code for writing Custom Server Control named PageDescription. You may exactly copy-paste this code.
using System;
using System.Data;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Configuration;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
namespace TutorialsPageDesc
{
public class PageDescription : Control
{
/* PLEASE NOTE:
* In Practical scenario you should prefer to use your existing architecture to get
* the data from database, However for this demo project, I am directly using Sql objects
* and getting records from database */
// override the render method
protected override void Render(HtmlTextWriter writer)
{
string m_PageName = HttpContext.Current.Request.Url.AbsolutePath;
WritePageDescription(writer, m_PageName);
}
/// <summary>
/// write actual description from database
/// </summary>
/// <param name="writer"></param>
private void WritePageDescription(HtmlTextWriter writer, string pageName)
{
string strPageDescription = string.Empty;
strPageDescription = GetPageDescription(pageName);
// if there is some description for this page then write it otherwise leave it
if (strPageDescription.Length > 0)
{
writer.WriteFullBeginTag("div");
writer.Write(HttpContext.Current.Server.HtmlDecode(strPageDescription).Replace("\n", "<br />"));
writer.WriteEndTag("div");
}
}
/// <summary>
/// Get data from database or cache
/// </summary>
/// <returns></returns>
private string GetPageDescription(string pageName)
{
DataTable dTable = new DataTable();
string strPageDesc = string.Empty;
string strCahceName = ConfigurationSettings.AppSettings["PageDescCacheName"].ToString();
// first check the data into cache, if its there get from cache even don't initialize any object
// You are gaining performance here
if (System.Web.HttpContext.Current.Cache[strCahceName] == null)
{
string connStr = System.Configuration.ConfigurationSettings.AppSettings["ConnStr"].ToString();
SqlConnection conn = new SqlConnection(connStr);
SqlDataAdapter dAd = new SqlDataAdapter("spGetPagesDescription", conn);
DataSet dSet = new DataSet();
try
{
conn.Open();
dAd.Fill(dSet, "PagesData");
dTable = dSet.Tables[0];
// store data into cacheblnotd
System.Web.HttpContext.Current.Cache[strCahceName] = dTable;
}
catch (Exception ee)
{
// I am returning error so that I can track what error occured while getting the data, you may return nothing
strPageDesc = ee.Message;
}
finally
{
dSet.Dispose();
dAd.Dispose();
conn.Close();
conn.Dispose();
}
}
else
{
dTable = System.Web.HttpContext.Current.Cache[strCahceName] as DataTable;
}
if (dTable.Rows.Count > 0)
{
// you have all data now, filter it based on parameter
DataRow[] row = dTable.Select(" PageName = '" + pageName + "'");
if (row.Length > 0) // if there is any data for this page then set properties
{
strPageDesc = row[0]["PageDescription"].ToString();
}
}
return strPageDesc;
}
} // class
} // namespacec
Render method that overrides the Render method of the control base class and receives HtmlTextWriter as a parameter, I am getting the current requested page name using HttpContext.Current.Request.Url.AbsolutePath. This will give me only the name of the file that is being requested currently. Even if there will be any querystring with this url at the time of request, it will only give the absolute path of the page (path from your root folder of the application). This absolute path will be passed to the private method named
WritePageDescription that will take care of writing descriptioin of the page. This method will again calls
GetPageDescription method with pageName as the parameter to get the actual description of the page, if any.
For Simplicity reason, I have not used layered architecture to get the data, instead I am using Sql objects directly to this control and getting the data from database for the first time.
GetPageDescription method will check for the Cache of the page description data, if not found then it will connect to the database, get the data and stores into a DataTable. The same DataTable will be stored into the Cache so that in the next request application doesn’t need to hit the database for the page description records again. Once the records are stored into the Cache it will check for the no. of records into the DataTable, as there might be a chance that you have not entered or you don’t want any description for a particular page. When it ensures that there are some records into the DataTable, it filter the records based on the pageName parameter and stores into the local variable and return it to its parent WritePageDescription method. WritePageDescription method will check for the returned value and write the actual description of the page if any.
When subsequent time any page is requested from your website, application checks for the Cache records and once found, it will skip the database connecting block and get the records from the Cache and serve to the website. In this way, we are not hitting the database again and again to get the page description and saving resources and processing time.
Please note that you need to remove the Cached object at the time of inserting, updating and deleting records so that the updated page description will be immediately cached again in the next request. To remove the object from Cache, please use following code:
System.Web.HttpContext.Current.Cache.Remove(ConfigurationManager.AppSettings["PageDescCacheName"].ToString());
You may find this code in the downloaded source code.
So now you have your Custom server control ready. Just Build it and add reference to this project (MyControls) to your Website project by right clicking the Website and clicking Add Reference … as displayed in the picture – 5.
Step – 4
Registering Custom Server Control to your page
Now, it’s time to register your control to your master page and placing it as desired place so that it works for all pages of your website. If you have named the same way I did, your Register directives in the master page should look like
<%@ Register Namespace="TutorialsPageDesc" TagPrefix="MyPage" Assembly="MyControls" %>
Choose the place where you want to call this control and write following code
<MyPage:PageDescription id="Pd1" runat="server" />
Step – 5
Its time to test now
Now you are done. Go to your admin pages (in my case http://localhost/admin/default.aspx) and write absolute path of the page (/WebSite/Page2.aspx) in the Absolute path box and enter something in the Page Description box. You can well enter Text, HTML coded, CSS, JavaScript etc. into it and click Submit button. Try accessing the page for which you entered the record (http://localhost/WebSite/Page2.aspx) and you will see that your entered description is appearing, if you are not satisfied with the description go ahead and change it from your admin page (http://localhost/WebSite/admin/ListPage.aspx) still not satisfied? Play with it :) .
Hope this helps you managing static description or introduction of your pages and hassle of updating and uploading files on the server.
I know this is not the only way to achieve this task, but I find it easy and fast and it works for all pages of the website. If your website has no master pages you can well place it inside the .aspx pages but you need some extra effort of copy-pasting registering and calling the controls to all .aspx pages you want it on. If you have any questions, feedback or suggestions, do write to me.
Happy Coding and Enjoy!!!