locked
Establishing 2-Way communication between Windows Service and a Windows Application Also between a windows service and a web service

    Question

  • I am trying an application that requires me to establish two way communication between a Windows Service And a Windows Application. I know how to develop each one seperately. I looked into .net remoting. Windows service class typically inherited from ServiceBase so I can't inherit that from MarshallByRefObject, which is a must for the .NET remoting. So how can do this one? Also I need to make the same Window Service to communicate with a WebService. Any idea for full or partial solution would be great.

    Thank You

    Wednesday, May 12, 2010 4:36 AM

Answers

  • Okay, here is a code example, it is a bit quick and dirty but it's just to get the idea across.

    Let's say I keep the settings for a windows service in a class called 'ServiceSetting'

     

     public interface IServiceSettings
     {
     void ChangeSetting(string key, string value);
     string GetSetting(string key);
     }
    

     

    I then implement this in two classes. The first one is for internal use, used as singleton and can fire an event once a setting is chaged

    public class InternalSettings : IServiceSettings
     {
     public delegate void SettingChangedHandler(string key, string value);
     public event SettingChangedHandler SettingChanged;
    
     static InternalSettingsManager _instance;
     static object _syncRoot = new object();
     public static InternalSettings Instance
     {
      get
      {
      if (_instance == null)
      {
       lock (_syncRoot)
       {
       if (_instance == null) _instance = new InternalSettings();
       }
      }
      return _instance;
      }
     }
    
     private IDictionary<string, string> _properties;
     private InternalSettings()
     {
     
     }
    
     public string GetSetting(string key)
     {
      if (_properties.ContainsKey(key)) return _properties[key];
      return null;
     }
    
    
     public void ChangeSetting(string key, string value)
     {
      // change setting somehow ..
      if (this.SettingChanged != null) this.SettingChanged(key, value);
     }
    
     }

    I then make a second implementation, to be used in the remoting environment. This class is just a proxy and uses the other singleton to read and store the properties. As they run in the same AppDomain they both have access to the same instance.

    public class ServiceSettings : MarshalByRefObject, IServiceSettings
     {
    
     public ServiceSettings()
     {
      _properties = new Dictionary<string, string>();
     }
    
     public string GetSetting(string key)
     {
      return InternalSettingsManager.Instance.GetSetting(key);
     }
    
     
     public void ChangeSetting(string key, string value)
     {
      InternalSettingsManager.Instance.ChangeSetting(key, value);
     }
     }
    

     

    Now I can use remoting configuration to instantiate the ServiceSettings class :

     

     <system.runtime.remoting>
     <application>
     <service>
     <wellknown type="interfaces.ServiceSettings, interfaces"
       objectUri="config"
       mode="Singleton" ></wellknown>
     </service>
     <channels>
     <channel ref="http" port="8080" />
     </channels>
     </application>
     </system.runtime.remoting>

     

    and use that in code (and bind to the event):

     

     

    class Program
     {
     static void Main(string[] args)
     {
      Console.WriteLine("press any key to exit.");
      string configfilename = System.Reflection.Assembly.GetEntryAssembly().Location + ".config";
      RemotingConfiguration.Configure(configfilename, false);
      InternalSettingsManager.Instance.SettingChanged += new InternalSettingsManager.SettingChangedHandler(Instance_SettingChanged);
      Console.ReadLine();
     }
    
     static void Instance_SettingChanged(string key, string value)
     {
      Console.WriteLine(key + "=>" + value);
     }
     }

     

    A client would then just need this code:

     

     

     IServiceSettings settings = Activator.GetObject(typeof(IServiceSettings), @"http://127.0.0.1:8080/config") as IServiceSettings;
    settings.ChangeSetting("foo", "bar");
    Console.WriteLine(settings.GetSetting("foo")); ;
    I hope you get the idea.

     

     

     

     

    • Marked as answer by jcarter121212 Thursday, May 13, 2010 3:10 AM
    Wednesday, May 12, 2010 9:38 PM

