
Introduction
Recently, I ran into a problem while developing a client/server application. I needed to turn the server (console application) into a service so that it would run when the server started, without having to log into the machine. In the past, I would have left the console application as-is, started another project as the actual service and have it launch the console application. Then I would to start yet another project to do the actual installing and uninstalling of the service. Many of you might have used a similar technique and I'm sure you can all agree that having three executable files for switching between console and service is a real pain. So, I went scouring the internet and found an excellent article by Chris Mullins which put me in the right direction.
Using the code
If you have already created the console application, you will need to move it from the Program.cs file to the ConsoleApplication.cs class provided in the demo application. This may take some work if you built your entire application in the Program.cs file. If you haven't built your application yet, you're in luck as it's very simple to use this code. I would recommend using the demo project as your new project, as everything you need is already there. All you need to do is build your application in ConsoleApplication.cs, using the constructor as you would use the entry point of Program.cs. Here is a quick example of using the ConsoleApplication.cs file:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace HybridService
{
class ConsoleApplication
{
public ConsoleApplication(string applicationPath, bool consoleMode)
{
Console.WriteLine("Hybrid Service Application");
Console.WriteLine();
StreamWriter stream =
new StreamWriter(applicationPath + "\\output.txt", true);
stream.WriteLine(DateTime.Now.ToString("f") + " It works! \n");
stream.Flush();
stream.Close();
stream.Dispose();
Console.WriteLine(
"I have written to " + applicationPath + "\\output.txt");
Console.WriteLine("Press any key to exit...");
if (consoleMode) Console.ReadKey();
Environment.Exit(0);
}
public void Close()
{
}
}
}
You will also need to open the Program.cs file and give your application a name that will be displayed in the Services window.
applicationTitle = "My Hybrid Service";
Running the application
If you were to start debugging this application right now, it would show up as a console window. This is great for testing and debugging, but when you're ready to move it into production as a service, you would normally need to jump through hoops. Then if you needed to debug something, you would have to jump through those hoops all over again, but not anymore! Now it is easier than ever to switch between console and service. You don't even have to change your code. All you need to do is build your project, open a Command Window, navigate to your project's Release folder, and use the following command line argument:
HybridService -service
Your program will now install the service and run it once it's installed. It has also been configured to start when your machine boots. If you need to make changes to the program, stop the service and rebuild your application. That's it. Once you're done testing it in production, you will need to uninstall the service so that it doesn't linger on your machine. Use this command line argument:
HybridService -noservice
Your service has now been stopped (if it was running) and uninstalled.
Points of interest
I personally think this is the greatest thing since sliced bread, but I'm biased. However, there are some things that you need to be aware of:
- You cannot have spaces in your executable's name, and its extension must be .exe
- Since you aren't running your code in a static class, you cannot use "return" or
Application.Exit()
. You have to use Environment.Exit(0)
to end your application.
- Avoid using
Console.Read()
or any other blocking calls requiring user-input. If you need to use it only in console mode, check for the consoleMode
argument. The above example demonstrates this.
- Don't use
Environment.CurrentDirectory
unless you want it to return the System32 folder. Use the applicationPath
argument instead. Again, this is demonstrated above.
- Before renaming or moving your executable, make sure it is NOT installed as a service!
- You cannot install your application as a service if the executable is not on your local machine. Trying to install the service from a network drive will NOT work.
- Another little annoying Windows'ism is that you MUST close the Services window when you uninstall the service or it will stay in the list of services until you close it. Refreshing the window will NOT work. You have to close and re-open it.
Final notes
I would, again, like to thank Chris Mullins for posting his code. As for the ServiceInstaller, it is a modified version of some code I found about a year ago. I can't remember who the original author was, but if you know, send me a link to the original code and I'll post a thank-you to him/her as well. I hope this code helps someone. It has helped me quite a bit. Also, I would appreciate some feedback. This is my first post to CodeProject, so I'm interested in learning how I did. If you find any problems, let me know. If you use this in your project, I only ask that you give me credit for it in your application.
History
- 2007-06-22: Article posted