Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Configure Windows Service while Running (C# .Net)

Options
  • 06-09-2011 8:44pm
    #1
    Registered Users Posts: 683 ✭✭✭


    Hey,

    I'm just messing about with Windows Services through .Net and was wondering what the best method of changing attributes within the service would be.

    e.g. lets say there's a timer performing some polling at an interval. What would be the best method of changing the interval? One method would be to have the settings in a configuration file and each time the timer elapses, reload the configuration from the file and set the interval to the appropriate value, but are there better more appropriate methodologies?

    J.


Comments

  • Registered Users Posts: 9,294 ✭✭✭markpb


    If you want to keep the settings in a config file, you can register a callback so you're notified whenever the contents of the file changes instead of polling.

    Other options are to expose a WMI interface or listen for network connections using WCF (.net remoting, soap, etc). You could go all out and add a telnet server where people connect and execute commands, view traces, etc but that's probably overkill for most situations.


  • Registered Users Posts: 2,023 ✭✭✭Colonel Panic


    I've gone the FileSystemWatcher and WCF route suggested by markpb. Both are simple enough, but the former is definitely the lowest entry cost if you only want to configure the service on the local machine.


  • Registered Users Posts: 1,691 ✭✭✭JimmyCrackCorn


    I've gone the FileSystemWatcher and WCF route suggested by markpb. Both are simple enough, but the former is definitely the lowest entry cost if you only want to configure the service on the local machine.


    Just a heads up fileSystemWatcher can fail to event over network shares.

    Polling can work more reliable.


  • Registered Users Posts: 683 ✭✭✭JazzyJ


    Thanks guys,

    Forgot entirely about the FileSystemWatcher - haven't worked with .Net for a while!

    I had a look at the WCF route using web services, and am fine with hosting the web services, but can't figure out how to modify the windows service attributes through the web service - haven't seen anything around this when searching for this on the web. Any pointers on this?


  • Registered Users Posts: 9,294 ✭✭✭markpb


    If you want to use WCF, you'll need to modify your Windows service so that it hosts the WCF service instead of letting IIS to do it. This means that your service runs as normal but it also listens for requests over http, .net remoting, etc. Since it's all part of the same application, you can change any parameter you like.

    Check out these two links to find out how to host a WCF service in an application.


  • Advertisement
  • Registered Users Posts: 683 ✭✭✭JazzyJ


    markpb wrote: »
    If you want to use WCF, you'll need to modify your Windows service so that it hosts the WCF service instead of letting IIS to do it. This means that your service runs as normal but it also listens for requests over http, .net remoting, etc. Since it's all part of the same application, you can change any parameter you like.

    Check out these two links to find out how to host a WCF service in an application.

    Thanks for the pointers there, but I don't have any problem with creating the webservices I just can't get my head around providing a link between the web service and the windows service/managed application.

    For example in the first link, how could a link be provided from HelloWorldService.SayHello method that modifies an attribute of the Program class.

    For example, when SayHello is called I want to be able to change the value of valueToChange in Program:
        public class HelloWorldService : IHelloWorldService
        {
            public string SayHello(string name)
            {
                  [COLOR="Red"]// do something here that modifies the [B]valueToChange[/B] attribute in the Program class below[/COLOR]
            }
        }
    
        class Program
        {
            [COLOR="Red"]public bool valueToChange = false; // this is the attribute that I want to change[/COLOR]
    
            static void Main(string[] args)
            {
                Uri baseAddress = new Uri("http://localhost:8080/hello");
    
                // Create the ServiceHost.
                using (ServiceHost host = new ServiceHost(typeof(HelloWorldService), baseAddress))
                {
    
         ...
            }
        }
    

    Presumably the HelloWorldService needs some knowledge of the Program class?

    Or am I approaching this all wrong? :confused:


  • Registered Users Posts: 2,023 ✭✭✭Colonel Panic


    No, it's the right approach, but the problem with WCF and the ServiceHost class make passing dependencies to the service instance really difficult.

    The solution is to write write classes the implement IInstanceProvider, IServiceBehavior and subclass ServiceHost.

    That said, the most common solution on the net is to use a single service instance (InstanceContextMode.Single) and let it interact with some static class that way.

    We use a dependency injection framework called Ninject so I wrote a WCF host for that, but it's a bit of extra work.

    EDIT: Here's how you could do it without resorting to global state.
    public class Program
    {
        public int Setting { get; set; }
    }
    
    [ServiceContract]
    public interface ISettingService
    {
        [OperationContract]
        void SetSetting(int setting);
    }
    
    public class SettingService : ISettingService
    {
        private readonly Program program;
    
        public SettingService(Program program)
        {
            this.program = program;
        }
    
        public void SetSetting(int setting)
        {
            program.Setting = setting;
        }
    }
    
    internal class CustomInstanceProvider : IInstanceProvider
    {
        private readonly Program program;
    
        public CustomInstanceProvider(Program program)
        {
            this.program = program;
        }
    
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return GetInstance(instanceContext);
        }
    
        public object GetInstance(InstanceContext instanceContext)
        {
            return new SettingService(program);
        }
    
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            IDisposable disposable = instance as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
    }
    
    internal class CustomInstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
    {
        private readonly IInstanceProvider instanceProvider;
    
        public CustomInstanceProviderBehaviorAttribute(IInstanceProvider instanceProvider)
        {
            this.instanceProvider = instanceProvider;
        }
    
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
            {
                foreach (EndpointDispatcher ed in cd.Endpoints)
                {
                    if (!ed.IsSystemEndpoint)
                    {
                        ed.DispatchRuntime.InstanceProvider = instanceProvider;
                    }
                }
            }
        }
    
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
    }
    
    public class CustomServiceHost : ServiceHost
    {
        private readonly Program p;
    
        public CustomServiceHost(Program program, params Uri[] baseAddresses)
            : base(typeof(SettingService), baseAddresses)
        {
            this.p = program;
        }
    
        protected override void OnOpening()
        {
            Description.Behaviors.Add(new CustomInstanceProviderBehaviorAttribute(new CustomInstanceProvider(p)));
            base.OnOpening();
        }
    }
    


  • Registered Users Posts: 683 ✭✭✭JazzyJ


    Only got around to looking at this now. The custom classes from Colonel Panic work really well.

    Thanks a million for all your help guys.


Advertisement