Program Runs Fine until I turn it into a Service

0

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;
            }



        }
    }
c#
service
asked on Stack Overflow Oct 17, 2016 by Missy • edited May 23, 2017 by Community

1 Answer

1

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();
    [...]
answered on Stack Overflow Oct 17, 2016 by Thomas Weller • edited Oct 17, 2016 by Thomas Weller

User contributions licensed under CC BY-SA 3.0