In my opinion, the best way to go is to create a project that can be run as a Console application or as a Windows service. The good thing about that is that it makes debugging the application much easier, because debugging a Windows service is a right pain. Here are the important bits of an application that I created that is currently running in production with the NSW state government. Note that the project was created as a Console Application.
using System.IO;
using System.Linq;
using System.ServiceProcess;
using SI.Moh.Phisco_Periph.Dto.Mapping;
namespace SI.Moh.Periph.Submissions.Service
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
DomainMapper.MapDomain();
if (args.Length == 1 && args[0] == "/console")
{
// Run the application as a Console app.
using (var processor = new SubmissionProcessor())
{
var folder = new DirectoryInfo(Properties.Settings.Default.SubmissionsRootFolder);
foreach (var file in folder.GetFiles(Properties.Settings.Default.SubmissionFileNamePattern).OrderBy(fi => fi.CreationTime))
{
processor.EnqueueFile(file.FullName);
}
processor.ProcessQueuedFiles();
}
}
else
{
// Run the application as a Windows service.
var servicesToRun = new ServiceBase[]
{
new SubmissionService()
};
ServiceBase.Run(servicesToRun);
}
}
}
}
If the argument
/console
is received on the commandline, the application will run as a regular Console app. I have that argument set on the
Debug page of the project properties. Otherwise, the application assumes that it is installed as a Windows service.
using System;
using System.IO;
using System.ServiceProcess;
using ApplicationLogger = SI.Moh.Phisco_Periph.Global.ApplicationLogger;
namespace SI.Moh.Periph.Submissions.Service
{
public partial class SubmissionService : ServiceBase
{
private const string ERROR_LOG_NAME = "PeriphErrorLog";
private const string INFO_LOG_NAME = "PeriphInfoLog";
private SubmissionProcessor processor;
public SubmissionService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
processor = new SubmissionProcessor();
var path = Properties.Settings.Default.SubmissionsRootFolder;
var filter = Properties.Settings.Default.SubmissionFileNamePattern;
#if DEBUG
ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "Path: " + path);
ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "Filter: " + filter);
#endif
// Process files already in the submission folder.
foreach (var file in new DirectoryInfo(path).GetFiles(filter))
{
processor.EnqueueFile(file.FullName);
}
processor.ProcessQueuedFilesAsync();
// Watch for new files in the submission folder.
submissionFolderWatcher.Path = path;
submissionFolderWatcher.Filter = filter;
submissionFolderWatcher.EnableRaisingEvents = true;
}
catch (Exception ex)
{
ApplicationLogger.Inst.LogException(ERROR_LOG_NAME, ex.Message, ex);
}
}
protected override void OnStop()
{
}
private void submissionFolderWatcher_Renamed(object sender, RenamedEventArgs e)
{
ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "File detected: " + e.FullPath);
processor.EnqueueFile(e.FullPath);
processor.ProcessQueuedFilesAsync();
}
}
}
As you can see, the
if
block in the
Main
method loops through the files in a folder and adds them to a queue, then calls
SubmissionProcessor.ProcessQueuedFiles
. The
else
block creates a
SubmissionService
object and that does the same thing in its
OnStart
method, so when the application starts up as a Windows service, and also in the
Renamed
event handler of a
FileSystemWatcher
.
REM =----------------------------------------------------------=
REM Runs the PeriPH Submission Processor Service as a console app.
REM Please ensure you run this batch file as Administrator,
REM and that the PeriPH Submission Processor Service is NOT running.
REM =----------------------------------------------------------=
REM
C:
CD bin\Debug
SI.Moh.Periph.Submissions.Service.exe /console
PAUSE
REM =----------------------------------------------------------=
REM Installs the PeriPH Submission Processor Service.
REM Please ensure you run this batch file as Administrator.
REM =----------------------------------------------------------=
REM
C:
CD C:\PeriPH\Service
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe" SI.Moh.Periph.Submissions.Service.exe
PAUSE
REM =----------------------------------------------------------=
REM Uninstalls the PeriPH Submission Processor Service.
REM Please ensure you run this batch file as Administrator.
REM =----------------------------------------------------------=
REM
C:
CD C:\PeriPH\Service
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe" /u SI.Moh.Periph.Submissions.Service.exe
PAUSE