0

Problem

When I instantiate an instance of the Service class - derived from the ServiceBase class - the constructor I create for the Service class is skipped during instantiation. Then when the line "private ServiceController controller..." is hit, it fails because the ConfigStream object is never passed to the Service class variable _configstream. I don't have issues with constructors being skipped elsewhere in my code. Is this related to the use of the base class ServiceBase?

I've tried including the base class constructor like:

    public Service(ConfigStream configstream) : base() {}

It doesn't produce any different result. From what I've read, that makes sense because the default constructor of the base class should be called by default.

I've included the beginning of both my Service class and ConfigStream. ConfigStream utilizes its constructors without any issue, but its also not inheriting any classes.

Code

    public static class MainClass
    {
        static void Main(String[] args)
        {
            // Test if input arguments were supplied
            if (args.Length > 0)
            {
                // if arguments supplied, use the supplied config file path (second cli argument)
                if (args[0] == "-i")
                {
                    // ConfigStream configstream = new ConfigStream(args[1]);
                    ServiceBase.Run(new Service(new ConfigStream(args[1])));
                }
            }
            else
            {
                // otherwise run service without arguments
                // the config will be assumed in the same directory
                Service service = new Service(new ConfigStream());
                ServiceBase.Run(service);
            }
        }
    }
    public class Service : ServiceBase
    {
        // class instantiation
        private Thread processThread;
        private Process process;

        // Instance variables
        private static ConfigStream _configstream;

        // Function: Service
        // Purpose: Class Constructor
        public Service(ConfigStream configstream)
        {
            // assign ConfigStream instance
            _configstream = configstream;

            // set global service name and description for use by installer
            GlobalVariables.setServicename(_configstream.getSetting("Service Name"));
            GlobalVariables.setServicedesc(_configstream.getSetting("Service Description"));

            ServiceName = _configstream.getSetting("Service Name");

            //setting logger level
            logger.setLogLevel(0);

            logger.info("System Event", "Starting service");
            processThread = new Thread(ProcessManager);
            processThread.Start();

        }

        private ServiceController controller = new ServiceController(_configstream.getSetting("Service 
Name"));
       ...
    }

     public class ConfigStream
    {
        // set properties of ConfigStream
        public string config { get; private set; }

        // constructor with config as an argument
        public ConfigStream(string config_location)
        {
            string config = config_location;
        }

        // constructor with no arguments
        public ConfigStream()
        {
            config = GlobalVariables.cwd + "\\" + GlobalVariables.configFileName;
        }
        ...
    }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Matt Brauer
  • 211
  • 4
  • 13
  • `private ServiceController controller` is a field and is initialized before the constructor. – juharr Feb 25 '20 at 21:56
  • 3
    This is a common cause of confusion; I wrote a couple articles about this back in 2008 that might be helpful: https://learn.microsoft.com/en-us/archive/blogs/ericlippert/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one and https://learn.microsoft.com/en-us/archive/blogs/ericlippert/why-do-initializers-run-in-the-opposite-order-as-constructors-part-two – Eric Lippert Feb 25 '20 at 22:04

1 Answers1

1

When I instantiate an instance of the Service class - derived from the ServiceBase class - the constructor I create for the Service class is skipped during instantiation

It is not skipped. It's just the order of initialization that causes your problem.

Member fields are initialized first, before any constructor's code is run. Thus when the initializer of controller is called, an exception is thrown because _configStream is null. See this Q&A for further information.

Side note: In addition, it is a very bad idea to have the _configStream field declared static and at the same time initialize it from the constructor every time an instance is created.

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
  • That make sense. I am trying to retrieve parameters from the configstream object that will be passed for the initialization of the ServiceController within the Service class. If _configstream isn't static I get the error "a field initializer cannot reference a non-static field..." Since the initialization of controller is happening before the Service constructor, I'll need to rethink that strategy anyway. – Matt Brauer Feb 25 '20 at 22:37