ServiceBase.Run,​​为什么我不能捕获它的异常,或者以其他方式对它们做出反应?

Joh*_*ohn 4 c# windows-services exception try-catch

我从入口点静态 main 方法调用以下内容:

    try { ServiceBase.Run(new MonitorSer()); }
    catch (Exception ex) { Console.WriteLine(ex.Message + Process.GetCurrentProcess().MainModule.FileName); }
Run Code Online (Sandbox Code Playgroud)

MonitorSer 是以下实例:

class MonitorSer : ServiceBase {
Run Code Online (Sandbox Code Playgroud)

入口 main 方法是我的类的成员:

[RunInstaller(true)]
public class WindowsServiceInstaller : Installer {
Run Code Online (Sandbox Code Playgroud)

我在捕获异常进行调试方面取得了很好的结果,但有时它们似乎会找到自己的方法来绕过我的陷阱,就像在本例中一样。

我得到一个 Windows 框,告诉我需要使用 installutil 安装,而我真正想要的是找到该进程的名称,并使用我已连接的 -i 开关再次调用它,以使其安装 intself (归功于那些贡献/回收该代码的人)。

更令人沮丧的是,如果我在对 ServiceBase.Run 的调用之前设置断点,它将默默地失败,并且留下闪烁的控制台。

更新

    static void Install(bool undo, string[] args)
    {
        try
        {
            Console.WriteLine(undo ? "uninstalling" : "installing");
            using (AssemblyInstaller inst = new AssemblyInstaller(typeof(MonitorSer).Assembly, args))
            {
                IDictionary state = new Hashtable();
                inst.UseNewContext = true;
                try
                {
                    if (undo) inst.Uninstall(state);
                    else
                    {
                        inst.Install(state);
                        inst.Commit(state);
                    }
                }
                catch
                {
                    try
                    {
                        inst.Rollback(state);
                    }
                    catch { }
                    throw;
                }
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我将入口点聚集在这里,这样我就可以调用上面的函数,我将尝试将其移动到另一个类并在那里设置入口点,但我知道我可以通过调用使这个入口点(你,德米特里,否认)工作本身带有适当的安装参数(只有 BaseService 类可以做到),如果我错了,请纠正我。

Dmi*_*try 5

[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
Run Code Online (Sandbox Code Playgroud)

不是你的切入点。当您使用 InstallUtil.exe 安装服务时,将调用一次该函数。入口点可以在项目属性中指定,通常默认为Program.Main. 您不应该从 Installer 类启动服务。

如果您订阅此事件,CLR 将让您知道未处理的异常:

static void Main() {
    ...
    AppDomain.CurrentDomain.UnhandledException 
                                      += CurrentDomain_UnhandledException;
    ...
}

private static void CurrentDomain_UnhandledException(
                                                 Object sender, 
                                                 UnhandledExceptionEventArgs e) {

    if (e != null && e.ExceptionObject != null) {
        // log exception:
    }
}
Run Code Online (Sandbox Code Playgroud)

此事件提供未捕获异常的通知。它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息...从 .NET Framework 版本 4 开始,对于破坏应用程序状态的异常,不会引发此事件。进程,例如堆栈溢出或访问冲突,除非事件处理程序是安全关键型的并且具有 HandleProcessCorruptedStateExceptionsAttribute 属性。应用。

您可能想要在 Windows 服务中记录异常的另一个地方(因为.NET/SCM 会吞掉启动异常):

protected override void OnStart(String[] args) {
    try {

    } catch(Exception e) {
        // log exception:
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)