以 Console 方式运行、调试、编译 .Net 编写的 Windows 服务

经常看到一些人在调试 Windows 服务时,很执著的在附加进程后调试!
其实 .Net 编写的 Windows 应用程序,包括 Windows 服务都可以编译成 Console 程序!
甚至于 ASP.Net ASPX 的 codebehind 里加个 Main 函数,编译成 Console 也未尝不可!
万事万物皆Console!(学自《thinking in java》万事万物皆对象!有点牵强,表笑偶)
利用 Visual Studio .Net 2003 创建的 "Windows 服务" 项目默认不是 Console,
你可以在项目属性中:
"通用属性->常规->输出类型->应用程序" 强行指定为 "控制台应用程序"
"配置属性->调试->启动选项->命令行参数" 指定为任意字符串,如: "/cxxx"

然后将生成的 C# 服务代码,如: Service.cs 的 Main 函数改为如下代码

static void Main(string[] args )
{
    Service1 x 
= new Service1();
    
if (args.Length > 0)
    
{
        Console.WriteLine(
"Console");
        x.OnStart(
null);
        Console.ReadLine();
    }

    
else
    
{
        System.ServiceProcess.ServiceBase[] ServicesToRun;
        
// 同一进程中可以运行多个用户服务。若要将
        
//另一个服务添加到此进程,请更改下行
        
// 以创建另一个服务对象。例如,
        
//
        
//   ServicesToRun = New System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
        
//
        ServicesToRun = new System.ServiceProcess.ServiceBase[] { x};
        System.ServiceProcess.ServiceBase.Run(ServicesToRun);
    }

}

接下来就可以 F5 运行了,如果有客户端调用,且你设了断点,自然就可以断点调试了!
这个程序即可以服务方式运行,也可以在运行时指定命令行参数以 Console 运行!
绝不不影响 InstallUtil 部署该服务!
我在 程序代码 里经常加些 System.Console.WriteLine 的提示信息!
再多说几句:
Visual Studio 生成的服务程序代码比较多,并不是所有的代码都是必要的!
其实实现一个最简单的 Windows 服务,用不了太多的代码,
Service 的 Installer 的最关键代码是 ServiceName 要一致!
下面就是一个 SimpleService 的简单例子

