如何制作Windows服务应用程序,以便它也可以作为独立程序运行?

时间:2010-06-27 23:21:47

标签: c# windows-services

我将从一个示例开始:Apache Web服务器(在Windows下)有一个很好的功能:它既可以作为独立应用程序运行(具有当前用户权限),也可以作为Windows安装和运行直接服务(作为本地系统帐户),使用相同的可执行文件。

为了使应用程序作为独立应用程序运行,它需要做的就是在某些公共类中使用静态公共Main()。

为了使应用程序可以作为服务进行安装和运行,它必须以某种方式实现ServiceBase和Installer类。但是,如果像这样的应用程序作为独立应用程序运行,它将显示消息框。

如何实现类似Apache的操作模式?我相信解决方案很简单,但我真的不知道从哪里开始。

以下代码用于调用服务。可以修改它以允许独立使用吗?

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new Service() // defined elsewhere as Service : ServiceBase
        };
        ServiceBase.Run(ServicesToRun);
    }
}

我选择的语言是C#。

编辑:目前,我已将公共代码抽象为单独的程序集(让我们称之为Library.dll),我有两个可执行文件:Console.exe和Service.exe,它们是独立的和windows服务应用程序,分别只是调用Library.dll的方法。

我的目标是将这两个可执行文件合并为一个,仍然会调用Library.dll。

4 个答案:

答案 0 :(得分:10)

在C#中,一种简单的方法是要求命令行参数将其作为服务运行。如果参数不存在,则运行表单/控制台应用程序。然后让您的安装程序在安装服务时在可执行文件路径中包含参数,使其如下所示:

C:\MyApp\MyApp.exe -service

它看起来像这样:

static void Main(string[] args)
{
    foreach (string arg in args)
    {
        //Run as a service if our argument is there
        if (arg.ToLower() == "-service")
        {
            ServiceBase[] servicesToRun = new ServiceBase[] { new Service1() };
            ServiceBase.Run(servicesToRun);
            return;
        }
    }

    //Run the main form if the argument isn't present, like when a user opens the app from Explorer.
    Application.Run(new Form1());
}

这只是一个给你一个想法的例子,可能有更简洁的方法来编写这段代码。

答案 1 :(得分:8)

经过一番挖掘后,我终于查看了.NET hood(System.ServiceProcess.ServiceBase.Run方法),发现它检查Environment.UserInteractive bool以确保可执行文件不是以交互方式运行。

对我有用的超简化解决方案:

class Program
{
    static void Main(string[] args)
    {
        if (!Environment.UserInteractive)
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                // Service.OnStart() creates instance of MainLib() 
                // and then calls its MainLib.Start() method
                new Service()
            };
            ServiceBase.Run(ServicesToRun);
            return;
        }

        // Run in a console window
        MainLib lib = new MainLib();
        lib.Start();
        // ...
    }
}

答案 2 :(得分:3)

您应该在库中抽象出所有功能。它碰巧从Windows服务运行的事实应该无关紧要。实际上,如果你有一个名为ServiceFrontEnd的面向类,它有一个Start()和Stop() - Windows服务应用程序可以调用它,那么命令行应用程序,Windows应用程序或其他任何东西都可以。

你在这里描述的只是需要更多的抽象。 “服务”的功能不需要与Windows服务的运行方式紧密耦合。希望有所帮助

答案 3 :(得分:0)

在您的网站示例中,我非常有信心Apache应用程序是用C或C ++编写的。为此,您需要一个ServiceMain函数。如果像普通程序一样执行它,则会调用main。如果您指向服务控制管理器,则会调用ServiceMain。

关于C#,不能说我知道这一点。如果我必须在c#中编写服务,我想我会从这里开始 - http://msdn.microsoft.com/en-us/library/bb483064.aspx