Click here to Skip to main content
Click here to Skip to main content

Ad Rotator Widget Control for BlogEngine.NET

, 19 Dec 2008 CPOL
Rate this:
Please Sign up or sign in to vote.
BlogEngine.NET Ad Rotator Control provides a simple interface for managing and rotating ads on the blog

Introduction

BlogEngine.NET is an open source .NET blogging project that was born out of a desire for a better blog platform. A blog platform with less complexity, easy customization, and one that takes advantage of the latest .NET features. Being an open source, BlogEngine.NET provides great level of customization and extensibility.

Starting a blog couple months ago, I start looking into available extensions you can download and implement into your own BlogEngine.NET installation. Browsing through the long list of available extensions, I was quite surprise not to find any extensions which would allow adding and managing ads on the blog.

Background

Thinking about the requirements I wanted from such a control, I came out with the following list:

  • Should support any Ad Provider
  • Should allow hide ads for authenticated users, to keep correct impression count
  • Should be easy to manage and allow to keep all my ad script in one repository
  • Should provide not only random but also weighted rotation, allowing to customize frequency with which each ad script is displayed to the users. The idea behind it is to distribute ad impressions between different providers to maximize revenue stream.

Using the Code

The widget consists of AdManagementBase.cs file with a set of common classes for the widget and “Sponsored Links” folder with widget code.

To install it, just copy AdManagementBase.cs into BlogEngine\App_Code\Extensions folder and then copy “Sponsored Links” folder to BlogEngine\widgets folder. The widget now should be available in the widget collection of BlogEngine.NET

InstallWidget.jpg Widget.jpg

To see it working, take a look at the Interview Patterns with C# blog.

Points of Interest

LoadWidget Method

BlogEngine.NET provides a very straight forward interface for implementing widgets and custom extensions. AdRotator class inherits from abstract class WidgetBase which is essentially a child of ASP.NET UserControl class. WidgetBase contains only one abstract method and two abstract properties which need to be implemented:

//This method works as a substitute for Page_Load. 
//You should use this method for data binding etc. instead of Page_Load.
public abstract void LoadWidget();
// Gets the name, must be exactly the same as the folder that contains the widget
public abstract string Name { get; }
// Gets whether or not the widget can be edited.
public abstract bool IsEditable { get; }

The heart of the widget control is the LoadWidget method.

public override void LoadWidget()
{
ASPCache aspCache=new ASPCache(this.Page);
StringDictionary settings = GetSettings();
Boolean hideForAuthenticatedUsers= true;

List<Ad> ads = AdManagementBase.DeSerializeAds
		(settings[AdManagemenConstants.AdCollectionKey]);

ads.ForEach(delegate(Ad ad) { totalWeight += ad.RWeight; });

Boolean.TryParse(settings[AdManagemenConstants.HideAdsForAuthZUsersKey],
			out hideForAuthenticatedUsers);

adManager = new AdManagementBase(aspCache, ads);

if (!IsPostBack)
{
if ((!System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated) || 
			(!hideForAuthenticatedUsers))
ShowAds(totalWeight);
else
adHolder.InnerHtml = AdManagemenConstants.AuthZUserMessage;
}
}

Class WidgetBase isolates widget developers from implementation of settings storage retrieval mechanism by providing GetSettings() function which returns StringDictionary with widget settings specified on the edit screen. Unfortunately this interface works only with strings and doesn't have any internal logic to serialize complex objects. To solve this problem, AdManagement base class uses XmlSerializer and StringWriter to serialize list of Ad objects and persist it in widget settings collection.

public static string SerializeAds(List<Ad> ads)
{
if ((ads == null) || (ads.Count == 0)) return string.Empty;

XmlSerializer serializer = new XmlSerializer(typeof(List<Ad>));
StringWriter stream = new StringWriter();
serializer.Serialize(stream, ads);
return stream.ToString();
}


public static List<Ad> DeSerializeAds(string serializedStream)
{
if (string.IsNullOrEmpty(serializedStream)) return new List<Ad>();

XmlSerializer serializer = new XmlSerializer(typeof(List<Ad>));
return (List<Ad>)serializer.Deserialize(new StringReader(serializedStream));
}

