不受Visual Studio干扰的Windows服务

11

我希望创建和管理一个Windows服务应用程序,但不需要使用Visual Studio设计器的“帮助”。

由于这是.NET平台,根据MSDN和设计器所做的事情,这意味着要继承自Installer,并构建和处理ServiceProcessInstallerServiceInstaller以便能够管理安装时执行服务的操作。

在运行时,这意味着创建一个ServiceBase子类,并从Main中使用ServiceBase.Run启动它(并覆盖各种ServiceBase事件处理方法)。

然而,当我这样做时,Visual Studio坚持将InstallerServiceBase子类视为由设计器编辑的文件。这并没有帮助阅读性,更不用说它通常无法处理手写代码。 为了让事情容易管理(特别是对于那些难以测试和调试的代码,例如Windows服务必须被安装后才能运行),并且能够在运行时指定服务名称而不是在编译时指定服务名称 - 设计器不支持这一点 - 我希望避免使用设计器。

如何创建一个没有所有繁琐操作的Windows服务应用程序?


2
你可能想要查看TopShelf项目 - http://topshelf-project.com/ - stuartd
哦,不错!看起来有点过度设计,还不够成熟,但如果我要写一个新的应用程序,我肯定会考虑它。 - Eamon Nerbonne
4个回答

12

ServiceBase 继承自 Component。若要禁用设计视图,您可以添加如下属性:

[System.ComponentModel.DesignerCategory("")]
[System.ComponentModel.DesignerCategory("Code")]
public class MyService : ServiceBase
{

}

只要在添加继承之前添加这行代码,就可以使其工作,而无需创建设计者。 - Matthew
这确实是正确的答案,像个冠军一样工作! - Ronald
1
工作了,但在此之前我必须删除并重新添加对System.ServiceProcess的引用才能生效。 - Matthew Sharpe

6

由于我经常创建这样的服务:

我有一个通用的基类,看起来像这样:

internal class ServiceRunner : ServiceBase {
   protected static void Startup(string[] args, ServiceRunner instance, bool interactiveWait) {    
    if (instance == null)
        throw new ArgumentNullException("instance");

    if (Environment.UserInteractive) {
        instance.OnStart(args);
        if (interactiveWait) {
            Console.WriteLine("Press any key to stop service");
            Console.ReadKey();
        }
        instance.OnStop();
    }
    else
        Run(instance);
}

然后我像这样创建我的所有服务
internal class MyService : ServiceRunner
{
    public MyService() {
        ServiceName = ConfigurationManager.AppSettings["MyServiceName"];
    }

    private static void Main(string[] args) {
        Startup(args, new MyService(), true);
    }

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

    protected override void OnStop() {
        ...
        base.OnStop();
    }
}

现在我可以通过在调试器或命令行上运行来测试该服务。

安装时使用命令行。

sc create ServiceName binPath= C:\...\MyService.exe

我无法阻止设计师双击打开的行为。


2

好的,只需要在构造函数中删除InitializeComponent()调用,那么设计器生成的代码就不影响你了。


那行不通: Visual Studio很“聪明”:它不关心您是将文件添加为类还是组件-重要的是继承层次结构。如果您继承了 Installer 并因此成为 IComponent,则会获得设计师 - 即使您最初通过“添加类”创建该文件。 - Eamon Nerbonne
我甚至尝试在Installer之前添加一个无意义的类 - 它仍然使用设计师。一个(不太令人满意的)解决方法是右键单击:打开方式,选择CSharp编辑器并将其设置为默认值。这是不令人满意的,因为在另一台机器上进行新的源代码控制检出将丢失该用户设置并恢复到请搞乱我的代码设计师。 - Eamon Nerbonne
1
我复现了。很烦人,不是吗? - Hans Passant

-1

1
ServiceName不是常量时,设计师会崩溃 - 并且它会改变我编写的代码:我真的不想要这个设计师。此外,它生成的代码比必要的代码容易大5倍,而且更难理解。 - Eamon Nerbonne
1
让我这样说吧:除了作为包含所需类型的初始模板之外,对于设计师来说是否有任何有用的功能? - Eamon Nerbonne

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