一个既可以作为服务运行,又可以作为控制台应用程序运行的应用程序通常采用什么样的模式?

4
我有一个部署在生产环境中的项目,作为Windows服务运行。但是为了本地开发目的,将其作为控制台应用程序运行会很有用。目前,我有一个名为ReportingHost的类提供我的核心功能,以及一个名为ReportingServiceHost的类,继承自ServiceBase,允许我将应用程序作为服务运行。还有一个带有主方法的程序类,在我的ReportingServiceHost上调用ServiceBase.Run
我认为我需要编写一个ReportingConsoleHost类,允许我在控制台中运行功能。然后,我需要修改我的Main方法来响应命令行开关并选择其中之一。这就是我遇到困难的两个方面。
我查看了此文档并尝试使用其中的代码,但我的应用程序立即退出,它不显示控制台窗口,也不等待按Enter键后再关闭。
问题的一部分是我对这些东西的工作原理没有深刻的理解。我希望实现的是一个明确的模式,将我的功能拆分为两种不同的运行方式,并且一个主方法根据命令行参数选择其中一种方式。
4个回答

9
我猜测您的测试项目被配置为Windows可执行文件,而不是控制台可执行文件。使用Windows可执行文件,Console.ReadLine将立即返回。
要创建一个既可以作为服务又可以在命令行中运行的控制台可执行文件,请在Visual Studio中启动它作为服务项目,并添加对Environment.UserInteractive的检查 - 即:
static void Main() {
    if(Environment.UserInteractive) {
        // code that starts the listener and waits on ReadLine
    } else {
        // run the service code that the VS template injected
    }
}

当然,您也可以使用命令行开关。我在microsoft.public.dotnet.languages.csharp上有一个示例,它可以作为:

  • 安装程序/卸载程序
  • 服务
  • 控制台模式应用

根据不同的开关进行切换。


为了使VS在您使用此解决方案时按下F5时生成控制台窗口,您必须更改项目属性,在应用程序选项卡下将输出设置为控制台应用程序。 据我所知,它仍然可以完美地安装自身为服务。 - Carl Hörberg

2
我之前已经通过实现普通的Windows服务(通过继承ServiceBase)来完成这个任务,但是在主方法中添加了一个检查命令行参数的步骤。
如果args包含“/console”,则启动控制台版本,否则启动服务。
类似于这样:
内部类MyService:ServiceBase { 内部静态void Main(string[] args) { 如果(args.Length == 0) { //作为服务运行.... ServiceBase [] servicesToRun = new ServiceBase [] {new MyService()}; 运行(servicesToRun); } 其他 { //作为控制台应用程序运行.... } } }

2
我的建议是将所有与您的服务相关的逻辑放在一个单独的程序集中(类库或DLL)。然后创建一个引用您的类库并将其用作服务代码的服务项目。创建第二个控制台项目,也引用您的类库,但将其作为控制台应用程序使用。
这样,您将在解决方案中拥有三个不同的项目,但可以保持它们分开。实际上,这将使您能够以几种其他形式扩展您的服务。例如,您可以创建第四个项目作为Web服务,并从客户端系统的Web浏览器中调用您的服务。由于软件逻辑与使用逻辑分离,因此您可以对其进行更多的控制。
请注意,服务可能会比控制台应用程序运行受到更多限制。通常情况下,服务默认情况下没有网络访问权限,没有指定监视器来显示错误消息,并且通常使用受限用户帐户或系统帐户运行。您的服务可能在控制台上运行成功,但在作为服务时失败了,因为受到这些限制。

1

上面已经有两个很好的答案了 - 但我想贴一个链接到Brian Noyes' Debuggable Self-Host Windows Service Project博客文章 - 它谈论了WCF,但应该适用于任何“Windows服务”。

最好的事情是示例代码 - 如果您无法弄清楚上面的示例“适合哪里”,请获取完整的项目并查看其工作方式。感谢Brian


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接