One of the most basic facts when developing applications under Windows is that as long as a program is running, its DLLs and executable cannot be overwritten. Probably you've experienced this behaviour. You want to replace a DLL with an updated version and Windows tells you, "The process cannot access the file because it is being used by another process." A look at the taskbar shows that in fact the application the DLL belongs to is still running.
While developing a desktop application, this usually isn't a big problem - you modify the code, rebuild and start debugging. When the code has to be modified, you simply shut down your application, perform the code changes and restart the application (or use edit and continue in the cases where this is supported).
Now if you don't develop a desktop application but a Windows Service, things usually tend to become a little clumsy, since you don't start and stop your service in the same way you start and stop a desktop application.
For this article, I've set up a simple solution where the service is used to publish a .NET remoting server.
ISample defines the interface for the remoting server;
Sample is the actual server implementation and
SampleService is the service responsible for publishing the remoting server. In order to be able to run and test the service, of course, it has to be installed first using InstallUtil.
I guess the most common approach is to install the service directly from the Debug directory. Once the service has been installed, you can start it via the service control panel. Everything is fine up to now, but when you have to modify your code (the service implementation, for example) the shortcomings of this approach become visible: rebuilding the
SampleService project will fail because the service is still running, thus locking Sample.dll and preventing Visual Studio from overwriting the DLL.
So you have to switch to the services control panel again, stop the service, go back to Visual Studio, rebuild again, go back to the control panel and restart the service. Honestly, I've followed this tedious manual pattern for quite a long time without giving it a second thought. But finally I asked myself, "Can't I simplify this whole procedure?"
Making It Easier
The solution turned out to be amazingly simple. The much underrated pre-build action comes to the rescue: I want the service to be stopped before rebuild and to be started once the rebuild is complete.
Services can be started and stopped with two simple commands from the command line:
net start <ServiceName> and
net stop <ServiceName>. By adding the command to stop the service during pre-build and the command to start the service during post-build, you don't have to perform these steps manually (and you cannot forget to perform them!) every time you rebuild.
Applying Final Polish
So now the service is being stopped automatically before the DLLs are being replaced and restarted automatically once the rebuild has been successful.
net stop returns a non-zero exit code when the service in question has not been started (yet). Because every pre-build action has to be executed successfully (with zero exit code) before Visual Studio continues the build process, you won't be able to build your solution unless the service is running. So we have to tweak the pre-build action a little. We don't care whether or not the service is running before rebuilding. All we want is that the service is not running during rebuild! By adding a simple
echo. to the pre-build action, we can ignore the exit code of
net stop and give Visual Studio the exit code of
echo instead (which always is zero).
By adding two simple lines to your build events you can simplify the process of developing a Windows service application. As an alternative for using
net stop you can also use sc.exe to control services from the command line. The syntax is almost identical for these commands, so it's more or less a matter of taste which command to use.
- 9th March, 2008 -- Original version posted
- 11th March, 2008 -- Article edited and moved to The Code Project main article base