• 以 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();
        }
    }
    
    
  • 相关阅读:
    Nginx+Keepalived实现站点高可用
    强(strong)、软(soft)、弱(weak)、虚(phantom)引用
    Linux SSH 连接不上
    ExtJs Column 显示文字内容过长 使用Tootip显示全部内容
    史上最清晰的红黑树讲解(上)
    MySQL Cluster 集群
    分析《统计学习方法第2版》PDF+习题部分代码+部分课件讨论
    Case Styles: Camel, Pascal, Snake, and Kebab Case
    为什么EXE不能超过4GB
    But How Do It Know 关于人工智能的思考
  • 原文地址:https://www.cnblogs.com/Microshaoft/p/376767.html
Copyright © 2020-2023  润新知