【问题标题】:Program Runs Fine until I turn it into a Service程序运行良好,直到我把它变成服务
【发布时间】:2016-10-17 19:04:59
【问题描述】:

我正在构建一项服务。基本上,它等待文件到达一个目录,然后将它们加密到另一个目录,然后删除它们。当它不是服务时它可以正常工作,但是它不能作为服务工作。当我中断服务进行调试时,它卡在了

    ServiceBase.Run(ServicesToRun);

当文件进入指定目录时,似乎从来没有真正执行过代码。这是我的第一个服务,我的很多代码来自 AES encryption on large fileshttps://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx 任何输入将不胜感激。

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



        }
    }

【问题讨论】:

  • 可以使用任务调度器代替service来运行程序。
  • 这是个好主意,但程序必须每分钟运行一次,所以服务似乎是一个更好的策略。
  • @urlreader - 我似乎无法让它通过任务调度程序运行。服务理念行不通,我不知道如何调试它。我给了它所有最高权限,它显示为服务,但实际上并没有执行。所以我切换到任务计划程序的想法,它说它正在运行,但没有迹象表明它正在运行 - 即它不在任务管理器中,仅在计划任务中。有什么想法吗?
  • 如果您使用任务调度程序,则只需将其作为控制台程序,而不是使用相同的代码进行服务。它更容易调试,实际上关于我们应该使用任务调度程序还是服务有很多讨论。
  • 这里是关于服务或任务计划程序的讨论:stackoverflow.com/questions/390307/…,“底线:计划任务通常比 Windows 服务更受欢迎。”

标签: c# service


【解决方案1】:

你正在创建一个新的计时器

System.Timers.Timer timer = new System.Timers.Timer();

内部有局部作用域

protected override void OnStart(string[] args)

当它超出范围时,它可以被垃圾收集。这可能迟早会发生,因此您的服务工作时间会更短或更长,具体取决于收集垃圾的时间。

将计时器声明为与服务一样长的字段:

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();
    [...]

【讨论】:

  • 嗨,Thomas -- 非常感谢您的回答。你能具体说明我将如何去做吗?
  • 服务将永远存在。
  • 我应该把_timer的定义放在哪里?在受保护的覆盖 void OnStart(string[] args) 之前?我试过了,但没有用。我应该把它放在 static void Main() 之前还是之前?
  • 任何编译的地方都可以
  • 如果这不起作用,我认为权限问题会产生异常。添加更多错误处理。
猜你喜欢
  • 2011-09-10
  • 2013-04-23
  • 2020-08-21
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多