I wrote this custom server control class to demonstrate how easy it is to develop a portable control generating RSS feeds for a content-oriented site. It formats data coming out of a SQL Server database to conform with the RSS 2.0 Specification.
The only requirement is that since this control generates XML data, a page using the control can have no other HTML headers or markup other than the control, and page-level directives, so output caching will still apply to the XML-based data. For example, this would be the code in a client page, like an .ASPX or .ASCX file:
There's some room for improvement, which is very easily done, notably in the following areas:
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace RSSFeed
{
/// <summary>
/// This custom server control grabs data from KUAM.COM to be used as an RSS feed for headlines.
/// This control requires removing all of the HTML headers from a page (no content). Therefore, the only
/// things that can be on the page are the control itself and any page-level directives.
/// </summary>
[DefaultProperty("Text"),ToolboxData("<{0}:rssgenerator runat=server></{0}:rssgenerator>")]
public class rssgenerator : System.Web.UI.WebControls.WebControl
{
// data members
private string _sql;
private string _serverName;
private string _url;
// public properties
[Bindable(true),Category("Data"),DefaultValue("")]
public string SQLString
{
get {return this._sql;}
set {this._sql = value;}
}
[Bindable(true),Category("Data"),DefaultValue("")]
public string Server
{
get {return this._serverName;}
set {this._serverName = value;}
}
[Bindable(true),Category("Data"),DefaultValue("{0}")]
public string DataFormatString
{
get {return this._url;}
set {this._url = value;}
}
// get the daily news
private string GetRSSNewsFeed(string server,string sql)
{
SqlConnection conn = new SqlConnection(server);
SqlCommand comm = new SqlCommand(sql,conn);
SqlDataReader dr;
string newsFeedData = string.Empty;
try
{
conn.Open();
dr = comm.ExecuteReader(CommandBehavior.CloseConnection);
newsFeedData += "<!-- RSS Newsfeed custom server control -->\n";
newsFeedData += "<!-- Written by Jason Salas \n Web Development Manager / News Anchor, KUAM News \n jason@kuam.com \n http://weblogs.asp.net/jasonsalas/ \n December 19, 2003 -->\n";
newsFeedData += "<rss version=\"2.0\">\n\t<channel>";
while(dr.Read())
{
// TODO: make the array of DB values come from a string[] array, use boolean operator for data provider
newsFeedData += "\n\t\t<item>\n\t\t\t<title>" + MakeDataXMLSafe(dr.GetString(2)) + "</title>\n\t\t\t<description>";
newsFeedData += CreateAbstract(dr.GetString(4)) + "</description>\n\t\t\t<link>";
newsFeedData += MakeDataXMLSafe(string.Format(DataFormatString,dr.GetInt32(0))) + "</link>\n\t\t\t<author>";
newsFeedData += MakeDataXMLSafe(dr.GetString(3)) + "</author>\n\t\t\t<pubDate>";
newsFeedData += MakeDataXMLSafe(string.Format("{0:D}",dr.GetDateTime(1).ToString())) + "</pubDate>\n\t\t</item>";
}
dr.Close();
newsFeedData += "</channel>\n\t</rss>";
}
catch(SqlException ex)
{
newsFeedData += ex.ToString();
}
catch(Exception ex)
{
newsFeedData += ex.ToString();
}
finally
{
if(conn.State == ConnectionState.Open) conn.Close();
comm.Dispose();
conn.Dispose();
}
return newsFeedData;
}
private string MakeDataXMLSafe(object data)
{
string dataString = data.ToString();
dataString = dataString.Replace("'","'");
dataString = dataString.Replace("\"",""");
dataString = dataString.Replace(">",">");
dataString = dataString.Replace("<","<");
dataString = dataString.Replace("&","&");
return dataString;
}
private string CreateAbstract(string bodyContent)
{
// create an story summary by truncating the BODY field of the DB table
int periodIndex = bodyContent.IndexOf(".");
string finalText = string.Empty;
if(periodIndex < 150)
{
int newPeriodIndex = bodyContent.IndexOf(".",periodIndex+1);
finalText = bodyContent.Substring(0,newPeriodIndex);
}
else
{
finalText = bodyContent.Substring(0,periodIndex);
}
return finalText + " ... ";
}
protected override void OnInit(EventArgs e)
{
// set the MIME type for the page in which the control sits to XML
this.Context.Response.ClearContent();
this.Context.Response.ClearHeaders();
this.Context.Response.ContentType = "text/xml";
}
protected override void Render(HtmlTextWriter output)
{
output.Write(GetRSSNewsFeed(_serverName,_sql));
}
}
}