This is the first of a three-part blog post on how to monitor and control a .NET Windows Service from an ASP.NET page. The general approach I've taken involves using remoting to marshal a singleton object over a tcp channel. If you're not familiar with Singleton objects, remoting, serialization and marshalling, you may want to go figure out that stuff first, then come back here to the specifics. I'm not an expert on these in general, so I'm not going to even try to do them justice with explanations here. This approach does work well for me, I'm using it to monitor a service that checks for status changes on shipping containers. It looks like this:

Step 1: Add a reference to System.Runtime.Remoting to your Service project. You also want to use the following namespaces in your .cs code:
using
System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;
Step 2: Create a Serializable object that will be marshalled over the tcp channel. What I've done here create an object that contains the service information I want to monitor. This class keeps information about how long the service has been running, how often it executes its checks, and an array of items that have info about each status check. It looks like this, sorta (I've simplified the code for this example).
[Serializable]
public class WatchListStatus
{
public TimeSpan ExecutionInterval;
public WatchListStatusItem [ ] StatusItems;
public DateTime ServiceStarted;
}
[Serializable]
public class WatchListStatusItem
{
public int NumberEvents;
public DateTime CheckDateTime;
public TimeSpan ExecutionTime;
public WatchListCheckResult Result;
}
[Serializable]
public enum WatchListCheckResult
{
Successful,
FailedTimeOut,
FailedError
}
Step 3: Create a wrapper class that inherits from MarshalByRefObject. This will be the remotable object. I've been calling these wrapper classes [wrapped-classname]Remotable for consistency. You can control the time-to-live for your object, by overriding the InitializeLifetimeService(). To make your object live for the life of the service process, return null here.
public
class WatchListStatusRemotable : MarshalByRefObject
{
public WatchListStatus ServiceStatus;
// Sets the time to live for this object. When this expires, the object will have to
// be re-marshalled
public override Object InitializeLifetimeService()
{
return null;
}
}
Step 4: Add a private instance member object to your service class. This is where the singleton model stuff becomes important. You only want to have one instance of this object per service.
private WatchListStatusRemotable m_Status;
Step 5: On - Startup of the service, marshal the object like so:
// Register the TCP Channel on port 8001
ChannelServices.RegisterChannel(new TcpChannel(8001));
// Register the type
RemotingConfiguration.RegisterWellKnownServiceType (
typeof(WatchListStatusRemotable),
"WatchListStatus",
WellKnownObjectMode.Singleton);
// Now, Marshal it this will make it available to other processes via the TCP remoting channel
try
{
RemotingServices.Marshal(m_Status, "WatchListStatus");
System.Diagnostics.Trace.WriteLine("Watch List Status Marshalled");
}
catch (System.Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
System.Diagnostics.Trace.WriteLine(ex.InnerException);
}
That's it! You can modify the object as the service does it's thing and other processes that remote to this object will have access to this information. All you have to do is consume it with a call to Activator.GetObject from your ASP.NET code. In part two, I'll go into the details of how I did this in my app and how to control the service.
-Brendan
Music tip: Have I mentioned British Sea Power?
Posted
Wed, Nov 12 2003 12:30 PM
by
Brendan Tompkins