[Windows Service] 替 Windows Service 專案加上 Debug 模式

Windows Service 專案並不能直接按 F5 進入除錯模式,這對開發人員來說還挺麻煩的,對 Windows Service 專案按下 F5,它會不客氣的跳出一個對話視窗

以往我會透過專案分層的方式來解決這個問題,Console App 和 Windows Service 兩者都依賴 BLL,BLL 處理邏輯依賴 DAL,DAL 處理IO(SQL | CSV);開發時預設專案選 Console App,佈署用 Windows Service

一次要維護兩個專案有點累,現在我要用一小技巧來將他們合併,原本 BLL.WinService 裡的 Program 如下:

namespace BLL.WinService
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

 

現在把它變這樣

namespace BLL.WinService
{
    internal static class Program
    {
        ///// <summary>
        ///// The main entry point for the application.
        ///// </summary>
        //static void Main()
        //{
        //    ServiceBase[] ServicesToRun;
        //    ServicesToRun = new ServiceBase[]
        //    {
        //        new Service1()
        //    };
        //    ServiceBase.Run(ServicesToRun);
        //}
        private static void Main(string[] args)
        {
            // Run Service
            ServiceBase[] services =
            {
                new Service1()
            };
            if (Environment.UserInteractive)
            {
                RunInteractive(services);
            }
            else
            {
                ServiceBase.Run(services);
            }
        }
        public static void RunInteractive(ServiceBase[] services)
        {
            Console.WriteLine();
            Console.WriteLine("Install the services in interactive mode.");
            Console.WriteLine();
            // Get the method to invoke on each service to start it
            var onStartMethod =
                typeof(ServiceBase).GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
            // Start services loop
            foreach (var service in services)
            {
                Console.WriteLine("Installing {0} ... ", service.ServiceName);
                onStartMethod.Invoke(service, new object[] {new string[] { }});
                Console.WriteLine("Installed {0} ", service.ServiceName);
                Console.WriteLine();
            }
            // Waiting the end
            Console.WriteLine("Press a key to uninstall all services...");
            Console.ReadKey();
            Console.WriteLine();
            // Get the method to invoke on each service to stop it
            var onStopMethod = typeof(ServiceBase).GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
            // Stop loop
            foreach (var service in services)
            {
                Console.Write("Uninstalling {0} ... ", service.ServiceName);
                onStopMethod.Invoke(service, null);
                Console.WriteLine("Uninstalled {0}", service.ServiceName);
            }
            Console.WriteLine();
            Console.WriteLine("All services are uninstalled.");
            // Waiting a key press to not return to VS directly
            if (Debugger.IsAttached)
            {
                Console.WriteLine();
                Console.Write("=== Press a key to quit ===");
                Console.ReadKey();
            }
        }
    }
}

 

裡面有兩個關鍵:
  1. Environment.UserInteractive 用來判斷是否為互動模式
  2. RunInteractive 方法用反射調用 Service 裡的 OnStart 方法
在專案設定:
Output type:Console Application
大功告成,我再也不需要維護另外一個 Console 專案了
 
 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2019 .NET

Image result for microsoft+mvp+logo