Thursday, January 31, 2008

dnrtv It is time for another personal project for me and this time I thought I would put together a dnrTV feed aggregator. Rather than watch each episode on my home computer, I prefer to watch them on the big screen TV in the living room. They are very viewable and I can sit in my lazy boy with the remote, a beer and maybe the laptop. ( mostly the remote and a beer )

In order to make this happen, I download each show to my Home Server and watch it via my Xbox 360 in the living room. The Xbox 360 acts as a media extender for any movie, music or picture I have stored on my network.

Basically, this software should run as a windows service on my Home Server and check the feed about once a week, download the show, unzip it,  and place the in the proper shared video directory. In order to change settings and monitor the health of the application, I want to create a winform application that will reside on my personal computer's system tray and communicate via some means to the service. Right now, I am leaning towards named pipes.  Our first Step is to create a Windows Service Project.

 

sshot-5

Next we will rename our service to 'dnrTVService' and then we will need to add an Installer Project to our solution. Let's name it 'dnrTVInstaller' and add the following code:

 

   1:  using System.ComponentModel;
   2:  using System.Configuration.Install;
   3:  using System.ServiceProcess;
   4:   
   5:  namespace dnrTVAggregator
   6:  {
   7:      [RunInstaller(true)]
   8:      public partial class dnrTVInstaller : Installer
   9:      {
  10:          public dnrTVInstaller()
  11:          {
  12:              InitializeComponent();
  13:   
  14:              ServiceProcessInstaller ProcessInstaller = new ServiceProcessInstaller();
  15:              ServiceInstaller Installer = new ServiceInstaller();
  16:   
  17:              ProcessInstaller.Account = ServiceAccount.LocalSystem;
  18:              ProcessInstaller.Username = null;
  19:              ProcessInstaller.Password = null;
  20:   
  21:              Installer.ServiceName = "dnrTV_Service";
  22:              Installer.Description = "Service to download new episodes of dnrTv to my Home Server";
  23:              Installer.StartType = ServiceStartMode.Manual;
  24:              Installer.DisplayName = "dnrTv Aggregator Service";
  25:   
  26:              this.Installers.Add(ProcessInstaller);
  27:              this.Installers.Add(Installer);
  28:          }
  29:      }
  30:  }

 

Here we setup the name of our service, it's description and display name. We also decide whether or not it will start manually or automatically. Without this installer project, you will not be able to use INSTALLUTL.EXE to install your service.  Next, let's go back to our service and make it do something. For the time being, let's just have it report the current date and time via a named pipe. We will use a System.Timer and throw an event every 10 seconds. 

 

   1:  using System;
   2:  using System.Diagnostics;
   3:  using System.IO;
   4:  using System.IO.Pipes;
   5:  using System.ServiceProcess;
   6:  using System.Timers;
   7:   
   8:  namespace dnrTVAggregator
   9:  {
  10:      public partial class dnrTVService : ServiceBase
  11:      {
  12:          Timer MyTimer = new Timer(10000);
  13:          public dnrTVService()
  14:          {
  15:              InitializeComponent();
  16:              MyTimer.AutoReset = true;
  17:              MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
  18:          }
  19:   
  20:          void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
  21:          {
  22:              NamedPipeClientStream  np = new NamedPipeClientStream(".", "test_pipe", PipeDirection.InOut);
  23:              np.Connect();
  24:              
  25:              using (StreamWriter w = new StreamWriter(np))
  26:              {
  27:                  w.AutoFlush = true;
  28:                  w.WriteLine(String.Format("TIME IS {0}", DateTime.Now));
  29:              }
  30:              np.Close();
  31:          }
  32:   
  33:          protected override void OnStart(string[] args)
  34:          {
  35:              MyTimer.Start();
  36:          }
  37:   
  38:          protected override void OnStop()
  39:          {
  40:              MyTimer.Stop();
  41:          }
  42:      }
  43:  }

 

The OnStart and OnStop Event will start and end the timer and the MyTimer_Elaspsed will execute the needed code. As I said early, I'm just using some test code to demonstrate it's use. We will add our aggregation code in another post, but for now, let's keep it simple. Once you have compiled your service, you can install it using INSTALLUTIL /I dnrTVService.exe.

sshot-6

Our next step is to create the client winform application. We will drop three buttons on it, a start button, a stop button and a connect button. Also, we'll be needing a list box to report the time back too. Two additional controls we will be using will be the ServiceController to start and stop our service and a BackgroundWorker process.

 

sshot-7

The following code in our winform application will start up a background worker thread and wait for the service to contact us. Yes, I know it is sort of backwards, but it will have to do for now. I'll see about reversing the client/server role in my next post.

 

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.ComponentModel;
   4:  using System.Data;
   5:  using System.Drawing;
   6:  using System.Linq;
   7:  using System.Text;
   8:  using System.Windows.Forms;
   9:  using System.IO.Pipes;
  10:  using System.IO;
  11:   
  12:  namespace dnrTVClient
  13:  {
  14:      public partial class MainForm : Form
  15:      {
  16:          public MainForm()
  17:          {
  18:              InitializeComponent();
  19:          }
  20:   
  21:          private void StartButton_Click(object sender, EventArgs e)
  22:          {
  23:              dnrTVController.Start();
  24:          }
  25:   
  26:          private void StopButton_Click(object sender, EventArgs e)
  27:          {
  28:              dnrTVController.Stop();
  29:          }
  30:   
  31:          private void dnrTVProcessWorker_DoWork(object sender, DoWorkEventArgs e)
  32:          {
  33:              while (true)
  34:              {
  35:                  NamedPipeServerStream np = new NamedPipeServerStream("test_pipe", PipeDirection.InOut);
  36:   
  37:                  np.WaitForConnection();
  38:                  StreamReader r = new StreamReader(np);
  39:                  dnrTVProcessWorker.ReportProgress(0, r.ReadLine());
  40:   
  41:                  np.Close();
  42:              }
  43:          }
  44:   
  45:          private void ConnectButton_Click(object sender, EventArgs e)
  46:          {
  47:              dnrTVProcessWorker.RunWorkerAsync();
  48:          }
  49:   
  50:          private void dnrTVProcessWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
  51:          {
  52:              LogListBox.Items.Add(e.UserState.ToString());
  53:          }
  54:      }
  55:  }
 
Assuming we already compiled and installed our service, it is time to compile and run out client application. The output for the should look something like this.
 
sshot-8
 
Things look like they are going pretty good. For my next post in this series, I will add the aggregation code to pull the feed, download the show, unzip it and update a configuration XML file.
 
 
kick it on DotNetKicks.com
posted on Thursday, January 31, 2008 5:13:23 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2]