The check for CurrentPrincipal property CurrentPrincipal.Identity.IsAuthenticated allows to display default text instead of ads for all authenticated users and avoid false impressions.

AuthZUser.jpg

Editing Settings

As per BlogEngine documentation, the only way a widget can be editable is by adding a edit.ascx file to the widget folder. However, there are a couple more things that need to be done:

  1. Widget needs to override IsEditable property of WidgetBase class to return true
  2. Widget should contain edit.ascx file with base class inherited from WidgetEditBase
  3. Save method should be implemented to provide logic to save widget settings
public abstract class WidgetEditBase : UserControl
{
// Saves the basic widget settings such as the Title.
public abstract void Save();

// Get settings from data store
public StringDictionary GetSettings()
{
...
}

// Saves settings to data store
protected virtual void SaveSettings(StringDictionary settings)
{
...
}

public static event EventHandler<EventArgs> Saved;
// Occurs when the class is Saved
public static void OnSaved()
}

SponsoredLinks widget overrides Save method and saves two parameters: collection of ad providers and boolean value indicating if the ads should be hidden for authenticated users:

public override void Save()
{
doUpdate();
StringDictionary settings = GetSettings();
settings[AdManagemenConstants.AdCollectionKey] = 
		AdManagementBase.SerializeAds(adCollection);
settings[AdManagemenConstants.HideAdsForAuthZUsersKey] = 
				cbAuthZAds.Checked.ToString();
SaveSettings(settings);
HttpRuntime.Cache.Remove(AdManagemenConstants.WidgetSettingsKey);
HttpRuntime.Cache.Remove(AdManagemenConstants.SerializedAdsKey); 
CurrentIndex = 0;
}

The Ad object also contains such information as name for the script you are using, JavaScript code snippet provided by ad network (Google, YPN, Microsoft, Bride, etc.) and the rotation weight. Use rotation weight to influence the ration of ads delivered from each ad provider. Note: If all of your scripts have weight equal to zero, the ads will have equal probability to be shown. If any of your scripts have weight greater than zero, all the ads with zero weight will not be shown at all.

EditScreen.jpg

Click here for the demo.

History

  • 20th December, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

SALEKS

United States United States
No Biography provided

Comments and Discussions

 
QuestionThanks for the code. I just added it to blogengine 2.7. PinmemberJames Hodges10-Nov-12 18:35 
QuestionThis is nice - I have some questions not discussed in the article. Pinmemberstixoffire28-Aug-09 19:50 
GeneralThanks PinmemberJeffCirceo13-May-09 6:12 
GeneralNull reference exception fix PinmemberSALEKS31-Mar-09 19:47 
Generalsame problem Pinmemberkdutttomb24-Mar-09 7:48 
QuestionObject reference not set to an instance of an object. Pinmemberbcousins26-Jan-09 17:29 
Installed and ran your extension. Pasted in the javascript code from my Google AdSense account and get the following error when the extension runs:
----------
Server Error in '/BlogEngine' Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
 
Source Error:
 
Line 58: }
Line 59: else
Line 60: adCollection = AdManagementBase.DeSerializeAds(HttpRuntime.Cache[AdManagemenConstants.SerializedAdsKey].ToString());
Line 61:
Line 62:
 

Source File: c:\Inetpub\wwwroot\BlogEngine\widgets\Sponsored Links\edit.ascx.cs Line: 60
 
Stack Trace:
 
[NullReferenceException: Object reference not set to an instance of an object.]
widgets_SponsoredLinks_edit.OnLoad(EventArgs e) in c:\Inetpub\wwwroot\BlogEngine\widgets\Sponsored Links\edit.ascx.cs:60
System.Web.UI.Control.LoadRecursive() +50
System.Web.UI.Control.LoadRecursive() +141
System.Web.UI.Control.LoadRecursive() +141
System.Web.UI.Control.LoadRecursive() +141
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627
 

Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.2 | Last Updated 20 Dec 2008
Article Copyright 2008 by SALEKS
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid