Digital Colony!

Add Item to DropDownList After DataBind

We often want the first option in a drop-down list to not default to the first item in the list. Instead we would prefer the option of adding a --Select Item-- at the top of the asp:DropDownList. After the DataBind, execute an Item.Insert.
ddlAuthor.DataTextField = "FullName";
ddlAuthor.DataValueField = "AuthorID";
ddlAuthor.DataSource = authorDB.GetAuthors();
ddlAuthor.DataBind();
ddlAuthor.Items.Insert(0, "-- Select Author --");

Labels: ,

 

Roll Your own Drudge Report in ASP.NET

Matt Drudge is my hero. He started The Drudge Report while working the graveyard shift at 7-11. He was at the store when the newspapers first arrived and most of the world was asleep. He was able to parlay that first access to the news into creating one of the most popular sites on the internet. Read his book Drudge Manifesto if you wish to learn more about his rise to fame.

Unlike Matt Drudge, I have no desire to get up super early and go through endless newspapers to create a hand-edited HTML page of my favorite links. Fortunately for me, we now have RSS feeds. This article will mix the ASP.NET article of the day RSS feed with the Drudge look and feel to create the ASP.NET Report.

Reverse Engineer the Drudge Report

The Drudge Report is basically a 3 column layout with an image logo and a top story link. The layout will vary over time, but that is the usual template. For the 3 column news look, we will use the asp:DataList control.

Drudge Font and Image

The logo was created using the Impact font at 100 points and Italic. In PhotoShop, under Blending Options (right mouse click Text layer), add a Drop Shadow. Play with the color, width and direction of the shadow.

Drudge uses a large upper-case Arial font for the top story and Courier for the 3-column stories. All links are black.
body 
{
    font-family: "Courier New", Courier, monospaced;
    font-size: 10pt; 
    font-weight: bold;
    color: #000;
    background-color: #fff;        
}
#headerDIV
{
    text-align: center;
}
#topstoryDIV
{
    font-size:32pt;
    font-weight:bold;
    font-family: Arial, Verdana, Helvetica;
}    
a:link, a:active, a:visited {
    color:#000;
    text-decoration:underline;
    line-height:1.2;
}

The Code

The RSS feed is loaded into an XmlDocument. The first story in the RSS feed will be designated the top story. The rest of the stories will be loaded into a DataTable which is binded to the asp:DataList.

Since ASP.NET code tends not to be photogenic, I've hard-coded links to some of my vacation photos for the top image. To mix it up a little, it will change depending upon the day of the week.
DataTable dt = new DataTable();
dt.Columns.Add("title", Type.GetType("System.String"));
dt.Columns.Add("link", Type.GetType("System.String"));

// ASP.NET Article of the Day
string rssURL = "http://asp.net/community/articles/rss.ashx";

XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
doc.Load(rssURL);

// display a different image based upon day of week
int dayOfWeek = (int)DateTime.Now.DayOfWeek;

switch (dayOfWeek)
{
    case 0:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/117793421-S.jpg";
        break;
    case 1:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/118708221-S.jpg";
        break;
    case 2:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/95113678-S.jpg";
        break;
    case 3:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/91872258-S.jpg";
        break;
    case 4:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/91842649-S.jpg";
        break;
    case 5:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/79938653-S.jpg";
        break;
    default:
        imgHeader.ImageUrl = "http://criticalmas.smugmug.com/photos/92103181-S.jpg";
        break;
}        

XmlNode oNode = doc.DocumentElement;
XmlNodeList oNodeList = oNode.SelectNodes("channel/item");

for (int itemCount = 0; itemCount < oNodeList.Count; itemCount++)
{
    string title = oNodeList[itemCount].SelectSingleNode("title").InnerText;
    string link = oNodeList[itemCount].SelectSingleNode("link").InnerText;

    if (itemCount == 0)
    {
        // top story
        hypTopStory.Text = title.ToUpper();
        hypTopStory.NavigateUrl = link;
    }
    else
    {
        DataRow dr = dt.NewRow();
        dr["title"] = title;
        dr["link"] = link;
        dt.Rows.Add(dr);
    }
}
dlStories.DataSource = dt;
dlStories.DataBind();

The ASP.NET Page

<form id="form1" runat="server">
<div id="parentDIV">
<p><a href="/">Return to Digital Colony</a></p>
    <div id="headerDIV" >
        <asp:Image ID="imgHeader" runat="server" Width="400" Height="300" BorderWidth="1" />
        <div id="topstoryDIV"><asp:HyperLink ID="hypTopStory" runat="server" /></div>
        <img src="aspnet-report.gif" width="716" height="137" alt="ASP.NET Report" />
    </div>
    <div id="storiesDIV">
    <asp:DataList ID="dlStories" runat="server" RepeatColumns="3" Width="100%" CellPadding="5">
        <ItemTemplate>
          <a href="<%# Eval("link") %>"><%# Eval("title") %></a>
          <hr />
        </ItemTemplate>            
    </asp:DataList>
    </div>        
</div>
</form>

Caching

When pulling RSS feeds, it is wise to be considerate of the bandwidth of your host site. Don't pull a fresh feed with every Page Load. Add an OutputCache directive to your page. For the ASP.NET Report example, I know that this feed updates daily, so I can set the Duration to 86400 which is the number of seconds in one day.
<%@ OutputCache Duration="86400" VaryByParam="none" %>

Working Demo

Visit my ASP.NET Report web page.

Better Than Drudge

Unlike The Drudge Report which uses awful HTML, our ASP.NET version is both XHTML and CSS compliant. It also validates under Section 508.

Your Drudge Report

If you create your own version using a different RSS feed, share it by adding a comment with a link to your page.

UPDATE JULY 2007: Microsoft moved the URL to the ASP.NET RSS feed and now restricts it to 10 articles. This makes it look silly in the Drudge format, but at least it working again. An ideal number of posts in an RSS feed for the Drudge look would be around 40.

Labels: , , , ,

 

Converting HTML to XHTML Programmatically in .NET

The Pro Version of FreeTextBox has a neat feature that will clean up poorly written HTML to a cleaner XHTML.
FreeTextBoxControls.FreeTextBox ftb = new FreeTextBoxControls.FreeTextBox();
string html = "<P><img src=joe.gif width=200 height=100 vspace=10>";
ftb.Text = html;
string xhtml = ftb.Xhtml;

Trace.Write("HTML", html);
Trace.Write("XHTML", xhtml);

Before and After

<P><img src=joe.gif width=200 height=100 vspace=10>
<p>
<img src="joe.gif" width="200" height="100" vspace="10" />
</p>
The FreeTextBox closed the paragraph tag, made the paragraph tag lower-case, added quotes to all the attributes and closed the img tag to make the entire string XML compliant. What this control didn't do was replace the deprecated vspace attribute with it's CSS equivalent.

Labels: , , ,

 

COM Informant for Classic ASP

I currently do business with 4 different web hosts. Each of them has a different subset of 3rd-party ASP components installed on their server. Sometimes they are open with which components are installed, sometimes they aren't. Whenever I wanted to test to see if a particular COM object was available, I'd write a quick script. The script would try to create the object via the Server.CreateObject method and then I'd go to the page to see if it returned an error code. No error code meant it was installed and I could start coding my application around that knowledge.

Tedious and Repetitive

After about the 10th script I wrote, it hit me that there probably is a better way to do this. What was needed was a script that tested the most common ASP components and allowed the user to quickly add new ones to the list. Having a bunch of test scripts lying on the file server wasn't optimal. And the last thing you would want is to hard-code all the test cases inside your ASP code. My solution was to have a single page handle the creation, modification, and display of component test cases. The data source would be a single XML file.

Sample comlist.xml file

<?xml version="1.0"?> 
<comlist> 
<com company="Microsoft" name="CDONTS" id="CDONTS.NewMail"/> 
<com company="Persit Software Inc." name="ASPUpload" id="Persits.Upload"/> 
</comlist>

Developers Tool

COM Informant is handy tool to have if your development team creates custom components and then deploys them across multiple servers. What better way to test if a component is installed than viewing a single web page. The top portion of the tool allows the user to add any component name to test list.

screen shot

The Download

COM Informant For Classic ASP consists of sniff.asp, comlist.xml, com.css, and blue.gif. This tool will be ready to run after download. You need to be running IIS in order to download and run COM Informant. Also, if you want to add or delete components from the list, then the comlist.xml file must reside in a directory that has read/write permission. You can modify the location of that file within the first 3 lines of code. The code performs some XML file manipulation, which is outside the scope of this article.

This article was first written in 2001

Labels: , ,

 

Update Fails on FormView

After a miserable afternoon chasing down this bug, I thought it may be helpful to step through why a database update could fail when using the asp:FormView control.

Symptoms

  1. The Database Connection String works, because the "Get" is displaying the record.
  2. The Stored Procedure works, because you ran it inside the database using dummy values.
  3. You stepped through the wizard to build both the asp:SqlDataSource and asp:FormView controls.
  4. When you modify a record and click the Update link, the record stays the same. No error is thrown and no changes are made to the database.

Try This

If this is your situation, then you may have the same problem I ran into. Only after I setup debugging in the stored procedure itself did I realize that the asp:FormView was returning a NULL as the primary key. And if a NULL is passed to an UPDATE stored procedure it will execute error free with an updated ROWCOUNT of zero.

My fix was to add the primary key to DataKeyNames field on the asp:FormView.
<asp:FormView ID="FormView1" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="AuthorID">

Labels: ,

 

Displaying a SmugMug Gallery with ASP.NET

Back in the day I used to host all my own image galleries on my site. It's a tedious process and you can quickly use up your allocated disk space with today's multi-mega pixel cameras. Fortunately we have companies like SmugMug and Flickr that will host, manage and back-up all our images.

