building a contentrotator asp
TRANSCRIPT
-
8/7/2019 Building a ContentRotator ASP
1/17
Building a ContentRotator ASP.NET Server
Control
Summary: This article examines the steps involved in creating a custom, compiled ASP.NET server
control that randomly rotates through specified content, much like the built-inAdRotator control
randomly rotates through a series of predefined banner advertisements. In examining the innards
of the ContentRotator control this article touches upon several aspects of custom ASP.NET control
development. (20 printed pages)
Download ContentRotator.msi.
Contents
Introduction
Thinking About Content RotationSpecifying Content Items
Specifying Content Through a Content File
Specifying Content Items Declaratively
Specifying Content ProgrammaticallyDetermining the Content Item to Display
Reading Content Data from the Content File
Reading Content Data Programmatically
Reading Content from the Control's Declarative Syntax
Picking a Random Content ItemServing Dynamic ContentCustomizing the Selected Content Item
ConclusionSpecial Thanks toAbout the Author
Introduction
Back in the late 90s, anything seemed possible. The World Wide Web and its effect on business
was growing astronomicallykids were dropping out of college to build Web sites and become
millionaires overnight while companies were shelling out millions of dollars for prime-time
television commercials to have a sock puppet extol the virtues of buying pet food online. Yes, this
was the time of the New Economy, when attracting millions of Web surfers to a Web site was
deemed more economically valuable than selling boring old products from a stuffy building.
At the height of these exuberant times, Microsoft introduced theAdRotator COM component for
classic ASP, a tool that allowed budding Web entrepreneurs to easily add banner advertisements
to their site. The first step in displaying a banner ad was to have an advertisements file listing the
banners that could be displayed. This text file contained four bits of information about each
banner:
-
8/7/2019 Building a ContentRotator ASP
2/17
y A URL to the banner's imagey The URL that the image links toy The alternate text for the imagey The frequency by which the banner was to be shown relative to the other banners in the
file
Armed with this text file, all an ASP developer had to do was call the
AdRotator'sGetAdvertisement(advertisementFile) method, passing in the path to the
advertisements file, and the AdRotator would return the HTML markup for displaying a randomly
selected banner advertisement from the specified file. At this point, I imagine, the money started
rolling in.
When ASP.NET shipped in 2002, the New Economy was officially kaput. The NASDAQ composite,
which had peaked around 5,000 in 2000, had slumped back down to below 2,000. Despite the
dot-com meltdown, however, Microsoft must still have been bullish on online advertising, for they
gussied up the AdRotator control from classic ASP and released it as one of the standard Web
controls that shipped with ASP.NET. The ASP.NET version of the AdRotator offered several
benefits over the classic ASP version:
y The advertisements file was now XML-formatted, making it easier for page developers tocreate and edit the file's contents.
y Each ad could contain a keyword indicating the category to which it belonged. This, inaddition to the AdRotator's new KeywordFilter property, could be used to limit the
set of banners displayed for a particular AdRotator control instance.
y In addition to the standard set of advertisement properties, page developers could addtheir own additional settings in the advertisements file. These added settings could then
be accessed programmatically by a page developer in the AdRotator'sAdCreated event.
While the AdRotator makes it easy to randomly display a banner from a predefined list, it has anumber of shortcomings, in my opinion, two of the main ones being:
1. The AdRotator's content can only be specified through an XML-formatted advertisementsfile. This is not a major limitation, but it would be nice if one could specify content
declaratively through the AdRotator's markup or programmatically through source code,
in a similar fashion to how ListItems can be specified declaratively or programmatically for
the DropDownList Web control.
2. The AdRotator is rather limited in the markup it can generate. As its name implies, it isdesigned to display ads, which are either text or an image linked to some URL. With a bit
more work, the AdRotator could have been created to display anytype of content, not
just banners or text ads.
It is this second shortcoming that particularly bugs me, as with just a bit more work the AdRotator
could have been made into a very generic content rotator, as opposed to being designed to
solely display advertisements. In this article we'll right this shortcoming and others by creating a
full-featured ContentRotator server control.
Thinking About Content Rotation
-
8/7/2019 Building a ContentRotator ASP
3/17
Before diving into any coding project, it's important to take ample time to answer the following
three questions.
1. Is there an existing control that accomplishes what I need? If your days are anythinglike mine, with meetings, e-mails, and other such busy work taking up more hours of the
day than I'd like to admit, writing code is oftentimes the most fun activity of the day.
There's nothing more enjoyable than being genuinely excited about a problem and
finding a solution to the problem through code.
However, "fun" and "economically viable" are two different things. It may be enjoyable to
create a particular control, but it probably doesn't make economic sense to spend one's
time building, testing, and tweaking the control if there already exists one that offers the
needed functionality.
When I find myself gearing up to create a new server control, the first thing I do is head
over to the ASP.NET Control Gallery to see if my efforts might be in vain. A quick
inspection of the Control Gallery shows that there's an entire category dedicated to Content
Rotators. Many of these content rotators, however, are the type that rotate throughcontent on a single page, such as news or stock tickers.
I found one control that rotates through arbitrary static HTML content like the AdRotator
controlDuncan Mackenzie'sContentRotator User Control, presented in the article Rotating
Is Fun. While Duncan's User Control offered the base functionality of the AdRotator, albeit
with arbitrary HTML content, I decided not to use his solution as it does not provide quite
the functionality I was looking for. (For example, Duncan's control does not allow for
content to be tagged with a keyword.)
In my searches I was unable to find a content rotator that met my requirements.
Therefore, I decided to create my own. (Woo hoo! This meeting can wait, bossI have acoding project to complete now!)
2. What functionality does my control need to provide? If you decide that you need tocreate your own control, be certain not to rush into the fun partcoding; rather, have a
clear picture on what, exactly, you need the control to do before writing your first line of
code. One good way to determine the control's requirements is to devise common use
cases that describe how end users (page developers, in this case) will be using your
control. Among the first things I ask myself when building server controls are:
o How will page developers use this control?o What will they need to have this control work as desired, ando How should the syntax look?
After my initial brainstorming I came up with the following four use cases:
Harry, an up-and-coming ASP.NET developer, wants to enhance his company's intranet so
that the homepage randomly displays a short biography and picture of one of the
company's employees. Since Harry's company has only a dozen employees, he's content
with hard-coding the bio and picture markup in a file for now, but would like the ability to
upgrade this later to retrieve the items from a database as the company grows. His aim is
-
8/7/2019 Building a ContentRotator ASP
4/17
to have the ContentRotator randomly select one employee from that file and display his
information on the homepage for each visit.
Jisun is a developer at BuyPetFoodOnline.com, a new startup that has pegged its venture
capital on the hopes that John Q. Public is interested in buying Alpo online. All the brands
of pet food sold at BuyPetFoodOnline.com are maintained in a Microsoft SQL Server
database. On the site's home page, Jisun wants to display either a list of the top 10 selling
brands of pet food, a list of all types of dog food, or a list of all types of cat food.
Furthermore, she wants the content for the top 10 selling brands to appear, on average,
twice as often as the dog or cat food content combined.
Todd runs a fitness Web site and has thousands of members registered on his site, with
information such as their names, birth dates, weights, and other fitness-related data. At
the bottom of each page, Jim would like to display a random fitness statistic tailored to
the visitor's personal information. For example, he'd like to have messages like the
following to appear: [[username]], in the [[numberOfDaysSinceBirth]] days you've been
alive, your heart has beat over [[averageHeartRateTimesDaysAlive]] times," where each of
the placeholders are filled with values specific to the logged-on user.
Budding ASP.NET developer Darren is very new to XML and is worried he'll make a
mistake when specifying content items in an XML-formatted content file. Darren is
familiar with the DropDownList Web control and used to the DropDownList's declarative
syntax for specifying ListItems. Darren would like to be able to specify content items for
the ContentRotator in the same manner. Similarly, he would like to be able to
programmatically manipulate the ContentRotator's content items with syntax similar to
that required for working with the DropDownList'sListItems programmatically.
The features of the ContentRotator flow from these use cases, which provide direction in
the ContentRotator's implementation.
3. Is there a possibility for code reuse? One of the main benefits of object-orientedprogramming is the ease with which existing functionality can be incorporated and
extended. When creating a new server control it is very likely that there already exists an
ASP.NET server control that provides similar functionality. Is it possible to merely extend
this existing server control, rather than build one from the ground up?Building on top of
an existing control will likely save countless hours of coding and testing.
Before I began creating the code for the ContentRotator, I examined the possibility of
having the ContentRotator extend the existing ASP.NET AdRotator control. The AdRotator
class already contains the methods and properties needed for reading in items from an
advertising file and randomly selecting an appropriate one. Might I be able to reuse this
class and just override the specific methods that emit a banner or text ad, crafting them
into methods that return more generic content?
I considered this avenue, but decided against it for a couple of reasons. First, many of the
AdRotator's methods are not marked virtual, meaning that they cannot be overridden.
In particular, because the methods that parse the advertisements file are not virtual, my
derived class would have to make use of the AdRotator's existing XML format. This would
-
8/7/2019 Building a ContentRotator ASP
5/17
not necessarily limit the ContentRotator's functionality (as the AdRotator can have
arbitrary XML elements added), but it would be a cosmetic downer, since it would use the
advertisement file's and elements. Also, the AdRotator
requires an element, which is an unacceptable requirement for a generic
content rotator.
After proceeding through this thought process with prudence, I was ready to start writing the
codefinally, the fun part! Throughout the remainder of this article I'll take you through some of
the more interesting parts of the code for the ContentRotator control that will not only shed light
on the inner workings of this particular control, but also provide an example for accomplishing
similar functionality in the server controls that you create.
Specifying Content Items
The ContentRotator control provides three ways to specify content items:
1. Through a separate content file in XML format.2. Through the ContentRotator's declarative syntax.3. Through server-side programmatic means.
The first option of using an external file provides better reuse of content items, since a single
content file can be used by many content rotators on different pages in a single Web site.
However, there may be times where you want to quickly put up a simple ContentRotator control
without having to bother with creating a separate content file. In these cases, you can use the
second option and provide the content items to iterate through in the control's declarative syntax.
The final option allows you to programmatically specify the content items. This option is useful if
the set of possible content items needs to be dynamically selected, or if they exist in a database
or some other nonstatic store.
Specifying Content Through a Content File
When specifying content items in an XML-formatted content file, the content items must be
presented according to a particular XML schema. Specifically, the content file must start with a
element that contains a element for each content item. Each
item has three optional attributes:
y impressionsspecifies the weight of the content item, which is used to determine theprobability of the item being displayed.
y keywordspecifies the content item's keyword. The ContentRotator control contains aKeywordFilter property that, if set, limits the content items to be considered for
display to just those with a matching keywordparameter.
y contentPathcontent items can contain either static HTML markup or dynamic, code-driven content. If you want to make use of dynamic content you can specify the path to a
User Control via this attribute. If the selected content item's contentPath attribute is
set, the content is generated by the specified User Control.
-
8/7/2019 Building a ContentRotator ASP
6/17
The element can also contain text that provides the static markup to display. This
static markup is displayed if the contentPath attribute is not provided.
The following shows an example of a properly formatted content file with four content items. The
first content item lacks any of the optional attributes, consisting only of the text content to
display. The second content item has both the impressions andk
eyword attributes provided,while the third content item has just the keyword attribute set. Note that if you want to display
HTML markup in the content item's text section you need to either XML-escape the markup as in
the second example, by using < and > rather than < and >, or by wrapping the entire
contents within a section. The fourth and final content item refers to a User
Control, RichContent.ascx, which is specified through the contentPath attribute.
Additionally, the impressions attribute is set to 5.
Things are just average... neither positive nor negative...You will soon see a workplace promotion.
Happiness is just around the corner!]]>
The content file needs to be saved on the Web server's file system. To display content from a
particular file, simply add a ContentRotator to an ASP.NET page and set its ContentFileproperty to the virtual path of the content file.
Note Keep in mind that XML is case-sensitive, so the casing of the XML elements is important. If
you fail to use the proper casingusing instead of, for examplethe
content items will not be retrieved from the content file, resulting in a ContentRotator control that
does not emit any content items.
Specifying Content Items Declaratively
Many of the built-in ASP.NET Web controls allow most of their properties to be specified in the
Web control's declarative syntax. For example, one can specify the particular DataGridColumnsthat should constitute a DataGrid through the declarative syntax. The ContentRotator
offers similar declarative syntax for specifying its content items. For each item the ContentRotator
should consider for random display, add a element within the
tag. Each element can contain the following
attributes:
y Content
-
8/7/2019 Building a ContentRotator ASP
7/17
y Impressionsy Keywordy ContentPath
These attributes map to the text portion of the element and the impressions,
k
eyword, andcontentPath attributes in the XML content file schema, respectively. (You canoptionally specify the Content attribute as the inner tag's text content, as shown below in the
first two instances.) The following shows the declarative syntax for a
ContentRotator with the same four content items as used above:
Things are just average... neither positive nornegative...You willsoon see a workplace promotion
Note that with the declarative syntax you do not need to escape HTML characters in the Content
attribute.
Specifying Content Programmatically
To aid with the concept of content and content items, the ContentRotator includes two classes:
y ContentItemabstractly represents a content item with properties like Content,ContentPath, Keyword, Impressions, and so on.
y ContentItemCollectiona strongly typed collection ofContentItem instances.The ContentRotator control contains an Items property that is of type
ContentItemCollection. You can programmatically specify the content items that the
ContentRotator should consider when randomly selecting an item by addingContentItem
instances to the Items property. As with other ASP.NET server controls, content added to the
Items property is stored in the control's view state, so you need to add these items only on the
first page visit and not on subsequent postbacks. The following code snippet shows how to
programmatically add the same set of content items used in the earlier two examples:
private void Page_Load(object sender, System.EventArgs e){if (!Page.IsPostBack)
{// only need to load content items on first page visit
they are persisted across// postbacks in the ViewState...
ContentRotator1.Items.Add(new ContentItem("Things are just
-
8/7/2019 Building a ContentRotator ASP
8/17
average... neither positive nor negative..."));
ContentRotator1.Items.Add(new ContentItem(" You willsoon see a workplace promotion ", string.Empty, "positiveComments",3));
ContentItemthirdCI = new ContentItem();thirdCI.Content = "Happiness is just around thecorner!";thirdCI.Keyword = "positiveComments";ContentRotator1.Items.Add(thirdCI);
// Add dynamiccontentContentRotator1.Items.Add(new ContentItem(string.Empty,"~/RichContent1.ascx", string.Empty, 5));
}}
As you can see, the ContentItem class has a number of constructor overloads that can reduce
creating a newContent
Item
instance and setting its properties down to just a single line of
code.
If you'd rather not read about the code details and would instead prefer to start using the
ContentRotator in your ASP.NET application, feel free to skip the rest of the article and download
the control from the link at the top of this article. The download includes the full source code for
the ContentRotator control (in C#) along with a sample ASP.NET Web application (also in C#) that
shows solutions for the use cases discussed above. Additionally, the download includes a spiffy-
looking compiled help file to assist page developers who decide to use the ContentRotator
control.
Determining the ContentItem to Display
Each time a page with a ContentRotator control is visited, the ContentRotator control must decide
what content item to randomly display. Each content item has an associated impressions value
that influences how likely it is to be selected relative to the other content items. This impressions
parameter is a positive integer value and, if not specified, defaults to a value of 1. Additionally,
each content item can have an optionalkeywordparameter. The ContentRotator control's
KeywordFilter property, if specified, restricts the set of content items that are considered for
display to those content items with a matching keywordvalue.
The algorithm used to randomly choose a content item works by laying out each applicable
content item end-to-end, forming a line. The length of each content item is its impressions value,
meaning that the total length of the line is the sum of the applicable content items' impressions.
Next, a random number less than the total length is chosen, and the content item to display is the
one that lies at the location of the random number. Figure 1 illustrates this algorithm graphically.
-
8/7/2019 Building a ContentRotator ASP
9/17
Figure 1. (Click to enlarge)
In order to apply this algorithm the ContentRotator control first needs to retrieve the list of
content items for consideration. Recall that this list may reside on disk as an XML file, be specified
in the ContentRotator's declarative syntax, or be provided programmatically. Let's examine how
this list of content items can be accessed for each of these three techniques.
Reading Content Data from the Content File
The ContentRotator has an Items property of type ContentItemCollection that contains the
set of applicable content items considered by the ContentRotator control. (Recall that the set of
applicable content items depends on whether the control'sKeywordFilter property is set and,if it is, the keywordparameters of the content items.) This Items property is populated in the
Load event by a call to the GetFileData(virtualFilePath) method. This method returns a
ContentItemCollection instance that containsall the content items in the content file
specified by the virtualFilePath parameter.
Opening, reading, and parsing the entire content file on each and every page visit would be
inefficient and unnecessary, especially considering that the file is likely to be changed
infrequently. To improve performance, the items in the content file are cached using a file
dependency. This means that the items in the content file will reside in the cache for improved
performance, but the cache item will be invalidated automatically when the underlying content
file is modified. The following code from the GetFileData(filePath) method illustrates thiscaching behavior:
// See if the item exists in the cachestringcacheKey = string.Concat("ContentRotateCacheKey:",physicalFilePath);
ContentItemCollectioncachedContent = (ContentItemCollection)HttpContext.Current.Cache[cacheKey];if (cachedContent == null){
// it's *not* in the cache, must manually get the file data andcache itcachedContent = LoadFile(physi
calFilePath);if (cachedContent == null)
return null;else
// Add the content to the cacheHttpContext.Current.Cache.Insert(cacheKey, cachedContent,newCacheDependency(physicalFilePath));}
// return the cached content
-
8/7/2019 Building a ContentRotator ASP
10/17
returncachedContent;
The variable physicalFilePath contains the physical path to the content file, and is used in
forming the cache key. This ensures that each unique content file will have its own cache entry.
Next, the Cache object is accessed, retrieving the value of the cache item named cacheKey. If
this item is nulleither because no such item has been inserted into the cache or the cache
item has become invalidatedthe contents from the content file are loaded and inserted into the
cache along with a cache dependency based on the content file.
The LoadFile(physicalFilePath) method iterates through the content file using an
XPathNodeIterator, stripping out the various attributes and text content and building up a
ContentItem instance for each item in the content file. EachContentItem instance is added to
a ContentItemCollection, which is returned at the conclusion of the method. The following
code shows the iteration through each item in the content file;fStream is an opened file stream
to the content file.
// Use an XPathNavigator to iterate through the XML elements in the
ContentFilereader = new XmlTextReader(fStream);XPathDocumentxpDoc = new XPathDocument(reader);XPathNavigatorxpNav = xpDoc.CreateNavigator();
XPathNodeIteratorxmlItems = xpNav.Select("/contents/content");
XPathExpressioncontentExpr = xpNav.Compile("string(text())");XPathExpressioncontentPathExpr = xpNav.Compile("string(@contentPath)");XPathExpressionkeywordExpr = xpNav.Compile("string(@keyword)");XPathExpressionimpressionsExpr = xpNav.Compile("string(@impressions)");
if (xmlItems == null)
throw new FormatExc
eption("ContentFile in invalid format.");else
{while (xmlItems.MoveNext())
{string content = (string) xmlItems.Current.Evaluate(contentExpr);stringcontentPath = (string)xmlItems.Current.Evaluate(contentPathExpr);string keyword = (string) xmlItems.Current.Evaluate(keywordExpr);stringimpressionsStr = (string)xmlItems.Current.Evaluate(impressionsExpr);
int impressions = 1; // default impressions value is 1if (impressionsStr != null &&impressionsStr.Length> 0)
impressions = Convert.ToInt32(impressionsStr,CultureInfo.InvariantCulture);
contentItems.Add(new ContentItem(content.Trim(),contentPath, keyword, impressions));
}}
-
8/7/2019 Building a ContentRotator ASP
11/17
An XPathNodeIterator steps through each element, applying an
XPathExpression to pick out each attribute and the text content. As each item is
iterated, a ContentItem instance is created and its properties assigned the values from the
XPathExpressions. Each ContentItem instance is added to a ContentItemCollection
instance, which is later returned from the LoadFile(physicalFilePath) method.
Reading Content Data Programmatically
In order to programmatically add items to any type of Web control you need to perform the
following three steps:
1. Create a class that represents the items to be added.2. Create a class that represents a collection of the items.3. Add a property to the Web control of the type of class defined in step 2. This property
holds the set of items for the control.
To see these steps in action, consider the built-in ASP.NET DropDownList Web control, which
consists of a set of items that constitute the DropDownList's available selections. Each item is
represented by an instance of the ListItem class (step 1). The ListItemCollection class
provides a strongly typed collection ofListItem instances (step 2), and the DropDownList
class has an Items property of type ListItemCollection (step 3). From an ASP.NET page's
source code portion, a DropDownList can have ListItem instances programmatically added to it
using syntax like:
DropDownList1.Items.Add(newListItem(text,value));
In order to accomplish similar functionality with the ContentRotator I created the ContentItem
class to represent a particular content item. As discussed earlier, this class has properties specific
to a content item, such as Content, Impressions, and so on. Next, I created aContentItemCollection class that provides a strongly typed collection ofContentItem
instances. Lastly, I created an Items property of type ContentitemCollection in the
ContentRotator class.
With these classes and properties created, a page developer can programmatically add content to
the ContentRotator in syntax not unlike that of the DropDownList:
ContentRotator1.Items.Add(new ContentItem(content));ContentRotator1.Items.Add(new ContentItem(content, contentPath,keyword, impressions));...
Reading Content from the Control's Declarative Syntax
In addition to being able to specify items programmatically, a number of Web controls also
enable the page developer to specify the set of items through the control's declarative syntax. For
example, with the DropDownList the ListItems can be spelled out declaratively like so:
-
8/7/2019 Building a ContentRotator ASP
12/17
text1...
textN
Adding this functionality to the ContentRotator is fairly simple and straightforward since wealready have a ContentItem class defined as well as an Items property for the ContentRotator
control. All we need to do is use two attributes to indicate that the items specified in the
declarative syntax map to the ContentRotator'sItems property.
First, at the class level, add the ParseChildren() attribute, indicating that the child markup
should be parsed and that it maps to the Items property:
[ParseChildren(true, "Items")]publicclass ContentRotator : Control{
...
}
And last, add the PersistenceMode() attribute to the Items property declaration, indicating
that the Items property is to be persisted as the inner, default property.
[PersistenceMode(PersistenceMode.InnerDefaultProperty]publicContentItemCollection Items{get { ... }}
That's all there is to it! With these two attributes, a page developer can specify content items in
the control's declarative syntax like so:
...
One thing to note is that with our current code all properties of the ContentItem instance must
be specified as attributes of the element. Ideally, a page developer would
be able to specify static content through either the Content attribute or as the text content that
appears between the and tags. To accomplish
that we need to add a small bit of code to the ContentItem class indicating how the classshould parse inner text content.
Specifically, the ContentItem class needs to implement the IParserAccessor interface,
which defines a single method, AddParsedSubObject(object). The
AddParsedSubObject(object) method passes in the content of the
element in the declarative syntax. If the inner content is plain text, a LiteralControl instance
-
8/7/2019 Building a ContentRotator ASP
13/17
will be passed in. In this case, we want to assign the LiteralControl'sText property to the
Content property of the ContentItem instance. This is accomplished with the following code:
publicclass ContentItem : IParserAccessor{
...
public void AddParsedSubObject(object obj){
if (obj is LiteralControl)Content = ((LiteralControl) obj).Text;
elsethrow new HttpException(...);
}#endregion
}
Picking a Random Content Item
After the ContentRotator'sItems property has been retrieved in the Load event, the
SelectContentFromItems() method is called. This method returns a randomly selected
ContentItem instance from the Items collection. If the ContentRotator'sKeywordFilter
property is set, it removes the nonapplicable items from the collection. It then determines the
sum of the impressions parameters for the remaining items and chooses a random number
between 0 and the total impressions value minus one.Based on this random number, the
appropriate content item is selected and returned.
The following code shows how, if the KeywordFilter property is set, the nonapplicable items
are removed from consideration and how the sum of impressions is computed. Following this, a
random impressions is selected and the appropriate ContentItem instance is returned.
// Determine the sum of the ImpressionsinttotalWeight = 0, i = 0;stringcontrolsKeywordFilter = this.KeywordFilter;ContentItemCollectionfilteredArray = new ContentItemCollection();
for (i = 0; i
-
8/7/2019 Building a ContentRotator ASP
14/17
totalWeight = 0;
// Now grab the appropriate ContentItem based on randomWeighti = 0;while (i
-
8/7/2019 Building a ContentRotator ASP
15/17
Figure 2. (Click to enlarge)
By default, the ContentRotator will randomly select a content item to display on everypage visit,
including postbacks to the same page. If you want the same randomly retrieved content item
displayed across postbacks, simply set the ContentRotator'sNewContentOnPostbacks to false.
If you are using dynamic content that requires postbackssuch as a User Control that prompts
the user for some input and, on postback, displays detailed information about that inputthen
you will need to set NewContentOnPostbacks to false. If you leave
NewContentOnPostbacks with its default value of true, the ContentRotator might select adifferent content item when the user posts back from the randomly selected User Control,
thereby losing the postback data.
In fact, regardless of whether static or dynamic content is loaded, the ContentRotator's control
hierarchy has its view state disabled if the NewContentOnPostbacks property is set to true.
This is because on postback the ContentRotator might choose a different content item to display
from the page's previous visit. If the ContentRotator did not disable view state in this case, an
-
8/7/2019 Building a ContentRotator ASP
16/17
exception would be thrown during the load view state stage if a different content item had been
randomly selected. If, however, the NewContentOnPostbacks property is set to false, the view
state for the ContentRotator's control hierarchy is maintained.
Note For more information on loading User Controls programmatically with the
LoadControl() method, be sure to read my earlier article,An Extensive Examination of User
Controls. Information regarding view state and related issues can be found in Understanding
ASP.NET View State.
Customizing the Selected Content Item
One of the feature requirements of the ContentRotator was to allow a page developer to specify
dynamic placeholders in a content item. For example, a page developer should be able to create a
content item with the content text "The current time is [[time]]," and have the [[time]] placeholder
dynamically replaced by the current system time. I deduced that there were two approaches I
could take to solving this problem:
1. Provide a predefined set of placeholders that could be used for dynamic replacement.2. Allow the page developer to decide what placeholders to use and what values to replace
them with.
The first option would be the easier of the two to implement: I could just have a check in the
Load event of the ContentRotator control that methodically replaced all predefined placeholders
in the selected content item with their corresponding dynamic values. While this approach would
be easy to implement, it would not afford the page developer nearly the level of customizability I
thought he deserved.
Therefore, I placed the onus of defining placeholders and injecting dynamic values squarely on
the shoulders of the page developer. A page developer can make up whatever placeholders he'd
like to, adding them into the text content of the content items in the content file or through the
declarative syntax. All I needed to do was provide a mechanism for the page developer to tap into
the selected content item. I did this by having the ContentRotator expose a ContentCreated
event. This event is fired on each page visit whenever the content item to display is selected.
A page developer can create an event handler for this event. In the event handler, the page
developer will receive the ContentItem instance that was selected for display. At this point, the
text of the content item can be searched for placeholders to be replaced with their dynamic
values. The following example illustrates this behavior. The ContentRotator has three content
items defined via the declarative syntax, two with dynamic placeholders.
-
8/7/2019 Building a ContentRotator ASP
17/17
In the code-behind class of the ASP.NET page an event handler is created and wired up to the
ContentRotator'sContentCreated event. The second parameter to this event handler is of type
ContentCreatedEventArgs, which contains the selected ContentItem instance in its
ContentItem property. As the following code shows, the event handler replaces any instances of
[[time]] with the current system time and any instances of [[url]] with the current page's URL.
private void ContentRotator1_ContentCreated(object sender,skmContentRotator.ContentCreatedEventArgs e){
// Replace [[time]] with DateTime.Now.TimeOfDaye.ContentItem.Content = e.ContentItem.Content.Replace("[[time]]",DateTime.Now.TimeOfDay.ToString());
// Replace [[url]] with Request.RawUrle.ContentItem.Content = e.ContentItem.Content.Replace("[[url]]",Request.RawUrl);}
Note The placeholders[[time]] and [[url]] in this exampleare at the page developer's
discretion. That is, the page developer can use whatever names and markup he chooses as
placeholders. Rather than [[time]], for example, we could have used *currentTime* as the
placeholder, replacing all instances of [[time]] with *currentTime* in the content file and event
handler.
Conclusion
With the dot-com boom a fading memory of the past, controls like Microsoft's Ad Rotator are
scurrying away into obscurity. However, the concept of the Ad Rotator is a good one, and there
are many scenarios in which a generic content rotation control would prove invaluable. The
ContentRotator control presented in this article should fit the bill for most of these situations. The
ContentRotator provides similar semantics and syntax to that of the Ad Rotator control, includingan impressions value for content items, keyword filtering, and an event that allows page
developers to tap into the selected content item. In addition, the ContentRotator allows for its
content items to also be specified declaratively and allows for both static and dynamic content.
Happy Programming!