我正在VB.NET 2008中开发一个Windows服务,但我觉得我会有一个动脉瘤。为了调试服务,我在初始化代码中添加了15秒的等待,这使我有时间启动服务并在发生任何事情之前附加.NET调试器,因此我可以点击断点等。我真的很想念这种类型的解决方案的“集成”调试,测试似乎是一个巨大的痛苦。
对正在开发的Windows服务进行“常规”调试的最佳方法是什么?我考虑过的一个选项是将我的所有逻辑移到DLL项目中,只在服务本身中保留控制逻辑,然后创建一个基本上只有“开始”和“停止”按钮的Forms项目,并调用DLL做其他一切。这样,我可以正常调试我的代码,然后在DLL就绪时部署已编译的服务。
这是否有意义/惹恼别人?我愿意接受任何可用的解决方法。 PB的建议here听起来就像我问的那样 - 是否有人使用过这种方法?
答案 0 :(得分:13)
如果你能处理一点C#,这就是我的方式。
假设你有一个使用onStart方法派生自ServiceBase的类MainService,那么当没有在调试器内运行时,服务会正常启动,否则会手动调用onStart,它会以控制台模式运行代码。
static void Main(string[] args)
{
// If no command line arguments, then run as a service unless we are debugging it.
if ( args.Length == 0)
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
args = new string[] { "/NonService"} ;
}
else
args = new string[] { "/Service"} ;
}
string cmdLine = args[0].ToLower().Substring(1);
Console.WriteLine("Starting Program with Cmdline : " + args[0]);
switch (cmdLine)
{
case "service" :
ServiceBase.Run(new MainService());
break;
case "nonservice" :
MainService ms = new MainService();
ms.OnStart(null);
break;
...
default :
Console.Error.WriteLine("Unknown Command line Parameter");
Console.Error.WriteLine("Supported options are /Install /Uninstall /Start /Stop /Status /Service and /NonService");
}
答案 1 :(得分:11)
除了使用Debugger.Break()之外,其他几个人已经提到过,我将所有服务代码都以单独的程序集写入实际的Windows服务项目本身。然后我还编写了一个调用相同服务代码的Windows控制台应用程序。这样我就可以通过将控制台应用程序设置为启动项目来在IDE中进行调试。
Windows服务项目和Windows控制台应用程序本身除了调用服务“核心”代码之外什么都不做,因此由于服务和控制台应用程序之间的差异导致的缺陷范围很小。
答案 2 :(得分:8)
Debugger.Break()
:)
答案 3 :(得分:6)
当我使用.NET开发Windows服务时,我利用单元测试加上TypeMock,这样我就可以在单元测试中运行服务代码,而不必附加到正在运行的实例服务。您可以查看的其他模拟框架包括Rhino Mocks。
所以我的计划是使用MSTest创建单元测试项目和针对我的服务运行的测试方法,任何运行时依赖项都将由TypeMock处理,这将为我的服务创建模拟对象。例如,如果我的服务处理与文件有关的事情,那么我可以使用TypeMock创建一个模拟文件,并在我的单元测试中使用它来传递给服务。
在过去,我经历了编译服务,安装,运行和附加等的痛苦。当我发现模拟框架时,只需单击一下即可测试我的代码是一种很棒的感觉。 Visual Studio IDE中的一个按钮。
试一试。
答案 4 :(得分:3)
另一种方法是转到service1.designer.vb文件,找到并“封装”以下方法代码,如下所示:
Shared Sub Main()
#If DEBUG Then
Dim servicio As New Service1
servicio.OnStart(Nothing)
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite)
#Else
Dim ServicesToRun() As System.ServiceProcess.ServiceBase 'original code
ServicesToRun = New System.ServiceProcess.ServiceBase() {New Service1} 'original code
System.ServiceProcess.ServiceBase.Run(ServicesToRun) 'original code
#End If
希望对那些有遗留代码的程序员提供帮助;) 积分给了一个程序员,他把它教给我。
答案 5 :(得分:2)
我已经构建了一个WCF服务,该服务作为具有.EXE扩展名的命令行应用程序执行。这使我只需双击即可在调试或VS外部轻松加载应用程序。然后我有另一个项目是Windows服务主机,并且引用了我的WCF服务项目。 Host Service可以像处理.dll文件一样处理.exe文件。
这可能会有一些我没有遇到过的问题所以我不能推荐它作为“最佳实践”,但它对我来说非常有效,并且解决了你正在处理的问题。
答案 6 :(得分:2)
我将Windows服务编写为控制台应用程序,然后将init代码从Main移动到Service_Start命令。这适用于大多数服务。您仍然可以通过控制台应用程序测试服务的停止/启动功能。
答案 7 :(得分:1)
像leppie和其他人所说的那样,包括PB's suggestion,请使用:
Debugger.Break()
但请记住,一旦您的服务运行,您可以将VS.NET附加到正在运行的服务进程并设置断点。当然,如果断点处的代码被自动命中,你需要快速附加,但在我的情况下,我的服务处理请求,所以我附加到服务并触发请求。
答案 8 :(得分:-1)
阅读Debugging a .Net Windows Service the "easy way"。在本文中,Mark Pearce描述了如何从Visual Studio调试.Net Windows服务。基本上它归结为以下代码片段,但请阅读文章以获得完整的解决方案。
Shared Sub Main()
#If DEBUG Then
Dim DebugService As New ServiceAdmin
DebugService.OnStart(Nothing)
#Else
Dim ServicesToRun() As System.ServiceProcess.ServiceBase
ServicesToRun = New System.ServiceProcess.ServiceBase() {New ServiceAdmin()}
System.ServiceProcess.ServiceBase.Run(ServicesToRun)
#End If
End Sub