Wrapping a C# service in a console app to debug it

前端 未结 10 1207
遇见更好的自我
遇见更好的自我 2020-12-15 03:36

I want to debug a service written in C# and the old fashioned way is just too long. I have to stop the service, start my application that uses the service in debug mode (Vis

相关标签:
10条回答
  • 2020-12-15 04:14

    The approach I always take is to isolate out all of your application's logic into class libraries. This makes your service project really just a shell that hosts your class libraries as a service.

    By doing this, you can easily unit test and debug your code, without having to deal with the headache of debugging a service by attaching to a process. I'd recommend unit testing of course, but if you're not doing that then adding a console application that calls the same entry point as your service is the way to go.

    0 讨论(0)
  • 2020-12-15 04:15

    You might want to check out TopShelf as well in your adventures.

    http://codebetter.com/blogs/dru.sellers/archive/2009/01/11/topshelf.aspx

    http://code.google.com/p/topshelf/

    0 讨论(0)
  • 2020-12-15 04:24

    I use this to check if my process is running as a service or not.

    public class ServiceDiagnostics
    {
        readonly bool _isUserService;
        readonly bool _isLocalSystem;
        readonly bool _isInteractive;
    
        public ServiceDiagnostics()
        {
            var wi = WindowsIdentity.GetCurrent();
            var wp = new WindowsPrincipal(wi);
    
            var serviceSid = new SecurityIdentifier(WellKnownSidType.ServiceSid, null);
            var localSystemSid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
            var interactiveSid = new SecurityIdentifier(WellKnownSidType.InteractiveSid, null);
    
            this._isUserService = wp.IsInRole(serviceSid);
    
            // Neither Interactive or Service was present in the current user's token, This implies 
            // that the process is running as a service, most likely running as LocalSystem.
            this._isLocalSystem = wp.IsInRole(localSystemSid);
    
            // This process has the Interactive SID in its token.  This means that the process is 
            // running as a console process.
            this._isInteractive = wp.IsInRole(interactiveSid);
        }
    
        public bool IsService
        {
            get { return this.IsUserService || this.IsLocalSystem || !this.IsInteractive; }    
        }
    
        public bool IsConsole
        {
            get { return !this.IsService; }
        }
    
        /// <summary>
        /// This process has the Service SID in its token. This means that the process is running 
        /// as a service running in a user account (not local system).
        /// </summary>
        public bool IsUserService
        {
            get { return this._isUserService; }
        }
    
        /// <summary>
        /// Neither Interactive or Service was present in the current user's token, This implies 
        /// that the process is running as a service, most likely running as LocalSystem.
        /// </summary>
        public bool IsLocalSystem
        {
            get { return this._isLocalSystem; }
        }
    
        /// <summary>
        /// This process has the Interactive SID in its token.  This means that the process is 
        /// running as a console process.
        /// </summary>
        public bool IsInteractive
        {
            get { return this._isInteractive; }
        }
    }
    
    0 讨论(0)
  • 2020-12-15 04:31

    You can do something like this in the main entry point:

    static void Main()
    {
    #if DEBUG
        Service1 s = new Service1();
        s.Init(); // Init() is pretty much any code you would have in OnStart().
    #else
        ServiceBase[] ServicesToRun;
        ServicesToRun=new ServiceBase[] 
        { 
            new Service1() 
        };
        ServiceBase.Run(ServicesToRun);
    #endif
    }
    

    and in your OnStart Event handler:

    protected override void OnStart(string[] args)
    {
        Init();
    }
    
    0 讨论(0)
  • 2020-12-15 04:31

    To avoid using global defines I generally test at run-time whether I'm a service or regular application through the Environment.UserInteractive property.

        [MTAThread()]
        private static void Main()
        {
            if (!Environment.UserInteractive)
            {
                ServiceBase[] aServicesToRun;
    
                // More than one NT Service may run within the same process. To add
                // another service to this process, change the following line to
                // create a second service object. For example,
                //
                //   ServicesToRun = New System.ServiceProcess.ServiceBase () {New ServiceMain, New MySecondUserService}
                //
                aServicesToRun = new ServiceBase[] {new ServiceMain()};
    
                Run(aServicesToRun);
            }
            else
            {
                var oService = new ServiceMain();
                oService.OnStart(null);
            }
       }
    
    0 讨论(0)
  • 2020-12-15 04:35

    You could call the service methods via reflection as seen below.

    Using Environment.UserInteractive enables us to know if we are running as a console app or as a service.

    ServiceBase[] ServicesToRun;
    ServicesToRun = new ServiceBase[]
    {
        new MyService()
    };
    
    if (!Environment.UserInteractive)
    {
        // This is what normally happens when the service is run.
        ServiceBase.Run(ServicesToRun);
    }
    else
    {
        // Here we call the services OnStart via reflection.
        Type type = typeof(ServiceBase);
        BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
        MethodInfo method = type.GetMethod("OnStart", flags);
    
        foreach (ServiceBase service in ServicesToRun)
        {
            Console.WriteLine("Running " + service.ServiceName + ".OnStart()");
            // Your Main method might not have (string[] args) but you could add that to be able to send arguments in.
            method.Invoke(service, new object[] { args });
        }
    
        Console.WriteLine("Finished running all OnStart Methods.");
    
        foreach (ServiceBase service in ServicesToRun)
        {
            Console.WriteLine("Running " + service.ServiceName + ".OnStop()");
            service.Stop();
        }
    }
    
    0 讨论(0)
提交回复
热议问题