K
Ken Allen
I have been experimenting with services written in C#/.Net, and have
resolved most of the questions that I had. However, I have encountered
some aspects that have me scratching my head.
From my research and experiments, there are at least three basic
service 'architectures':
1. A thread: in this approach, the OnStart() creates and starts a thread
(method from the service class) and OnStop() terminates the execution
of that thread. Quire straightforward.
2. A timer: in this approach a timer is declared in the service
constructor and an event handler (method in the service class) is
associated with the timer; the OnStart() starts the timer and the
OnStop() terminates the timer. Again, fairly simple.
3. A remoted object: in this case the Main() procedure registers a
channel and a well-known object (single-call in my case), and the
OnStart() and OnStop() routines do nothing. I believe that I cobbled
this one together from a book I had read, but I cannot recall for
certain, nor am I certain that this is the proper approach: perhaps the
OnStart() should register the channel and well-known object and the
onStop() should in-register them? (hmmm, how does one do that?)
Where I get confused in considering a service that is some combination
of the above. I have several needs of the next service that I want to
experiment with, but I am uncertain how to approach it as some needs are
met by each of the above architectures, but none meet all of them.
1. I want to be able to host multiple services inside the same
project/assembly. I have conducted enough experiments to understand how
to achieve this.
2. I want one of the services to act as a 'traffic cop', checking the
other services and restarting them if they fail. I was thinking of using
the second model above to invoke a timer event handler to perform the
check, and some experiments illustrated this will work. To make it
dynamic, I pass a list of service names into the constructor for this
service, but a better approach may be to pass the list via the OnStart.
----> Question: how can I pass in the list dynamically? Since all of the
services are auto-start, I suspect that the list shall have to be
specified at compile time or discovered dyanmically at runtime, perhaps
on the first execution of the timer.
3. An mentioned, all of the services shall be auto-started.
----> Question: if I confiure in the project the installer to use the
local system account, can I set the "allow to interact with the desktop"
as well? Or can this only be set from the service control manager?
4. I want the service to be able to check some configuration
information, likely in the regustry for now, and launch a number of
threads based on the configuraiton information. Stopping and starting
the service is acceptable as a means of changing the configuration, but
eventually I want to be able to reset the configuration at runtime. I
can do this in the OnStart() (should not take much time) for now, and I
could use a custom command to trigger this in the future - cool.
5. I also want to be able to connect a user interface to the set of
services and receive some output from them; not quite debugging
information, but tracing information, and I need to be able to do this
in release mode.
5a: If I use model (3) above, then the remoted object (which would have
to be a singleton) would permit procedure calls to retrieve information,
but what I really need is a 'push' -- I connect to the service and then
it begins giving me all of the details. More importantly, I do not see
how this model could permit the remoted class to initiate the processing
that the service is to perform, except in response to remote procedure
calls from a client, which may never come.
5b. I had contemplated using model (1) above, as the procedure passed to
the thread will do exactly what I wanted, and then have the service
pop-up a user interface in response to a custom command being received
(and hide it when another command is received). I have not had much luck
with this, mainly because I wanted the same form to be updated from all
of the services together, and the Invoke() command hung on a WaitOne()
call. This is after I set the "allow service to interact with desktop"
flag).
5c: What I really want is model (1) with some aspect of (3) so that
another application can put up the user interface and then connect to
the services and receive tracking information that is displayed. The
services should push the information so it appears in 'real time',
rather than depending on a polling approach from the client. It is not
clear to me how I would configure a service that launches a thread to
perform the processing and which also contains a remoted object that can
send updates to a user application.
Am I heading down some very bad tracks here? Is there a good book on
services out there? Something akin to the ".Net Multithreading" book by
Alan Dennis?
-ken
resolved most of the questions that I had. However, I have encountered
some aspects that have me scratching my head.
From my research and experiments, there are at least three basic
service 'architectures':
1. A thread: in this approach, the OnStart() creates and starts a thread
(method from the service class) and OnStop() terminates the execution
of that thread. Quire straightforward.
2. A timer: in this approach a timer is declared in the service
constructor and an event handler (method in the service class) is
associated with the timer; the OnStart() starts the timer and the
OnStop() terminates the timer. Again, fairly simple.
3. A remoted object: in this case the Main() procedure registers a
channel and a well-known object (single-call in my case), and the
OnStart() and OnStop() routines do nothing. I believe that I cobbled
this one together from a book I had read, but I cannot recall for
certain, nor am I certain that this is the proper approach: perhaps the
OnStart() should register the channel and well-known object and the
onStop() should in-register them? (hmmm, how does one do that?)
Where I get confused in considering a service that is some combination
of the above. I have several needs of the next service that I want to
experiment with, but I am uncertain how to approach it as some needs are
met by each of the above architectures, but none meet all of them.
1. I want to be able to host multiple services inside the same
project/assembly. I have conducted enough experiments to understand how
to achieve this.
2. I want one of the services to act as a 'traffic cop', checking the
other services and restarting them if they fail. I was thinking of using
the second model above to invoke a timer event handler to perform the
check, and some experiments illustrated this will work. To make it
dynamic, I pass a list of service names into the constructor for this
service, but a better approach may be to pass the list via the OnStart.
----> Question: how can I pass in the list dynamically? Since all of the
services are auto-start, I suspect that the list shall have to be
specified at compile time or discovered dyanmically at runtime, perhaps
on the first execution of the timer.
3. An mentioned, all of the services shall be auto-started.
----> Question: if I confiure in the project the installer to use the
local system account, can I set the "allow to interact with the desktop"
as well? Or can this only be set from the service control manager?
4. I want the service to be able to check some configuration
information, likely in the regustry for now, and launch a number of
threads based on the configuraiton information. Stopping and starting
the service is acceptable as a means of changing the configuration, but
eventually I want to be able to reset the configuration at runtime. I
can do this in the OnStart() (should not take much time) for now, and I
could use a custom command to trigger this in the future - cool.
5. I also want to be able to connect a user interface to the set of
services and receive some output from them; not quite debugging
information, but tracing information, and I need to be able to do this
in release mode.
5a: If I use model (3) above, then the remoted object (which would have
to be a singleton) would permit procedure calls to retrieve information,
but what I really need is a 'push' -- I connect to the service and then
it begins giving me all of the details. More importantly, I do not see
how this model could permit the remoted class to initiate the processing
that the service is to perform, except in response to remote procedure
calls from a client, which may never come.
5b. I had contemplated using model (1) above, as the procedure passed to
the thread will do exactly what I wanted, and then have the service
pop-up a user interface in response to a custom command being received
(and hide it when another command is received). I have not had much luck
with this, mainly because I wanted the same form to be updated from all
of the services together, and the Invoke() command hung on a WaitOne()
call. This is after I set the "allow service to interact with desktop"
flag).
5c: What I really want is model (1) with some aspect of (3) so that
another application can put up the user interface and then connect to
the services and receive tracking information that is displayed. The
services should push the information so it appears in 'real time',
rather than depending on a polling approach from the client. It is not
clear to me how I would configure a service that launches a thread to
perform the processing and which also contains a remoted object that can
send updates to a user application.
Am I heading down some very bad tracks here? Is there a good book on
services out there? Something akin to the ".Net Multithreading" book by
Alan Dennis?
-ken