The problem with not hosting photo galleries is you send your audience away from your site over to their server. And your photo galleries develop their own audience which knows nothing about the parent site.

I discovered that using the XmlDataSource and DataList ASP.NET controls you can build a photo gallery on your site while the images stay over on SmugMug using a simple RSS feed.

The XmlDataSource

ASP.NET 2.0 introduced the asp:XmlDataSource control which we will use to connect to the SmugMug RSS feed. The DataFile parameter is the path to the RSS file for that photo gallery. In the snippet below, I hard-coded that value. In the example and lab that value is populated in the code behind. Also important is the XPath parameter. This is the address inside the XML Document that holds the information about each photo.
<asp:XmlDataSource ID="xmlDS" runat="server" XPath="rss/channel/item" 
    DataFile= "http://www.smugmug.com/hack/feed.mg?Type=gallery&Data=1838622&format=rss200" />

The RSS Feed (XML Document)

Here is a snippet of how a single photo is represented inside the XML Document. I've removed the portion which deals with the gallery name, as it is not used in this example. In this example the 2 values that are used when rendering the gallery inside the DataList will be link and guid.
<item>
    <title>Image Title</title>
    <link>http://criticalmas.smugmug.com/gallery/1838622/1/92083732</link>
    <description>Image description</description>
    <category>Vacation</category>
    <comments>http://criticalmas.smugmug.com/comment.mg...</comments>
    <exif:DateTimeOriginal>2006-08-24 19:07:19</exif:DateTimeOriginal>
    <pubDate>Thu, 31 Aug 2006 19:02:05 -0700</pubDate>
    <author>feeds-nobody@smugmug.com (criticalmas)</author>
    <guid isPermaLink="true">http://criticalmas.smugmug.com/photos/92083732-Th.jpg</guid>
    <enclosure url="http://criticalmas.smugmug.com/photos/92083732-Th.jpg" length="7741" type="image/jpeg"/>
</item>

The DataList Control

For this gallery, I set the RepeatColumns to 6 and just displayed the thumbnail image with a link to the full-sized image back on the SmugMug web site.
<asp:DataList ID="dlPhotos" runat="server" RepeatColumns="6">
<ItemTemplate>
  <a href="<%# XPath("link").ToString() %>">
     <asp:Image ID="img" ImageUrl='<%# XPath("guid") %>' runat="server"  /></a>
</ItemTemplate>
</asp:DataList>

Sample ASPX Using a Gallery Dropdown

The GalleryID is pulled from the URL of the photo gallery over on SmugMug. This is covered in detail in the sample lab.
<asp:XmlDataSource ID="xmlDS" runat="server" XPath="rss/channel/item" />
<h4>Select Gallery</h4>
<asp:DropDownList ID="ddlGallery" runat="server" AutoPostBack="true">
    <asp:ListItem Text="1838622: Uruguay - Colonia" Value="1838622" />
    <asp:ListItem Text="2473610: Lower Hellhole Canyon Desert Hike" Value="2473610" />
    <asp:ListItem Text="1887671: New Zealand - Whakarewarewa Thermal Village" Value="1887671" />
</asp:DropDownList>
<br /><br />
<asp:DataList ID="dlPhotos" runat="server" RepeatColumns="6">
<ItemTemplate>
    <a href="<%# XPath("link").ToString() %>">
        <asp:Image ID="img" ImageUrl='<%# XPath("guid") %>' runat="server" /></a>
</ItemTemplate>
</asp:DataList>
<asp:Label ID="lblError" Visible="false" runat="server" />

And the Code Behind (C#)

protected void Page_Load(object sender, EventArgs e)
{
   string rssURL;
   string galleryID;
   galleryID = ddlGallery.SelectedValue.ToString();
   rssURL = "http://www.smugmug.com/hack/feed.mg?Type=gallery&Data=" + galleryID + "&format=rss200";

   try
   {
       xmlDS.DataFile = rssURL;
       dlPhotos.DataSource = xmlDS;
       dlPhotos.DataBind();
   }
   catch (XmlException err)
   {
       lblError.Text = "Oops, looks like an error occured with this gallery: " + err.Message;
       lblError.Visible = true;            
   }   
}

Lab Demo

SmugMug Image Gallery in ASP.NET

The gallery uses a simple 6 column layout. Once you have the RSS feed, you can be as creative as you like in designing the layout for your photo gallery.

Other Gallery options

This demo is for the standard galleries. SmugMug has other Feed options described here.

My SmugMug referral code is: IzodUqeQndZYc
It will save you $5 on any new account.

Labels: , , , , , ,

 

Digital Colony Copyright © 1999-2008 XHTML   508
This site uses Blogger, which is not 100% XHTML compliant.
Try...Catch Disclaimer: For brevity many examples do not include error handling. That is your responsibility.