Does a .NET Windows service require a call to ServiceBase.Run()
I'm fairly new at working with Windows services but I found a peculiar incident and I would like some clarification. I have a Windows service written in C# which I install and start using the command line (great instructions found on stackoverflow). The main method of my service looks like this:
static void Main(string[] args)
{
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
else if (args.Length == 1)
{
const string name = "MyServiceName";
Type type = typeof(MyAssembly);
switch (args[0])
{
case "-install":
ServiceUtils.InstallService(name, type);
ServiceUtils.StartService(args, name);
break;
case "-uninstall":
ServiceUtils.StopService(name);
ServiceUtils.UninstallService(name, type);
break;
default:
throw new NotImplementedException();
}
}
}
When I debug, I ALWAYS send one parameter (-install) to the application. Because of this, the first if statement (if (args.Length == 0)
is NEVER executed. This is expected and my service is installed and started just fine. However, if I remove that if statement and just leave the if (args.Length == 1)
statement, my service installs correctly but it does not start and I get the following error:
Cannot start MyServiceName on computer '.'
My question is: Why is the code in the first if statement needed when it is NEVER executed in my application?
Here is the supporting code for the InstallService and StartService methods (which I got from stackoverflow also):
public static void InstallService(string serviceName, Type t)
{
if (IsInstalled(serviceName)) return;
try
{
Assembly a = t.Assembly;
using (AssemblyInstaller installer = GetInstaller(a))
{
IDictionary state = new Hashtable();
try
{
installer.Install(state);
installer.Commit(state);
}
catch
{
try
{
installer.Rollback(开发者_StackOverflowstate);
}
catch
{ }
throw;
}
}
}
catch
{
throw;
}
}
public static void StartService(string[] args, string serviceName)
{
if (!IsInstalled(serviceName)) return;
Console.WriteLine("Service is installed. Attempting to start service.");
ServiceController sc = new ServiceController();
sc.ServiceName = serviceName;
if (sc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine("Starting {0}: ", sc.ServiceName);
try
{
sc.Start(args);
sc.WaitForStatus(ServiceControllerStatus.Running);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
the first if statement (if (args.Length == 0) is NEVER executed
That's not correct, it is executed. By ServiceController.Start(). You cannot see this because the service controller starts your EXE again, creating another process. A service process this time, not a console process. One that you don't have a debugger attached to. If you remove that if statement then the service immediately exits after getting started. And the service controller correctly complains about that with the "Cannot start MyServiceName" exception message.
if (args.Length == 0)
{
ServiceBase.Run(new MyServiceName());
}
is run when the service is started by the Service Controller, as the Service Controller doesn't pass any arguments in to Main().
If you don't do ServiceBase.Run(new MyServiceName())
, then your service will not respond to any commands from the Service Controller, and you get errors as the ones you see.
Main()
is still the entry point of the application. The process is started as a separate step from starting the service(s) within.
It's actually possible to have multiple services running in the same process, and this way of handling things enables that. That is... not just the same exe program, but actually in the same running process.
精彩评论