Yet another IIS7 managed module: AdvertisementModule

This has got to be the most overdue blog ever (no kidding!) I wrote this managed module over 2 years ago using the then *new* IIS extensibility. Consider this post as my New Year resolution to get this published ;)

Advertisement Module: the idea

I wrote a managed module (called it advertisement module) which can be plugged into IIS7 and show cases a very simple example of how a customer can configure ads for a url and serve these when the url is requested. There are many features that can enhance this module capability like more configurable ad placement, video integration, richer content support, etc.

The idea is simple: the advertisements are configurable, so the customer can specify the ads to be served for a url. The advertisement managed module is registered for a url and will insert these ads to all the pages served by the url.

All the advertisements are specified in a collection in configuration. Each ad is assigned an impression (based on a criterion like level of service, money investment, business needs, etc). An ad with the highest impression has the highest probability of making it on the page when the url is requested.

Let me walk you through step by step…

Schema Definition:

The first thing to do is to define the schema for the configuration section. Below is the schema file for the advertisements section, this schema file is saved as %windir%\system32\inetsrv\config\schema\Advertisement_Schema.xml:

 

<configSchema>
  <sectionSchema name="system.webServer/advertisements" >                   
    <collection addElement="add" removeElement="remove" clearElement="clear">
      <attribute name="imageUrl" isUniqueKey="true" type="string" />
      <attribute name="navigateUrl" type="string" />
      <attribute name="toolTip" type="string" />
      <attribute name="impression" type="int" validationType="integerRange" validationParameter="0,1000" defaultValue="500"/>
    </collection>
  </sectionSchema>
</configSchema>

Each advertisement element contains:

- image url :path to the image aka the advertisement relative to the url (required)

- navigateUrl: a url to browse to when the advertisement is clicked

- tooltip : an alt text for the advertisement for when it is hovered on

- impression : this is an integer between 0 and 1000 (defaults to 500)

Add the section definition to applicationHost.config

Once you have saved the schema file under the inetsrv\config\schema file, we need to add this section’s definition to applicationHost.config. All you need to do is add the line <section name=”advertisements” /> to the sectionGroup with the name “system.webserver”. So the applicationHost.config will look like:

 

…
<sectionGroup name="system.webServer">
        <section name="advertisements" />
…

That’s all; the section is all defined and ready for some config data, a sample of how the configuration looks like for this section below:

 

<system.webserver>
    <advertisements>
            <add imageUrl="\welcome.png" navigateUrl="http://www.iis.net" toolTip="Click here to check out IIS7" impression="500" />
        </advertisements>
</system.webserver>

Advertisement module (details and code)

Let’s start the fun part! We have the configuration, we know how to configure and add advertisements for a url. Now let’s write the managed module that will use these configuration settings.

This managed module intercepts all responses to htm/html or aspx pages and places advertisements on the page. So we would need to register a post authorize event and write the event handler code.

Currently this module only supports images as ads; the images are added to a fixed position (top center) on the page.

The GetAdvertisement method gets all the advertisements from configuration, decides which advertisement to place on the page based on the impression number and reads that particular ad from the config. The ad is randomly picked from the collection of ads for the url. The probability of an individual ad being picked depends on its “impression” value. The higher the impression value, the higher the chance for the ad to be picked for the page. 

Code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.Web.Administration;

class AdvertisementModule : IHttpModule
{

    #region IHttpModule Members        
    int index, maxVal, randomVal, tempVal = 0;
    string adImageUrl, adNavigateUrl, adToolTip = string.Empty;    
    string html_addOn;   

    public void Dispose()
    {

    }

    public void Init(HttpApplication context)
    {     
        context.PostAuthorizeRequest += new EventHandler(this.GetAdvertisement);           
    }   
   
    public void GetAdvertisement(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
        HttpContext context = app.Context;
        HttpResponse response = context.Response;

        if ((app.Request.Path.EndsWith(".htm")) || (app.Request.Path.EndsWith(".html"))||(app.Request.Path.EndsWith(".aspx")))
        {       
            ConfigurationSection section = WebConfigurationManager.GetSection("system.webServer/advertisements");
            ConfigurationElementCollection coll = section.GetCollection();
            
            if (coll.Count > 0)
            {
                //getting the total of the impressions, using this as MaxVal for the random number generation                                        
                for (int i = 0; i < coll.Count; i++)
                {
                    maxVal += (int)coll[i].GetAttributeValue("impression");
                }
                Random random = new Random();
                randomVal = random.Next(0, maxVal + 1);
                
                //getting the index of the advertisement to read from config            
                for (int j = 0; j < coll.Count; j++)
                {
                    tempVal += (int)coll[j].GetAttributeValue("impression");
                    if (tempVal >= randomVal)
                    {
                        index = j;
                        break;
                    }
                }

                //reset
                maxVal = 0; 
                randomVal = 0;
                tempVal = 0;

                ReadAdFromConfig(index); //read ad details from config

                //form the html for the advertisement and add it to the response
                response.Write("<div align=\"center\" style=\"border: 0px width: 800px height: 254px overflow:visible\">");
                //objectCall = "<object classid=\"clsid:25336920-03F9-11CF-8FD0-00AA00686F13\" height=\"20%\" width=\"100%\" type=\"image/text\">"; //data=\"{0}\" >";
                
                if (adNavigateUrl == string.Empty)
                {
                    html_addOn = "<img border=\"0\" src=\"{0}\" width=\"800\" height=\"100\" alt=\"{1}\">";
                    response.Write(string.Format(html_addOn, adImageUrl, adToolTip));
                } else if (adToolTip == string.Empty){
                    html_addOn = "<img border=\"0\" src=\"{0}\" width=\"800\" height=\"100\" >";
                    response.Write(string.Format(html_addOn, adImageUrl));
                } else {
                    html_addOn = "<a href=\"{0}\"><img border=\"0\" src=\"{1}\" width=\"800\" height=\"100\" alt=\"{2}\"></a>";
                    response.Write(string.Format(html_addOn, adNavigateUrl, adImageUrl, adToolTip));
                }              
                response.Write("</div>");                
            }
        }
    }

    private void ReadAdFromConfig(int index)
    {
        //Get the url for the ad, insert the correct html text and return               
        ConfigurationSection section = WebConfigurationManager.GetSection("system.webServer/advertisements");
        ConfigurationElementCollection coll = section.GetCollection();               
        adImageUrl = coll[index].GetAttributeValue("imageUrl").ToString();
        adNavigateUrl = coll[index].GetAttributeValue("navigateUrl").ToString();
        adToolTip = coll[index].GetAttributeValue("toolTip").ToString();
        if (adToolTip == string.Empty)
        {
            adToolTip = adNavigateUrl;
        }               
    }       
   
    #endregion
}

Build and copy the module dll (AdvertisementModule.dll) to the bin folder under the site's physical path (for eg, for Default web site, this dll will be copied to %windir%\inetpub\wwwroot\bin)

Now, add this managed module to the site's web.config. Snapshot of the web.config file:

 

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <modules>
            <add name="MyAdModule" type="AdvertisementModule" />
        </modules>             
      <advertisements>
            <add imageUrl="\welcome.png" navigateUrl="http://www.iis.net" toolTip="Click here to check out IIS7" impression="500" />
        </advertisements>
    </system.webServer>
</configuration>

Now, just make a request to an htm/html or aspx page on this site and watch your module go!

A snapshot of this module in action below…

Snapshot

Next up I will post the Advertisement inetmgr UI module to configure the advertisements section.

No Comments