Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

RSS Feed Aggregator and Blogging Smart Client

, 16 Aug 2005 CPOL
RSS Feed aggregator and blogging Smart Client which uses Enterprise Library, Updater Application Block, lots of XML hacks and desktop tricks. A comprehensive guide to real life hurdles of Smart Client development.
rssfeeder_src.zip
RSSFeeder
RSSBlogAPI
RSSBlogAPI.csproj.user
Web References
CommunityServer
blogservice.disco
blogservice.wsdl
Reference.map
DotText
Reference.map
simpleblogservice.disco
simpleblogservice.wsdl
RSSCommon
Helper
PropertyEditor
RSSCommon.csproj.user
RSSFeeder
Controls
docs
dropshadow.png
My Pic 7.jpg
WIndows98.jpg
Helpers
Resources
E-mail.ico
rss.ico
RSSFeeder.mdb
RSSFeeder.csproj.user
RSSStarter.exe
RSSFeederResources
PublicQueue.ico
RSSFeeder.mdb
RSSFeederResources.csproj.user
RSSFeederSetup
Messages.ico
RSSFeederSetup.vdproj
Test
RSSStarter
DummyForm.frm
DummyForm.frx
MainModule.bas
RSSStarter.exe
RSSStarter.vbp
RSSStarter.vbw
RSSTests
App.ico
RSSTests.csproj.user
Thirdparty
AxInterop.DHTMLEDLib.dll
AxInterop.SHDocVw.dll
Eyefinder.dll
GotDotNet.Exslt.dll
HttpDownloader.dll
Interop.DHTMLEDLib.dll
Interop.SHDocVw.dll
Interop.WindowsInstaller.dll
Microsoft.ApplicationBlocks.Updater.ActivationProcessors.dll
Microsoft.ApplicationBlocks.Updater.dll
Microsoft.ApplicationBlocks.Updater.Downloaders.dll
Microsoft.Practices.EnterpriseLibrary.Caching.dll
Microsoft.Practices.EnterpriseLibrary.Common.dll
Microsoft.Practices.EnterpriseLibrary.Configuration.dll
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.dll
Microsoft.Practices.EnterpriseLibrary.Logging.dll
Microsoft.Practices.EnterpriseLibrary.Security.Cache.CachingStore.dll
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
Microsoft.Practices.EnterpriseLibrary.Security.dll
NotifyIconBalloon.dll
SandBar.dll
SandDock.dll
SgmlReaderDll.dll
// Copyright � 2005 by Omar Al Zabir. All rights are reserved.
// 
// If you like this code then feel free to go ahead and use it.
// The only thing I ask is that you don't remove or alter my copyright notice.
//
// Your use of this software is entirely at your own risk. I make no claims or
// warrantees about the reliability or fitness of this code for any particular purpose.
// If you make changes or additions to this code please mark your code as being yours.
// 
// website http://www.oazabir.com, email OmarAlZabir@gmail.com, msn oazabir@hotmail.com
using System;

using System.Xml.Serialization;
using System.ComponentModel;
using System.Drawing.Design;

namespace RSSCommon
{
	using PropertyEditor;
	
	/// <summary>
	/// Holds configuration informatino of a subscribed channel 
	/// </summary>
	
	[System.Xml.Serialization.XmlRoot(Namespace="")]
	[System.Xml.Serialization.XmlTypeAttribute("channel")]
	[Serializable]
	[TypeConverter(typeof(ExpandableObjectConverter))]	
	public class Channel
	{
		#region Events

		///<summary>A PropertyChanged event is raised when a property is changed on a component. A PropertyChangedEventArgs object specifies the name of the property that changed.</summary>
		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		#region Private Fields

		private int _Id;
		private string _Title;
		private Uri _FeedUrl;
		private TimeSpan _Frequency;
		private DateTime _LastUpdated;
		private DateTime _NextUpdate;
		private DateTime _LastUpdatedInOutlook;
		private string _FolderPath;
		private string _XSLPath;
		private bool _ShowInNewspaper;
		private int _ItemCount;
		private int _UnreadCount;
		//private bool _StoreInOutlook;

		#endregion

		#region Public Properties

		#region Store in outlook
		/*
		/// <summary>If true, this channel is stored in outlook</summary>
		[Category("Outlook"), 
		Description(@"If true, this channel is stored in outlook")]
		[XmlElement("storeInOutlook")]
		public bool StoreInOutlook
		{
			get
			{
				return this._StoreInOutlook;
			}
			set
			{
				bool changed = !object.Equals(this._StoreInOutlook, value);
				this._StoreInOutlook = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.StoreInOutlook));
			}
		}
		*/
		#endregion

		#region Outlook Folder Type
		
		public enum FolderCreationTypeEnum
		{
			Automatic_under_Base_Folder = 0,
			Specific_Folder
		}
		
