Reputation: 1368
I am building a service. Basically, it waits for files to arrive into a directory then encrypts them into another directory then deletes them. It works fine when it's not a service, however it isn't working as a service. When I interrupt the service to debug it, it is stuck on
ServiceBase.Run(ServicesToRun);
and never actually seems to execute the code when a file enters the designated directory. This is my first service and a lot of my code came from AES encryption on large files and https://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx Any input would be greatly appreciated.
/// Program.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace XYZDataEncryptor
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new XYZDataEncryptor()
};
// stuck here in service debugger
ServiceBase.Run(ServicesToRun);
}
}
}
/// XYZDataEncryptor.CS
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
namespace XYZDataEncryptor
{
public partial class XYZDataEncryptor : ServiceBase
{
public XYZDataEncryptor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
// Update the service state to Start Pending.
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWaitHint = 100000;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 60000; // 60 seconds
// Run the OnTimer Process
timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
timer.Start();
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
// process the files
ProcessFiles();
}
protected override void OnStop()
{
}
public enum ServiceState
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}
[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
public long dwServiceType;
public ServiceState dwCurrentState;
public long dwControlsAccepted;
public long dwWin32ExitCode;
public long dwServiceSpecificExitCode;
public long dwCheckPoint;
public long dwWaitHint;
};
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
private static void ProcessFiles()
{
string path = @"q:\XYZraw";
string outPath = @"q:\XYZEncryptedRaw";
string[] rawFiles = Directory.GetFiles(@"q:\XYZraw\", "*.txt");
foreach (string fileName in rawFiles)
{
// check if the file has fully arrived then encrypt it
CheckFile(path, outPath, fileName);
}
}
private static void CheckFile(string path, string outPath, string fileName)
{
if (File.Exists(fileName))
{
bool finished = false;
while (!finished)
{
// Wait if file is still open
FileInfo fileInfo = new FileInfo(fileName);
while (IsFileLocked(fileInfo))
{
// check to see if the file is still open (locked)
Thread.Sleep(5000);
}
finished = true;
}
string outFile = outPath + fileName.Substring(fileName.LastIndexOf("\\"));
// This path is a file
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
// encrypt file
AES_Encrypt(fileName, outFile, saltBytes);
File.Delete(fileName);
}
}
private static void AES_Encrypt(string inputFile, string outputFile, byte[] passwordBytes)
{
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged AES = new RijndaelManaged();
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.Zeros;
AES.Mode = CipherMode.CBC;
CryptoStream cs = new CryptoStream(fsCrypt,
AES.CreateEncryptor(),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
static bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open,
FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
}
}
Upvotes: 0
Views: 72
Reputation: 59228
You are creating a new timer
System.Timers.Timer timer = new System.Timers.Timer();
that has a local scope inside
protected override void OnStart(string[] args)
When it goes out of scope, it can be garbage collected. This may happen sooner or later, so your service works shorter or longer depending on when garbage is collected.
Declare the timer as a field that lives as long as the service:
System.Timers.Timer _timer;
protected override void OnStart(string[] args)
{
[...]
_timer = new System.Timers.Timer();
_timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
_timer.Start();
[...]
Upvotes: 1