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

2019-01-23 01:39发布

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 (Visual studio 2008), start the service, attach to the service process and then navigate in my Asp.Net application to trigger the service.

I basically have the service running in the background, waiting for a task. The web application will trigger a task to be picked up by the service.

What I would like to do is to have a console application that fires the service in an effort for me to debug. Is there any simple demo that anybody knows about?

10条回答
祖国的老花朵
2楼-- · 2019-01-23 02:14

I have used unit tests to debug difficult setups in the past, just write a unit test that calls whatever service method with whatever parameters and set debug breakpoints in the unit test.

Using testdriven.net or jetbrains testrunner makes it easier.

查看更多
唯我独甜
3楼-- · 2019-01-23 02:15
贼婆χ
4楼-- · 2019-01-23 02:17

TopShelf is another project that is perfect for this approach. It allows you to run a process as a service, or as a regular console application with minimal configuration.

查看更多
beautiful°
5楼-- · 2019-01-23 02:19

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; }
    }
}
查看更多
三岁会撩人
6楼-- · 2019-01-23 02:20

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();
}
查看更多
\"骚年 ilove
7楼-- · 2019-01-23 02:21

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();
    }
}
查看更多
登录 后发表回答