		private FolderCreationTypeEnum _FolderType;

		/// <summary>
		/// How folder will be created for this channel
		/// </summary>
		[Category("Outlook"), 
		Description(@"How folder will be created for this channel")]
		[XmlElement("folderType")]
		public FolderCreationTypeEnum FolderType
		{
			get
			{
				return this._FolderType;
			}
			set
			{
				bool changed = !object.Equals(this._FolderType, value);
				this._FolderType = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.FolderType));

				// Set back to default folder name if automatic selected
				if( FolderCreationTypeEnum.Automatic_under_Base_Folder == this._FolderType )
				{
					this.FolderPath = Configuration.Instance.OutlookBaseFolder + "\\" + this.GetFolderName();
				}
				else
				{
				}
			}
		}

		#endregion

		#region Unread Count

		/// <summary>
		/// Number of unread messages
		/// </summary>
		[Category("Misc"), ReadOnly(true),
		Description(@"Number of unread messages")]
		[XmlElement("unreadCount")]
		public int UnreadCount
		{
			get
			{
				return this._UnreadCount;
			}
			set
			{
				bool changed = !object.Equals(this._UnreadCount, value);
				this._UnreadCount = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.UnreadCount));
			}
		}
		
		#endregion

		#region Database ID

		/// <summary>
		/// Internal database Id
		/// </summary>
		[Category("Misc"), ReadOnly(true),
		Description(@"Internal ID of the channel")]
		[XmlElement("id")]
		public int Id
		{
			get
			{
				return this._Id;
			}
			set
			{
				bool changed = !object.Equals(this._Id, value);
				this._Id = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.Id));
			}
		}

		#endregion

		#region Item Count
        
		/// <summary>
		/// Number of items in this channel
		/// </summary>
		[Category("Misc"), ReadOnly(true),
		Description(@"Number of items in this channel")]
		[XmlElement("itemCount")]
		public int ItemCount
		{
			get
			{
				return this._ItemCount;
			}
			set
			{
				bool changed = !object.Equals(this._ItemCount, value);
				this._ItemCount = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.ItemCount));
			}
		}
		
		#endregion

		#region Outlook View XML Path

		private string _OutlookViewXmlPath;

		/// <summary>Path to an Outlook View XML file which is applied to this folder</summary>
		[Category("Outlook"), 
		Description(@"Path to an Outlook View XML file which is applied to this folder")]
		[XmlElement("outlookViewXmlPath")]
		[Editor(typeof(UIFileDialogEditor), typeof(UITypeEditor)),
		CommonDialogFilterAttribute("XML File (*.xml)|*.xml")]
		public string OutlookViewXmlPath
		{
			get
			{
				return this._OutlookViewXmlPath;
			}
			set
			{
				bool changed = !object.Equals(this._OutlookViewXmlPath, value);
				this._OutlookViewXmlPath = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.OutlookViewXmlPath));
			}
		}
		#endregion

		#region Outlook XSL

		private string _OutlookXSL;

		/// <summary>Path to an XSL file which is used to transform feeds to HTML format for Outlook posts</summary>
		[Category("Outlook"), 
		Description(@"Path to an XSL file which is used to transform feeds to HTML format for Outlook posts")]
		[XmlElement("outlookXSL")]
		[Editor(typeof(UIFileDialogEditor), typeof(UITypeEditor)),
		CommonDialogFilterAttribute("XSLT File (*.xslt)|*.xslt|XSL File (*.xsl)|*.xsl")]		
		public string OutlookXSL
		{
			get
			{
				return this._OutlookXSL;
			}
			set
			{
				bool changed = !object.Equals(this._OutlookXSL, value);
				this._OutlookXSL = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.OutlookXSL));
			}
		}
		#endregion

		#region Channel Title

		/// <summary>The name of the channel. It's how people refer to your service. 
		/// If you have an HTML website that contains the same information as your RSS file, 
		/// the title of your channel should be the same as the title of your website.</summary>
		[Category("Channel"), 
		Description(@"The name of the channel. It's how people refer to your service. If you have an HTML website that contains the same information as your RSS file, the title of your channel should be the same as the title of your website.")]
		[XmlElement("title")]
		public string Title
		{
			get
			{
				return this._Title;
			}
			set
			{
				bool changed = !object.Equals(this._Title, value);
				this._Title = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.Title));
			}
		}
		#endregion

		#region Feed URL

		/// <summary>URL of the RSS Feed from where the feed is downloaded</summary>
		[Category("Source"), 
		Description(@"RSS feed URL from where the feed is downloaded. It can be a local file, or a remote server.
		Please use http:// for web URL.")]
		[XmlElement("feedURL")]
		public Uri FeedURL
		{
			get
			{
				return this._FeedUrl;
			}
			set
			{
				bool changed = !object.Equals(this._FeedUrl, value);
				this._FeedUrl = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.FeedURL));
			}
		}
		
		#endregion

		#region Download Frequency

		/// <summary>Frequency of downloading this feed</summary>
		[Category("Download"), 
		Description(@"Frequency of feed synchronization. For example, if it is 30 mins, then it will be snchronized every 30 mins")]
		[XmlElement("frequency")]
		public TimeSpan Frequency
		{
			get
			{
				return this._Frequency;
			}
			set
			{
				bool changed = !object.Equals(this._Frequency, value);
				this._Frequency = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.Frequency));
			}
		}

		#endregion

		#region Last Updated

		/// <summary>Last update date when the feed was downloaded</summary>	
		[Category("Download"), ReadOnly(true),
		Description(@"Last update date when the feed was downloaded from the server")]
		[XmlElement("lastUpdated")]
		public DateTime LastUpdated
		{
			get
			{
				return this._LastUpdated;
			}
			set
			{
				bool changed = !object.Equals(this._LastUpdated, value);
				this._LastUpdated = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.LastUpdated));

				// Update next update time
				this.NextUpdate = this.LastUpdated.Add( ( this.Frequency == TimeSpan.Zero ? 
					TimeSpan.FromMinutes( Configuration.Instance.DefaultDownloadFrequency ) : this.Frequency ) );
			}
		}

		#endregion
		
		#region Next Update Date Time

		/// <summary>Next update date when the feed will be downloaded</summary>
		[Category("Download"), ReadOnly(true),
		Description(@"Next update date when the feed will be downloaded from the server")]
		[XmlElement("nextUpdate")]
		public DateTime NextUpdate
		{
			get
			{
				return this._NextUpdate;
			}
			set
			{
				bool changed = !object.Equals(this._NextUpdate, value);
				this._NextUpdate = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.NextUpdate));
			}
		}
		
		#endregion

		#region Last Updated In Outlook

		/// <summary>Last time when outlook received the RSS feeds</summary>
		[Category("Outlook"), ReadOnly(true),
		Description(@"Last time when outlook received the RSS feeds")]
		[XmlElement("lastUpdatedInOutlook")]
		public DateTime LastUpdatedInOutlook
		{
			get
			{
				return this._LastUpdatedInOutlook;
			}
			set
			{
				bool changed = !object.Equals(this._LastUpdatedInOutlook, value);
				this._LastUpdatedInOutlook = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.LastUpdatedInOutlook));
			}
		}

		#endregion
		
		#region Folder path

		/// <summary>Outlook folder path where RSS Feeds are stored</summary>
		[Category("Outlook"), 
		Description(@"Outlook folder path where RSS Feeds are stored")]
		[XmlElement("folderPath")]
		[Editor(typeof(UIOutlookFolderPickerEditor), typeof(UITypeEditor))]
		public string FolderPath
		{
			get
			{
				return this._FolderPath;
			}
			set
			{
				bool changed = !object.Equals(this._FolderPath, value);
				this._FolderPath = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.FolderPath));
			}
		}
		#endregion

		#region XSL Path
		/// <summary>XSL used to convert RSS XML to HTML</summary>
		[Category("Outlook"), 
		Description(@"XSL used to convert RSS XML to HTML")]
		[XmlElement("xslPath")]
		[Editor(typeof(UIFileDialogEditor), typeof(UITypeEditor)),
		CommonDialogFilterAttribute("XSLT File (*.xslt)|*.xslt|XSL File (*.xsl)|*.xsl")]
		public string XSLPath
		{
			get
			{
				return this._XSLPath;
			}
			set
			{
				bool changed = !object.Equals(this._XSLPath, value);
				this._XSLPath = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.XSLPath));
			}
		}
		#endregion

		#region Show In Newspaper
		/// <summary>Whether this channel appears in newspaper</summary>
		[Category("Outlook"), 
		Description(@"Whether this channel appears in newspaper")]
		[XmlElement("showInNewsPaper")]
		public bool ShowInNewspaper
		{
			get
			{
				return this._ShowInNewspaper;
			}
			set
			{
				bool changed = !object.Equals(this._ShowInNewspaper, value);
				this._ShowInNewspaper = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.ShowInNewspaper));
			}
		}
		#endregion

		#region No of items in newspaper

		private int _NumberOfItemsInNewspaper = 5;
		/// <summary>Number of items to show in newspaper</summary>
		[Category("Newspaper"), 
		Description(@"Number of items to show in newspaper")]
		[XmlElement("newspaperItemCount")]
		public int NumberOfItemsInNewspaper
		{
			get
			{
				return this._NumberOfItemsInNewspaper;
			}
			set
			{
				bool changed = !object.Equals(this._NumberOfItemsInNewspaper, value);
				this._NumberOfItemsInNewspaper = value;
				if(changed) OnPropertyChanged(new PropertyChangedEventArgs(Properties.NumberOfItemsInNewspaper));
			}
		}
		#endregion

		#endregion

		#region Constructor

		public Channel()
		{
			this._Title = string.Empty;
			this._FeedUrl = null;
			this._Frequency = TimeSpan.Zero;
			this._LastUpdated = DateTime.MinValue;
			this._NextUpdate = DateTime.MinValue;

			this._LastUpdatedInOutlook = DateTime.MinValue;
			this._ShowInNewspaper = false;
			this._FolderPath = string.Empty;
			this._XSLPath = string.Empty;

			this._FolderType = FolderCreationTypeEnum.Specific_Folder;
		}

		public Channel( int id, string title, Uri feedUrl, TimeSpan frequency, DateTime lastUpdated, 
			DateTime nextUpdate, DateTime lastUpdateInOutlook, string folderPath, string xslPath,
			bool showInNewspaper, int itemCount, int unreadCount, FolderCreationTypeEnum folderType,
			string outlookViewXmlPath, string outlookXSL )
		{
			this._Id = id;
			this._Title = title;
			this._FeedUrl = feedUrl;
			this._Frequency = frequency;
			this._LastUpdated = lastUpdated;
			this._NextUpdate = nextUpdate;

			this._LastUpdatedInOutlook = LastUpdatedInOutlook;
			this._ShowInNewspaper = showInNewspaper;
			this._FolderPath = folderPath;
			this._XSLPath = xslPath;

			this._ItemCount = itemCount;
			this._UnreadCount = unreadCount;

			this.FolderType = folderType;
			this._OutlookViewXmlPath = outlookViewXmlPath;
			this._OutlookXSL = outlookXSL;
		}

		#endregion

		#region Private Methods

		private string GetFolderName()
		{
			char [] name = this.Title.ToCharArray();
			for( int i = 0; i < name.Length; i ++ )
				if( name[i] < ' ' && name[i] > 'z' )
					name[i] = ' ';

			return new string(name);
		}

		///<summary>A PropertyChanged event is raised when a property is 
		///changed on a component. A PropertyChangedEventArgs object 
		///specifies the name of the property that changed.</summary>
		protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
		{	
			if( null != PropertyChanged )
			{
				PropertyChanged(this, e);			
			}
		}

		#endregion

		#region Property Definition

		public class Properties
		{
			public const string NumberOfItemsInNewspaper = "NumberOfItemsInNewspaper";
			public const string OutlookXSL = "OutlookXSL";
			public const string OutlookViewXmlPath = "OutlookViewXmlPath";
			public const string StoreInOutlook = "StoreInOutlook";
			public const string FolderType = "FolderType";
			public const string Id = "Id";
			public const string Title = "Title";
			public const string FeedURL = "FeedURL";
			public const string Frequency = "Frequency";
			public const string LastUpdated = "LastUpdated";
			public const string NextUpdate = "NextUpdate";
			public const string LastUpdatedInOutlook = "LastUpdatedInOutlook";
			public const string FolderPath = "FolderPath";
			public const string XSLPath = "XSLPath";
			public const string ShowInNewspaper = "ShowInNewspaper";
			public const string ItemCount = "ItemCount";
			public const string UnreadCount = "UnreadCount";
		}

		#endregion

		#region Overrides
		
		public override string ToString()
		{
			return this._Title + " (" + this.UnreadCount.ToString() + ")";
		}

		#endregion
	}


	/// <summary>
	/// <see cref="Channel"/> Collection of Channels
	/// </summary>
	[Serializable]
	public class ChannelCollection : System.Collections.CollectionBase
	{		
		/// <summary>Adds an item to the IChannelCollection.</summary>
		public int Add(Channel value)
		{
			return base.List.Add(value as object);
		}
		/// <summary>Removes an item to the ChannelCollection.</summary>
		public void Remove(Channel  value)
		{
			base.List.Remove(value as object);
		}
		/// <summary>Inserts an IChannel to the ChannelCollection at the specified position.</summary>
		public void Insert(int index, Channel  value)
		{
			base.List.Insert(index, value as object);
		}
		/// <summary>Determines whether the ChannelCollection contains a specific value.</summary>
		public bool Contains(Channel  value)
		{
			return base.List.Contains(value as object);
		}
		/// <summary>Gets the IChannel at the specified index.</summary>
		public Channel  this[int index]
		{
			get { return (base.List[index] as Channel ); }
		}		
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

Share

About the Author

Omar Al Zabir
Architect BT, UK (ex British Telecom)
United Kingdom United Kingdom

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150414.1 | Last Updated 16 Aug 2005
Article Copyright 2005 by Omar Al Zabir
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid