2

Looking at the documentation it seems like Windows uses it in 2 scenarios:

  1. The ServiceBase.ServiceName needs to be the same name as when it is installed, however when starting my service I am able to call ServiceBase.Run() without specifying the service name or specifying a different service name altogether and my application still starts correctly. I am using a separate WiX project to install my service and define the service name there depending on some TRANSFORMS.

  2. Windows uses the ServiceBase.ServiceName to specify the EventLog.Source. I am successfully able to use Log4Net's EventLogAppender to log to the EventLog, manually specifying the applicationName in my log4net configs.

I want to make sure that I don't run into any repercussions down the road in the case that I don't specify the ServiceName correctly, however I am currently able to hit all my typical use cases as is. After calling ServiceBase.Run() I am able to use System.Management to determine my service name in case of any additional needs.

My main concern with avoiding setting the service name here is because my MSI installer can install different instances of my exe as different services via TRANSFORMs I create a sort of chicken-and-egg problem where I can't call GetServiceName() without calling ServiceBase.Run(), but I can't call ServiceBase.Run() without defining the ServiceBase.ServiceName.

Some example code of what I am running:

public aync Task<int> RunAsync()
{
    var serviceToRun = new ServiceBase{/*ServiceName = "Avoiding.."*/};

    var runServiceTask = Task.Run(() => ServiceBase.Run(serviceToRun));

    logger.Warn($"ServiceName   : '{GetServiceName()}'");
    logger.Warn($"Service ShortName : '{serviceToRun.ServiceName}'");

    await runServiceTask.ConfigureAwait(false);
    return serviceToRun.ExitCode;
}

public string GetServiceName()
{
    var processId = Process.GetCurrentProcess().Id;
    var query = $"SELECT * FROM Win32_Service where ProcessId = {processId}";
    var managementObject = new ManagementObjectSearcher(query).Get().Cast<ManagementObject>().FirstOrDefault();

    if (managementObject == null)
    {
        throw new Exception("Could not get service name");
    }

    var serviceName = managementObject["Name"].ToString();
    return serviceName;
}
Community
  • 1
  • 1
Paul Milla
  • 255
  • 1
  • 13
  • 2
    According [to the documentation for SERVICE_TABLE_ENTRY](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686001(v=vs.85).aspx) the service name is ignored provided the service type is `SERVICE_WIN32_OWN_PROCESS` so you can probably get away with this even if the .NET documentation doesn't mention it. – Harry Johnston Jan 09 '17 at 20:10
  • (There are other problems with the posted code, however. You're supposed to be subclassing `ServiceBase` so that you can provide `OnStart` and possibly `OnStop` functions. And you're meant to call Run() directly from your main function.) – Harry Johnston Jan 09 '17 at 20:12
  • 1
    The *canonical* solution to this problem is to pass the service name as a command-line argument, though I'm not sure how you do that in .NET, or alternatively to rename the executable for each particular instance to be the same as the service name. (You should be able to look up the executable name easily enough.) – Harry Johnston Jan 09 '17 at 20:14
  • Fair enough! I'm giving this part a bit of a rewrite and extending ServiceBase properly is definitely on the todo list. However as I came across this issue I figured my problem won't really change if I define ServiceName here or in a subclass and this snippet of code is much easier to digest. – Paul Milla Jan 09 '17 at 21:25

0 Answers0