可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm developing a Windows Service in VB.NET 2008, but I feel like I'm going to have an aneurysm. To debug the service, I've added a 15 second wait to the initialization code, which gives me time to start the service and attach the .NET debugger before anything happens, so I can hit breakpoints and such. I really miss "integrated" debugging with this type of workaround, and testing seems to be a huge pain.
What's the best way to do "regular" debugging of a Windows Service that's in development? One option I'd considered was moving all of my logic to a DLL project, leaving only control logic in the service itself, and then creating a Forms project that essentially just had "start" and "stop" buttons on it, and called into the DLL to do everything else. This way, I can debug my code normally, and then just deploy the compiled service when the DLLs are ready.
Does this make sense/annoy others? I'm open to any workarounds available. PB's suggestion here sounds like what I'm asking - has anybody used this approach?
回答1:
回答2:
If you can handle a little C#, this is the way I do it.
Assuming you have a class MainService derived from ServiceBase with an onStart Method then, when not running inside the debugger, the service starts normally, otherwise the onStart is called manually which runs the code in console mode.
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");
}
回答3:
Apart from use of Debugger.Break(), which several others have already mentioned, I write all my service code in a seperate assembly to the actual windows service project itself. I then also write a windows console app that calls the same service code. This lets me debug in the IDE just by setting the console app as the startup project.
The windows service project and the windows console application themselves literally do nothing except call the service "core" code, so the scope for defects due to the differences between the service and the console app are minimal.
回答4:
When I develop a Windows service using .NET, I take advantage of unit tests plus TypeMock so that I can run the code of the service in a unit test, without having to attach to a running instance of the service. Other mocking frameworks you could look at include Rhino Mocks.
So my plan was to use MSTest to create the unit test project and test methods that run against my service, and any run-time dependencies would be handled by TypeMock, which would create mock objects for my service to use. So if my service was handling stuff to do with files, for example, then I could create a mock file, using TypeMock, and use that in my unit test to pass to the service.
In the past, I went through the pain of compiling the service, installing it, running it and attaching, etc. When I discovered mock frameworks, it was such a great feeling being able to test my code with a single click of a button from the Visual Studio IDE.
Give it a try.
回答5:
Another way is to go to service1.designer.vb file, locate and "encapsulate" the following method code like this:
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
Hope this help for those programers with legacy code out there ;)
Credits go to a fellow programmer, who teached it to me.
回答6:
I've built a WCF Service that executes as a Command Line application with a .EXE extension. This allows me to load the application easily in debug or outside of VS by just double clicking it. I then have another project that is a Windows Service Host and has a reference to my WCF Service project. The Host Service can handle the .exe file in the same way as a .dll file.
This might have issues that I've not experienced so I can't recommend it as a "best practice" but it does work very well for me and solves the issues you are dealing with.
回答7:
I write my windows services as a console application, then just move the init code from Main to the Service_Start command. This works for most services. You can still test the Stop/Start functionality of a service through a console application too.
回答8:
Like leppie and others have said, including PB's suggestion, use:
Debugger.Break()
But also remember that once your service is running, you can attach VS.NET to the running service process and set breakpoints. Of course, if the code at the breakpoint gets hit automatically, you'll need to attach fast, but in my case, my service handles requests, so I attach to the service and trigger the request.
回答9:
Read Debugging a .Net Windows Service the "easy way". In this article, Mark Pearce describes how to debug a .Net Windows service from Visual Studio. Essentially it boils down to the following code snippet, but read the article for the full solution.
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