There are actually a few things that I won't go into detail
on in this article, for brevity's sake, that are part and parcel of the .NET
Service Manager. The first is the actual Windows service code. I didn't go into
this because I don't think I can add much of value to what's already out
there-there are plenty of articles that cover how to build Windows services in
.NET. Suffice it to say that the "real" Windows service involves creating
an instance of the ServiceBroker and making use of a FileSystemWatcher to watch
the application directory for new DLLs. When a DLL is added or changed in the
directory, it will call ServiceBroker.StartService for the DLL. When a DLL is
deleted, it will call ServiceBroker.StopService for that file. And when you use
the Windows Services applet to start and stop or issue the same command from
the console, it just cycles through all DLLs in the directory and calls the
StartService and StopService methods on its ServiceBroker instance.
There was only one caveat I found in monitoring the
directory as described. I found that I sometimes got multiple events raised
from the FileSystemWatcher for the same file being dropped into the directory.
To avoid processing the same file change twice, I added a check to wait two
seconds between changes. Unfortunately, this led to a bug when you drop in
multiple DLLs at once, so I modified that check to also see if the file changed
was different from the previous. This means that I only process file changes
that are either two seconds apart or are not the same file.
The other bit of the app that I'll just cover briefly is the
Config class. This is the class, if you remember from Part 1, that enables us to have separate
configuration files for each managed service. In short, this class, when
instantiated, sets up a FileSystemWatcher to look for a file with the managed
service assembly name plus ".config" just like .NET does for .EXE
applications. It does this by calling
Assembly.GetCallingAssembly().GetName(false).CodeBase, replacing the URL-like
syntax with standard Windows syntax and appending ".config" on the
end. It uses a HybridDictionary to store the appSettings from that file,
delaying loading it until you request a setting using the provided string
indexer.
Overall, I hope you find the .NET Service Manager to be a
useful service to you in your development; I know I and others already have.
There is one caveat with the application as a whole that I don't think can be
reasonably solved, which is if you are deploying a managed service that has
dependent DLLs, you need to deploy the referenced DLLs first to ensure that
when StartService is called on your managed service that you don't get any
errors because it can't find referenced assemblies. I suppose I could create
some sort of timed queue that waited a certain amount of time before beginning
to process assemblies, but that wouldn't be wholly dependable. I think it's
best to just make a note of it in your deployment procedures.
Related Resources
.NET
Remoting Overview - MSDN Library
Programming
with AppDomains - MSDN Library
AppDomains
and Dynamic Loading - Eric Gunnerson
Reflection
Overview - MSDN Library
FileSystemWatcher
Class - MSDN Library
Suzanne Cook's .NET CLR Loader Notes