将 C# 服务包装在控制台应用程序中以对其进行调试

发布于 2024-08-26 12:25:17 字数 221 浏览 5 评论 0原文

我想调试用 C# 编写的服务,而老式的方法太长了。我必须停止该服务,启动在调试模式下使用该服务的应用程序 (Visual studio 2008),启动该服务,附加到服务进程,然后在我的 Asp.Net 应用程序中导航以触发该服务。

我基本上让服务在后台运行,等待任务。 Web 应用程序将触发服务拾取的任务。

我想做的是拥有一个控制台应用程序来触发服务,以便我进行调试。有没有人知道的简单演示?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

挽梦忆笙歌 2024-09-02 12:25:17

您可以在主入口点

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
}

和 OnStart 事件处理程序中执行类似的操作:

protected override void OnStart(string[] args)
{
    Init();
}

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();
}
旧人哭 2024-09-02 12:25:17

我始终采用的方法是将应用程序的所有逻辑隔离到类库中。这使得您的服务项目实际上只是一个将类库作为服务托管的外壳。

通过这样做,您可以轻松地对代码进行单元测试和调试,而不必处理通过附加到进程来调试服务的麻烦。当然,我建议进行单元测试,但如果您不这样做,那么添加一个调用与您的服务相同的入口点的控制台应用程序是可行的方法。

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.

一世旳自豪 2024-09-02 12:25:17

为了避免使用全局定义,我通常在运行时通过 Environment.UserInteractive 属性测试我是服务还是常规应用程序。

    [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);
        }
   }

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);
        }
   }
别闹i 2024-09-02 12:25:17

您可以通过反射调用服务方法,如下所示。

使用Environment.UserInteractive使我们能够知道我们是作为控制台应用程序还是作为服务运行。

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();
    }
}

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();
    }
}
是伱的 2024-09-02 12:25:17

TopShelf 是另一个非常适合这种方法的项目。它允许您将进程作为服务运行,或者作为具有最少配置的常规控制台应用程序运行。

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.

阪姬 2024-09-02 12:25:17

我倾向于使用配置设置或使用指令进行调试构建:

 #if DEBUG
    Debugger.Break();
 #endif

或者

if(Settings.DebugBreak)
            Debugger.Break();

将其放在服务组件的 OnStart 方法中。然后系统会自动提示您并附加到该流程。

I tend to have either a config setting or use a directive for debug builds:

 #if DEBUG
    Debugger.Break();
 #endif

or

if(Settings.DebugBreak)
            Debugger.Break();

I put that in the OnStart method of the service component. Then you are prompted automatically and attached to the process.

恰似旧人归 2024-09-02 12:25:17

这是一篇关于将 Windows 服务作为控制台应用程序。

您还可以创建一个新的控制台应用程序,引用与您的服务相同的逻辑来测试方法,或者对服务的逻辑设置单元测试

Here is a blog post about running your windows service as a console app.

You could also just create a new Console Application that references the same logic as your service to test methods, or set up Unit Tests on your services' logic

风吹短裙飘 2024-09-02 12:25:17

我过去曾使用单元测试来调试困难的设置,只需编写一个单元测试,使用任何参数调用任何服务方法,并在单元测试中设置调试断点。

使用 testdriven.net 或 jetbrains testrunner 会更容易。

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.

最丧也最甜 2024-09-02 12:25:17

我用它来检查我的进程是否作为服务运行。

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; }
    }
}

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; }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文