如何debuggingWindows服务?
我阅读了有关该主题的MSDN文章。 去引用:
因为服务必须从服务控制pipe理器的上下文中运行,而不是从Visual Studio中运行,所以debugging服务并不像debugging其他Visual Studio应用程序types那样简单。 要debugging服务,您必须启动该服务,然后将debugging程序附加到正在运行的进程。 然后,您可以使用Visual Studio的所有标准debuggingfunction来debugging您的应用程序。
现在我的问题是,我的服务无法在第一时间开始。 首先它崩溃,并说:
MyServiceName.exe [3596]中发生未处理的exception(System.Runtime.InteropServices.COMException))
并build议我debugging它(debugging器实例即时崩溃,当我select一个)。 然后它说
无法在本地计算机上启动MyServiceName服务。 错误1053:该服务没有及时响应启动或控制请求
那么,如何调查/debugging我的服务无法启动的原因呢? 事情是我创build了一个控制台应用程序,确实做了什么服务,它工作正常。 (我的意思是我刚把OnStart
()方法和主循环的内容复制到main)。
任何帮助,将不胜感激。
该服务是用C#编写的,大量使用interop。 我正在使用VS2008
你可以使用一个参数来让你的应用程序决定是否开始服务或普通的应用程序(即在这种情况下显示一个窗体或启动服务):
static void Main(string[] args) { if ((1 == args.Length) && ("-runAsApp" == args[0])) { Application.Run(new application_form()); } else { System.ServiceProcess.ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new MyService() }; System.ServiceProcess.ServiceBase.Run(ServicesToRun); } }
现在,如果您传递参数“-runAsApp”,您可以正常debugging应用程序 – SCM将不会传递此参数,所以您也可以将其用作不带任何代码更改的服务(前提是您从ServiceBase
派生)
编辑:
与Windows服务的另一个区别是身份(这可能对于InterOp来说尤其重要) – 您要确保在“应用”模式和服务模式下以相同身份进行testing。
要做到这一点,你可以使用模拟(我可以发布一个C#包装,如果有帮助的话,但这可以很容易地search)在应用程序模式下使用相同的身份您的Windows服务将运行,通常是LocalService或NetworkService。
如果需要其他身份,则可以将设置添加到app.config中,以允许您决定是否使用凭据,如果是,则可以模拟哪个用户 – 这些设置在以应用程序运行时处于活动状态,但对于Windows服务处于closures状态因为该服务已经以所需的身份运行):
<appSettings> <add key="useCredentials" value="false"/> <add key="user" value="Foo"/> <add key="password" value="Bar"/> </appSettings>
我通常只是手动设置一个断点,然后将其指向C#中当前打开的项目。 设置断点的代码是:
System.Diagnostics.Debugger.Break();
这应该让你开始,然后你可以通过你的代码,看看到底发生了什么。
我从C.劳伦斯·温汉(Lawrence Wenham)那里偷了这个东西,所以我没有真正的信任,但是你可以通过编程的方式把一个debugging器附加到一个服务上,
System.Diagnostics.Debugger.Launch();
把它放在你的服务的OnStart()方法中,作为第一行,它会提示你select一个VS的实例来连接它的debugging器。 从那里,系统将停止在你设置的断点,并抛出exception。 我将在代码中放置一个#if DEBUG
子句,以便发布版本不包含它; 或者您可以在发现问题后将其去掉。
我做的一件事(可能是一种黑客攻击)是在我的OnStart()
方法的开始处放一个Thread.Sleep(10000)
。 这给了我一个10秒钟的窗口来将我的debugging器附加到服务之前,它做任何事情。
当然,当我完成debugging时,我删除了Thread.Sleep()
语句。
你可以做的另外一件事情是:
public override void OnStart() { try { // all your OnStart() logic here } catch(Exception ex) { // Log ex.Message if (!EventLog.SourceExists("MyApplication")) EventLog.CreateEventSource("MyApplication", "Application"); EventLog.WriteEntry("MyApplication", "Failed to start: " + ex.Message); throw; } }
当您loggingex.Message
,您可能会收到更详细的错误消息。 此外,你可以loggingex.ToString()
来获取整个堆栈跟踪,如果你的.pdb文件与你的可执行文件在同一个目录下,它甚至会告诉你发生exception的那一行。
您可以使用WinDbg / NTSD(“Debugging tools for windows”包中的另一个debugging器)与您的服务一起启动一个debugging器。
要做到这一点打开“图像文件”选项卡“gflags”(也在上述包中可用),并设置为图像文件(服务)的可执行debugging器的path;
如果您的服务被标记为交互式(只有在SYSTEM帐户下才可以运行),则可以直接启动WinDbg,只需将debugging器设置为“PATH_TO_WINDBG \ windbg.exe -g -G” (-g / -G为因此debugging器不会在应用程序的开始或结束时中断执行 – 默认行为)。 现在,当开始你的服务时,windbg窗口应该会popup,并会捕获任何未处理的exception。
如果你的服务不是交互式的,你可以在远程模式下启动NTSDdebugging器(一个命令行debugging器),并从WinDbg(甚至可以在另一台PC上运行)连接到它。 为此,将debugging器设置为gflags,如“PATH_TO_NTSD \ ntsd -remote tcp:port = 6666,server = localhost” 。 然后通过使用“windbg -remote tcp:port = 6666,server = localhost”启动windbg来连接远程debugging器,并且应该完全控制另一个debugging会话。
至于查找exception本身的来源,windbg教程已经超过了这个话题,但是作为一个开始尝试在exception被捕获后执行“!analyze -v”命令 – 有一些运气,这是所有你需要的信息。 。
注意:也许这对你来说太过分了,但是通过这种方法,你甚至可以在系统启动的时候debugging服务(我曾经有一个服务的时间问题只有在系统第一次启动时才有问题)
在您的OnStart中添加大量详细的日志logging。 这是痛苦和老派,但它的工作。
似乎问题是与用户上下文。 让我确认我的假设是否正确。
-
当你说代码完全从控制台应用程序工作时,我假设你正在执行控制台应用程序在你login的同一个用户下。
-
当你说从windows服务中调用相同的代码时,我假设服务在你的开发机器上的“本地系统”帐户中运行。
如果我的假设都是正确的,请尝试以下步骤。
-
在服务列表中,右键单击您的服务,select属性,然后单击“login”选项卡。
-
select“这个帐户”选项,并提供现有的用户名和密码。
-
现在尝试启动服务。 现在应该开始没有任何错误。
以下可能是您的错误的根源
-
如果您正在使用SQL Server,请确保您没有使用SSPI身份validation。
-
如果您正在尝试使用“本地系统”帐户读取任何您没有权限的共享文件夹\资源。
-
如果应用程序所需的任何所需依赖项位于“本地系统”用户无权访问的其他文件夹中。
-
如果您使用的VBA自动化不能在“本地系统”帐户中工作。
-
尝试禁用您的防火墙或防病毒。
你可以在interop调用中添加一些日志logging来找出哪一个失败。
默认情况下,服务也不与桌面相关联; 如果您打开services.msc控制面板小程序,获取您的服务的属性,请转到“login”选项卡,您可以选中“允许服务与桌面交互”。 在某些情况下,这可以解决您的问题。
我会认为这个原因可能是由于大量使用interop造成的。 所以你需要以不同的方式解决这个问题。 我build议创build一个Windows或控制台应用程序与您的服务相同的逻辑,并确保它的工作原理没有任何问题,然后你可能想要创build的Win服务。
debugging服务是一个痛苦,尤其是因为启动似乎是许多问题出现的时候(至less对我们来说)。
我们通常所做的是尽可能多地将逻辑提取到具有启动和停止方法的单个类。 这些类方法都是服务直接调用的。 然后我们创build一个WinForm应用程序,它有两个button:一个调用start,另一个调用stop。 然后,我们可以直接从debugging器运行这个WinForm应用程序,看看发生了什么。
不是最优雅的解决scheme,但它适用于我们。
看看这个问题 ,讨论如何在窗口服务中捕获未处理的exception。
为了将debugging器附加到Windows服务,它需要首先启动。 Windows事件日志中可以检查服务无法启动的原因。
之后,附加debugging器的过程非常简单,从Visual Studio Debug-> Attach To Process。
我所做的是由OnStart()实现的,如下所示:
_myBusinessObject = new MyBusinessObject();
业务对象构build完毕后,定时器和IPC处理程序将完成所有真实(服务)工作。
这样做可以让你创build一个Forms / WPF应用程序,在Form_Loaded处理程序中调用上面相同的代码。 这样,debuggingForms应用程序和debuggingService完全一样。
唯一的问题是,如果您使用的是app.config的值,则会有第二个app.config文件需要保持最新。
在服务OnStart方法中使用以下代码:
System.Diagnostics.Debugger.Launch();
从popup消息中selectVisual Studio选项