Search code examples
c#wcfobjectwindows-servicesnet.pipe

Getting a Windows Service to send active values back to WCF client


I have a Windows service that uses net.pipe as a WCF server and a Windows forms client to connect to it. There is a class called ConfigSettings that has values I want the client to query.

I want to have the client read the current values inside the serviceConfig instance that the service uses. Ultimately, I want the client to change values in it, but baby steps first.

The form can talk to the server via named pipes, but 'return serviceConfig is sending a new empty instance back to the client. I want the data that the service is actively using (that is, serviceConfig.Setting1 = x; serviceConfig.Setting2 = "foo"; )

The Windows service and WCF server code is (updated to working version):

using System.IO;
using System.ServiceModel;
using System.ServiceProcess;

namespace WindowsServiceTest
{
    public partial class Service1 : ServiceBase
    {
        internal static ServiceHost myServiceHost = null;

        //this is the master config that the service uses
        public static ConfigSettings serviceConfig = new ConfigSettings();

        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            if (myServiceHost != null)
            {
                myServiceHost.Close();
            }
            myServiceHost = new ServiceHost(typeof(WCFService1));
            myServiceHost.Open();

            //set active default settings
            serviceConfig.Setting1 = 1;
            serviceConfig.Setting2 = "initial.Setting2:" + serviceConfig.Setting1;
        }

        protected override void OnStop()
        {
            if (myServiceHost != null)
            {
                myServiceHost.Close();
                myServiceHost = null;
            }
        }
    }

    public partial class WCFService1 : IService1
    { 
        public ConfigSettings GetConfig()
        {
            return Service1.serviceConfig;
        }

        public void SetConfig(ConfigSettings sentConfig)
        {
            Service1.serviceConfig = sentConfig;
        }
    }

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        ConfigSettings GetConfig();

        [OperationContract]
        void SetConfig(ConfigSettings sentConfig);
    }

    public class ConfigSettings
    {
        public int Setting1 { get; set; }
        public string Setting2 { get; set; }
        public ConfigSettings() { }
    }
}

The client retrieves the config like this (updated with some changes):

using System;
using System.ServiceProcess;
using System.Windows.Forms;
using WindowsServiceTest;

namespace WindowsServiceTestForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        ConfigSettings config = new ConfigSettings();

        //GetConfig()
        private void button1_Click(object sender, EventArgs e)
        {
            ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
            ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
            //get the current config and display
            config = myService.GetConfig();
            MessageBox.Show(config.Setting1 + "\r\n" + config.Setting2, "config");
            myService.Close();
        }
        //SetConfig(ConfigSettings)
        private void button2_Click(object sender, EventArgs e)
        {   //make changes to values
            config.Setting1 += 1;
            config.Setting2 = "new.Setting2:" + config.Setting1;

            ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
            ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
            //send the new config
            myService.SetConfig(config);
            myService.Close();
        }
    }
}

Update: Maybe what I'm thinking needs to be done is overkill. It seems that I'm hitting a membrane between WCF and the Windows Service.

How would YOU approach this problem?

  • Windows Service that needs a Form for configuration.
  • When service starts, it loads a config.xml file from disk. (a serialized class)
  • When GUI starts, I want to:
    • retrieve its current configuration,
    • make some changes to it,
    • push it back to the service,
    • trigger service to re-read and react to the new configuration.

I was trying to avoid statically/writing the config file to disk and telling service to re-read it again. It "seemed" like WCF was the way to go.

Update 2 It seems that by just changing the master config in the service to static, the WCF service can access it directly. I could have sworn I did that originally before I posted, but I guess not.

I also separated the naming of Service1 to WCFService1 above, but it turns out that doesn't matter and works either way.

New complete code has been updated above.


Solution

  • You are getting confused between Windows Service and WCF Service - and have tried to have them both in the same class - while this is possible - it is probably easier to understand if you split them into two classes.

    In your example the Windows Service starts, creates a new instance of itself as the WCF service then sets the config elements in the Windows Service instance, meaning the config is empty in the WCF Service instance.

    try this instead

    using System.ServiceModel;
    using System.ServiceProcess;
    
    namespace WindowsServiceTest
    {
        public partial class Service1 : ServiceBase
        {
            internal static ServiceHost myServiceHost = null;
    
            public Service1()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                if (myServiceHost != null)
                {
                    myServiceHost.Close();
                }
                myServiceHost = new ServiceHost(typeof(WCFService1 ));
                myServiceHost.Open();
    
    
            }
    
            protected override void OnStop()
            {
                if (myServiceHost != null)
                {
                    myServiceHost.Close();
                    myServiceHost = null;
                }
            }
        }
    
        public class WCFService1 : IService1
        {
            public WCFService1()
            {
                //change master settings from null
                myConfig.Setting1 = "123";
                myConfig.Setting2 = "456";
            }
    
            //this is the master config that the service uses
            public ConfigSettings myConfig = new ConfigSettings();
    
            public ConfigSettings GetConfig()
            {
                return myConfig;
            }
        }
    
        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            ConfigSettings GetConfig();
        }
    
        public class ConfigSettings
        {
            public string Setting1 { get; set; }
            public string Setting2 { get; set; }
    
            public ConfigSettings()
            { }
        }
    }