In my previous post, I have found something interesting when doing join project with a company and share that interesting things to you. Hopefully it can helps you in your development.
Yesterday, the IT manager want me to add notification functionality in an ASP.NET 2.0 application. Since the application contains more than 50 pages, I can’t suddenly write some code in their project and then do the recompilation. No, I won’t.
To make the notification information available in every pages, some of approaches are:
- Make a service layer (WCF or WebService) and consume it with JavaScript code. The JavaScript code would reside IN EVERY pages. So I have to copy the JavaScript code in every pages. This is awkward and painful. :( Even if I put the code inside .JS, but the code still have to copy in every pages.
- Modify the pages, and add custom code. I have to recompile again. This is not a good choice.
Those approaches is not good.
Because I know how ASP.NET pipeline work, then I already ‘gotcha’ that I have to create custom HttpModule. This solution is elegant, since I don’t have to touch their code and even their pages. :)
Technically, HttpModule is just a class which you can inherits from IHttpModule interface. So, let’s explore in depth.
- Create a new C# website in Visual Studio 2010 and name it as default. Choose Empty ASP.NET Web Site.
- Add new Web Form and name it as default. (Default.aspx)
- Add new class and name it NotificationModule.cs. Let VS2010 add into App_Code for you. Just confirm that. Your class skeleton is ready.
- Now, open your Default.aspx file and modify like below:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>This is Default.aspx</h1>
<asp:GridView ID="gridData" runat="server"></asp:GridView>
</div>
</form>
</body>
</html>
Press F7 to go into code behind, and modify like below (or change the code whatever you like):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (! IsPostBack)
{
string[] names = { "Agung", "Akbar", "Ayu", "Bayu", "Taufan" };
gridData.DataSource = names;
gridData.DataBind();
}
}
}
Go to your NotificationModule.cs, and implement the Init method.
public void Init(HttpApplication context)
{
context.BeginRequest += (sender, e) =>
{
context.Response.Write("BeginRequest ... executed<br />");
};
context.EndRequest += (sender, e) =>
{
context.Response.Write("EndRequest ... executed<br />");
};
}
Now, we explore the BeginRequest and EndRequest method. How this method work? Just compile and run the Default.aspx. You will understand based on the result. :)
Note that I used Lambda Expression because of the simple implementation. You can use event handler by pressing TAB button twice after you type += to write complex codes.
Then, save it by pressing CTRL+S.
Open your web.config file and put this in <system.web> section:
<httpModules>
<add name="NotificationModule" type="NotificationModule" />
</httpModules>
Just beware that the type attribute. The type attribute should in this format:
type=”Namespace.ClassName, Namespace”
So, if you put your class inside MyCompany namespace, then you should type like this:
type=”MyCompany.NotificationModule, MyCompany”
The last is, just open your Default.aspx in a web browser. The result will be like this (or depends on what you typed):
See the execution of BeginRequest and EndRequest? That’s the place where you want to put something in your application. :)
You don’t have to recompile all the pages, you don’t have to touch the pages itself.
Not only that, you can also override the Page_Load functionality or the other event in Page events by using PreRequestHandlerExecute. :)
Let’s modify it again.
Open your NotificationModule.cs and add this code inside Init method:
context.PreRequestHandlerExecute += (sender, e) =>
{
var handler = context.Context.CurrentHandler;
if (handler != null && handler is System.Web.UI.Page)
{
System.Web.UI.Page currentPage = (System.Web.UI.Page)handler;
currentPage.Load += (source, args) =>
{
System.Web.UI.WebControls.Literal lit = new System.Web.UI.WebControls.Literal();
lit.Text = "<b>This is injecting in HttpModule</b><br /><br />";
((System.Web.UI.Page)source).Controls.Add(lit);
};
}
};
First, I put the CurrentHandler inside handler variable reference to make it reusable.
Then, I have to check if handler is not null and handler is Page. Yes, you can cast handler whatever you want (if any and available). The CurrentHandler will return a Page class. Look at the breakpoint below:
Then the handler itself I cast into System.Web.UI.Page. The last is I make the Load event available to modify by enabling currentPage.Load event.
Remember, in this event, you can’t inject web user control or user control because the PreRequestHandlerExecute would not create viewstate, so just only literal HTML (plain old HTML allowed). Yes, this is the limitation. But, you can extend it by, let say, consume another service layer like WCF or WebService.
This is the complete code inside Init method:
public void Init(HttpApplication context)
{
context.BeginRequest += (sender, e) =>
{
context.Response.Write("BeginRequest ... executed<br />");
};
context.EndRequest += (sender, e) =>
{
context.Response.Write("EndRequest ... executed<br />");
};
context.PreRequestHandlerExecute += (sender, e) =>
{
var handler = context.Context.CurrentHandler;
if (handler != null && handler is System.Web.UI.Page)
{
System.Web.UI.Page currentPage = (System.Web.UI.Page)handler;
currentPage.Load += (source, args) =>
{
System.Web.UI.WebControls.Literal lit = new System.Web.UI.WebControls.Literal();
lit.Text = "<b>This is injecting in HttpModule</b><br /><br />";
((System.Web.UI.Page)source).Controls.Add(lit);
};
}
};
context.PostRequestHandlerExecute += (sender, e) =>
{
context.Response.Write("PostRequestHandlerExecute ... executed<br />");
};
}
Save it by pressing CTRL+S. And refresh the browser with F5. You will see the result:
You can put custom code and do whatever you like. :)
Hope this help.
See ya…