namespace Microshaoft
{
    
using System;
    
using System.ServiceProcess;
    
using System.ComponentModel;
    
using System.Security.Principal;
    
using System.Configuration.Install;

    
public class SimpleService : ServiceBase //继承于 ServiceBase
    {
        
public static readonly string serviceName = "Hello-World Service1";

        
public static void Main(string[] args)
        
{
            SimpleService x 
= new SimpleService();
            
int l = 0;
            
if (args != null)
            
{
                l 
= args.Length;
            }


            
if (l > 0//有参数时以 console 方式运行
            {
                Console.WriteLine(
"Run as Console");
                x.OnStart(
null);
                Console.ReadLine();
            }

            
else 
            
//intallutil 成服务后
            
//即: 无参数时,以 Service 方式运行
            {
                Console.WriteLine(
"Run as Service");
                ServiceBase.Run(x);
            }

        }

        
public SimpleService()
        
{
            CanPauseAndContinue 
= true;
            ServiceName 
= SimpleService.serviceName;
        }


        
protected override void OnStart(string[] args)
        
{

            Console.WriteLine(
".Net Version: {0}", Environment.Version.ToString());
            Console.WriteLine(
"Current Identity: {0}", WindowsIdentity.GetCurrent().Name);
            Console.WriteLine(
"{0} started,at {1}", SimpleService.serviceName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ss"));

            
//log 写入 windows 应用程序日志
            EventLog.WriteEntry(string.Format(".Net Version: {0}", Environment.Version.ToString()));
            EventLog.WriteEntry(
string.Format("Current Identity: {0}", WindowsIdentity.GetCurrent().Name));
            EventLog.WriteEntry(
string.Format("{0} started, at {1}", SimpleService.serviceName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ss")));

            
//在这里写你的程序
        }


///        protected override void OnStop()
///        {
///            EventLog.WriteEntry("Hello-World Service stopped");
///        }
///
///        protected override void OnPause()
///        {
///            EventLog.WriteEntry("Hello-World Service paused");
///        }
///
///        protected override void OnContinue()
///        {
///            EventLog.WriteEntry("Hello-World Service continued");
///        }

    }


    
//以下就是比普通应用程序多出的 ProjectInstaller
    [RunInstallerAttribute(true)]
    
public class ProjectInstaller: Installer
    
{

        
private ServiceInstaller serviceInstaller;
        
private ServiceProcessInstaller processInstaller;

        
public ProjectInstaller(){

            processInstaller 
= new ServiceProcessInstaller();
            serviceInstaller 
= new ServiceInstaller();

            
// Service will run under system account
            processInstaller.Account = ServiceAccount.LocalSystem;

            
// Service will have Start Type of Manual
            serviceInstaller.StartType = ServiceStartMode.Manual;

            serviceInstaller.ServiceName 
= SimpleService.serviceName;

            Installers.Add(serviceInstaller);
            Installers.Add(processInstaller);
        }

    }

}


请用命令行编译:
csc service1.cs
编译生成 service1.exe ,其实就是一个 Console!
如果编译时加上 /debug 还可以结合 DbgCLR.exe 工具进行断点调试!
用命令行:
InstallUtil.exe service1.exe
安装成服务!
或者在 cmd 命令行状态,运行如下命令行:
service1.exe /xxx
就可以 Console 运行该 "服务"!
如果你有 System.Console.WriteLine 的提示信息,看着多爽!
有些时候 "服务" 方式启动不了时,用 Console 运行还可以很轻易的发现错误!

我个人现在工作中,基本不写大量代码!
因此基本不用 Visual Studio,很少写 WinForm、WebForm,只写 Console!
只是使用 EditPlus + SDK + DbgCLR 编写、调试一些功能简单的测试代码!
接下来吐血●●●推荐下载我强大的 EditPlus:
http://microshaoft.googlepages.com/EditPlus.v2.21.b381.zip
注意: 解压后请复制到你的D盘根目录,即目录为 D:\EditPlus
如果你想放在其他盘或目录下,请打开 EditPlus 目录下的一些 INI 文件,并替换路径,保存!
可以编写、编译:
C#、Java、C/C++ 等
并集成了一些有用的 .Net 命令行工具,如: wsdl.exe、installutil、regasm、tlbimp 等
(如果命令行工具的路径不对,请自行打开 tool.ini 文件替换你自己的相应路径)
收集了一些有用的代码片断,
欢迎使用,提意见!


namespace Microshaoft
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration.Install;
    using System.Security.Principal;
    using System.ServiceProcess;
    using Microshaoft.Win32;
    public class WindowsServiceHost : ServiceBase
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Environment.CommandLine);
            WindowsServiceHost service = new WindowsServiceHost();
            int l = 0;
            bool needFreeConsole = false;
            if (args != null)
            {
                l = args.Length;
            }
            if (l > 0)
            {
                if (args[0].ToLower() == "/console")
                {
                    needFreeConsole = true;
                    Console.Title = "Service Run as Console ...";
                    Console.WriteLine("Alloc Console ...");
                    NativeMethods.AllocConsole();
                    service.OnStart(args);
                    Console.ReadLine();
                    return;
                }
            }
            Console.WriteLine("Service");
            ServiceBase.Run(service);
            if (needFreeConsole)
            {
                Console.WriteLine("Free Console ...");
                NativeMethods.FreeConsole();
            }
        }
        public WindowsServiceHost()
        {
            CanPauseAndContinue = true;
        }
        protected override void OnStart(string[] args)
        {
            Console.WriteLine("[{0}]", string.Join(" ", args));
            Console.WriteLine("Current User Identity: {0}", WindowsIdentity.GetCurrent().Name);
            Console.WriteLine(".Net Framework version: {0}", Environment.Version.ToString());
        }
    }
    [RunInstallerAttribute(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceInstaller _serviceInstaller;
        private ServiceProcessInstaller _processInstaller;
        public ProjectInstaller()
        {
            _processInstaller = new ServiceProcessInstaller();
            _serviceInstaller = new ServiceInstaller();
            // Service will run under system account
            _processInstaller.Account = ServiceAccount.LocalSystem;
            // Service will have Start Type of Manual
            _serviceInstaller.StartType = ServiceStartMode.Manual;
            //_serviceInstaller.ServiceName = WindowsServiceHost.serviceName;
            Installers.Add(_serviceInstaller);
            Installers.Add(_processInstaller);
        }
        public override void Install(IDictionary stateSaver)
        {
            SetServiceName();
            base.Install(stateSaver);
        }
        public override void Uninstall(IDictionary savedState)
        {
            SetServiceName();
            base.Uninstall(savedState);
        }
        private void SetServiceName()
        {
            var parameters = Context.Parameters;
            var parametersKeys = parameters.Keys;
            //foreach (KeyValuePair<string, string> kvp in parameters)
            foreach (string s in parametersKeys)
            {
                var k = s.Trim().ToLower();
                if (k == "servicename")
                {
                    //var serviceName = kvp.Value;
                    var serviceName = parameters[k];
                    _serviceInstaller.ServiceName = serviceName;
                    _serviceInstaller.DisplayName = serviceName;
                    break;
                }
            }
        }
    }
}
namespace Microshaoft.Win32
{
    using System.Runtime.InteropServices;
    public class NativeMethods
    {
        /// <summary>
        /// 启动控制台
        /// </summary>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        public static extern bool AllocConsole();
        /// <summary>
        /// 释放控制台
        /// </summary>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        public static extern bool FreeConsole();
    }
}

原文地址:https://www.cnblogs.com/Microshaoft/p/376767.html