是否有比通过Windows服务控制管理器启动服务,然后将调试器附加到线程更简单的方法来逐步遍历代码?这有点麻烦,我想知道是否有更直接的方法。
当前回答
最好的选择是使用“系统”。诊断的名称空间。
将代码包含在if else块中,用于调试模式和发布模式,如下所示,在visual studio中切换调试和发布模式。
#if DEBUG // for debug mode
**Debugger.Launch();** //debugger will hit here
foreach (var job in JobFactory.GetJobs())
{
//do something
}
#else // for release mode
**Debugger.Launch();** //debugger will hit here
// write code here to do something in Release mode.
#endif
其他回答
第一行的Debugger.Break()怎么样?
最好的选择是使用“系统”。诊断的名称空间。
将代码包含在if else块中,用于调试模式和发布模式,如下所示,在visual studio中切换调试和发布模式。
#if DEBUG // for debug mode
**Debugger.Launch();** //debugger will hit here
foreach (var job in JobFactory.GetJobs())
{
//do something
}
#else // for release mode
**Debugger.Launch();** //debugger will hit here
// write code here to do something in Release mode.
#endif
有时,分析在服务启动期间发生了什么是很重要的。附加到流程在这里没有帮助,因为在服务启动时附加调试器的速度不够快。
简单的回答是,我使用以下4行代码来做到这一点:
#if DEBUG
base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
Debugger.Launch(); // launch and attach debugger
#endif
这些被插入到服务的OnStart方法中,如下所示:
protected override void OnStart(string[] args)
{
#if DEBUG
base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
Debugger.Launch(); // launch and attach debugger
#endif
MyInitOnstart(); // my individual initialization code for the service
// allow the base class to perform any work it needs to do
base.OnStart(args);
}
对于那些以前没有做过的人,我在下面列出了详细的提示,因为你很容易陷入困境。以下提示适用于Windows 7x64和Visual Studio 2010 Team Edition,但也适用于其他(更新的)环境。
重要提示:以“手动”模式部署服务(在VS命令提示符中使用InstallUtil实用程序或运行您准备好的服务安装程序项目)。在启动服务之前打开Visual Studio并加载包含服务源代码的解决方案——在Visual Studio中根据需要设置额外的断点——然后通过服务控制面板启动服务。
因为调试器。启动代码,这将导致一个对话框“一个未处理的Microsoft . net Framework异常发生在Servicename.exe.”出现。单击“是”,调试Servicename.exe,如下图所示:
之后,Windows UAC可能会提示您输入管理凭据。输入它们并继续执行Yes:
之后,著名的Visual Studio即时调试器窗口出现。它询问您是否要使用已删除的调试器进行调试。在单击Yes之前,选择不想打开新实例(第二个选项)——在这里,新实例没有帮助,因为不会显示源代码。所以你选择之前打开的Visual Studio实例:
单击Yes后,过一会儿Visual Studio将在调试器所在的行中显示黄色箭头。启动语句,您可以调试您的代码(方法MyInitOnStart,其中包含初始化)。
按F5继续立即执行,直到到达您准备的下一个断点。
提示:要保持服务运行,请选择Debug -> Detach all。这允许您在服务正确启动并完成调试启动代码之后运行与服务通信的客户机。如果您按下Shift+F5(停止调试),这将终止服务。您应该使用服务控制面板来停止它,而不是这样做。
请注意,
If you build a Release, then the debug code is automatically removed and the service runs normally. I am using Debugger.Launch(), which starts and attaches a debugger. I have tested Debugger.Break() as well, which did not work, because there is no debugger attached on start up of the service yet (causing the "Error 1067: The process terminated unexpectedly."). RequestAdditionalTime sets a longer timeout for the startup of the service (it is not delaying the code itself, but will immediately continue with the Debugger.Launch statement). Otherwise the default timeout for starting the service is too short and starting the service fails if you don't call base.Onstart(args) quickly enough from the debugger. Practically, a timeout of 10 minutes avoids that you see the message "the service did not respond..." immediately after the debugger is started. Once you get used to it, this method is very easy because it just requires you to add 4 lines to an existing service code, allowing you quickly to gain control and debug.
为了调试Windows服务,我结合了GFlags和一个由regedit创建的.reg文件。
运行GFlags,指定ex -name和vsjitdebugger 运行regedit并转到GFlags设置选项的位置 从文件菜单中选择“导出密钥” 将该文件保存在扩展名为.reg的某处 任何时候你想调试服务:双击.reg文件 如果要停止调试,请双击第二个.reg文件
或者保存以下代码片段并用所需的可执行名称替换servicename.exe。
debugon.reg:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe] "GlobalFlag"="0x00000000" "Debugger"="vsjitdebugger.exe"
debugoff.reg:
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe] "GlobalFlag"="0x00000000"
更新
这种方法是目前为止最简单的:
http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx
我把最初的答案留给后人。
我的服务倾向于有一个封装定时器的类,因为我想让服务定期检查它是否有任何工作要做。
我们在服务启动期间更新类并调用StartEventLoop()。(这个类也可以很容易地从控制台应用程序中使用。)
这种设计的一个很好的副作用是,可以使用用来设置Timer的参数在服务实际开始工作之前有一个延迟,这样就有时间手动附加调试器。
p.s. .如何手动将调试器附加到正在运行的进程…?
using System;
using System.Threading;
using System.Configuration;
public class ServiceEventHandler
{
Timer _timer;
public ServiceEventHandler()
{
// get configuration etc.
_timer = new Timer(
new TimerCallback(EventTimerCallback)
, null
, Timeout.Infinite
, Timeout.Infinite);
}
private void EventTimerCallback(object state)
{
// do something
}
public void StartEventLoop()
{
// wait a minute, then run every 30 minutes
_timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
}
}
我也曾经做过以下事情(在之前的回答中已经提到过,但是使用条件编译器[#if]标志来帮助避免它在发布构建中被触发)。
我不再这样做了,因为有时我们会忘记在发布中构建,并在客户端演示上运行的应用程序中出现调试器中断(尴尬!)
#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
#endif
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 为什么Visual Studio 2015/2017/2019测试运行器没有发现我的xUnit v2测试
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 我如何找到哪个程序正在使用端口80在Windows?
- 在Windows中有像GREP这样的模式匹配实用程序吗?
- 没有ListBox。SelectionMode="None",是否有其他方法禁用列表框中的选择?
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 如何在Windows命令提示符下运行.sh ?