All replies

  • You don't need to expose the actual service object via remoting. Instead, you can create an object, derived from MarshallByRefObject, use that from within your service and expose that using remoting. Let me know if you need a code example.
    Wednesday, May 12, 2010 10:46 AM
  • BUt then you have a Class1:ServiceBase & Class2:MarshallByRefObject, right. You are saying expose Class2 object via Class1 using TcpChannel, Say 1111. When a client connects to the same channel 1111 and calls a function inside Class2 object, how does Class1 know that the client is in need of something that Class1 really has but is asked via Class2 function. To put in another way, Client is interested in data that Class1 has. Class2 is simply a mediator between both the Client and Class1. Since Class1 is creating class2 object and exposing, how does class2 object function let class1 know about the client need in upward fashion. Please let me know.

     

    Thank You 

    Wednesday, May 12, 2010 12:27 PM
  • Hi qDocter,

    Could you also tell me little bit about communication between Windows Service <-> Web Service. Does it work similar to a Windows Service <-> Windows app. Because web is more like a session less communication, right. Where as TcpChannel is pretty much like a dedicated channel. Please let me know how to make a successfull 2-way communication between a Windows Service to both a Windows application and a Web service. Any code example would be highly appreciated.

     

    Thank you

     

    Wednesday, May 12, 2010 12:53 PM
  • Okay, here is a code example, it is a bit quick and dirty but it's just to get the idea across.

    Let's say I keep the settings for a windows service in a class called 'ServiceSetting'

     

     public interface IServiceSettings
     {
     void ChangeSetting(string key, string value);
     string GetSetting(string key);
     }
    

     

    I then implement this in two classes. The first one is for internal use, used as singleton and can fire an event once a setting is chaged

    public class InternalSettings : IServiceSettings
     {
     public delegate void SettingChangedHandler(string key, string value);
     public event SettingChangedHandler SettingChanged;
    
     static InternalSettingsManager _instance;
     static object _syncRoot = new object();
     public static InternalSettings Instance
     {
      get
      {
      if (_instance == null)
      {
       lock (_syncRoot)
       {
       if (_instance == null) _instance = new InternalSettings();
       }
      }
      return _instance;
      }
     }
    
     private IDictionary<string, string> _properties;
     private InternalSettings()
     {
     
     }
    
     public string GetSetting(string key)
     {
      if (_properties.ContainsKey(key)) return _properties[key];
      return null;
     }
    
    
     public void ChangeSetting(string key, string value)
     {
      // change setting somehow ..
      if (this.SettingChanged != null) this.SettingChanged(key, value);
     }
    
     }

    I then make a second implementation, to be used in the remoting environment. This class is just a proxy and uses the other singleton to read and store the properties. As they run in the same AppDomain they both have access to the same instance.

    public class ServiceSettings : MarshalByRefObject, IServiceSettings
     {
    
     public ServiceSettings()
     {
      _properties = new Dictionary<string, string>();
     }
    
     public string GetSetting(string key)
     {
      return InternalSettingsManager.Instance.GetSetting(key);
     }
    
     
     public void ChangeSetting(string key, string value)
     {
      InternalSettingsManager.Instance.ChangeSetting(key, value);
     }
     }
    

     

    Now I can use remoting configuration to instantiate the ServiceSettings class :

     

     <system.runtime.remoting>
     <application>
     <service>
     <wellknown type="interfaces.ServiceSettings, interfaces"
       objectUri="config"
       mode="Singleton" ></wellknown>
     </service>
     <channels>
     <channel ref="http" port="8080" />
     </channels>
     </application>
     </system.runtime.remoting>

     

    and use that in code (and bind to the event):

     

     

    class Program
     {
     static void Main(string[] args)
     {
      Console.WriteLine("press any key to exit.");
      string configfilename = System.Reflection.Assembly.GetEntryAssembly().Location + ".config";
      RemotingConfiguration.Configure(configfilename, false);
      InternalSettingsManager.Instance.SettingChanged += new InternalSettingsManager.SettingChangedHandler(Instance_SettingChanged);
      Console.ReadLine();
     }
    
     static void Instance_SettingChanged(string key, string value)
     {
      Console.WriteLine(key + "=>" + value);
     }
     }

     

    A client would then just need this code:

     

     

     IServiceSettings settings = Activator.GetObject(typeof(IServiceSettings), @"http://127.0.0.1:8080/config") as IServiceSettings;
    settings.ChangeSetting("foo", "bar");
    Console.WriteLine(settings.GetSetting("foo")); ;
    I hope you get the idea.

     

     

     

     

    • Marked as answer by jcarter121212 Thursday, May 13, 2010 3:10 AM
    Wednesday, May 12, 2010 9:38 PM
  • Thank you for the nice code. That helps me a lot with the Windows App <-> Windows Service.

    How can I do for the WebService to Windows Service?

     

    Once again thank you

    Thursday, May 13, 2010 3:13 AM