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

Ad Rotator Widget Control for BlogEngine.NET

By , 19 Dec 2008
 

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)

About the Author

SALEKS
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionThanks for the code. I just added it to blogengine 2.7.memberJames Hodges10 Nov '12 - 18:35 
Thanks for the code. I just modified it to work with blogengine 2.7. and have it up and running.   It wasn't too painful (compared to some of the other widgets that I have fixed). I just had to wrap the project namespace around the classes in the code behind files as your code didn't use...
QuestionThis is nice - I have some questions not discussed in the article.memberstixoffire28 Aug '09 - 19:50 
Being new to BlogEngine.NET :   1: Where does this extension store the Ad information , is this in an XML file or in the database - if my site uses a database - does this control adapt to that or do I need to adapt it.   2: Is there a means where by I can place the control anywhere...
GeneralThanksmemberJeffCirceo13 May '09 - 6:12 
I was thinking about doing the exact same thing, now I don't have to.   By the sounds of some of the other comments I might have to resolve some exceptions but I’m ok with that.   5 from me   Take a look at my corner of the net at Code Research Center
GeneralNull reference exception fixmemberSALEKS31 Mar '09 - 19:47 
Sorry for the late responce, the Delete button functionality had bug and index was going out of the array range.   You can download new version from here: http://interviewpattern.com/SponsoredLink_BlogEngine.zip[^]   Or for quick and dirty fix just modify widgets\Sponsored...
Generalsame problemmemberkdutttomb24 Mar '09 - 7:48 
Object reference not set to an instance of an object.   What's the way to fix this?
QuestionObject reference not set to an instance of an object.memberbcousins26 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...

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 20 Dec 2008
Article Copyright 2008 by SALEKS
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid