Click here to Skip to main content
Click here to Skip to main content

Watchdog Management

, 1 Jul 2003
Rate this:
Please Sign up or sign in to vote.
The Watchdog Management gives your architecture an event driven mechanism to control your business processing within the specified time. Using the Remoting Watchdogs allow to distribute an exception or acknowledge result asynchronously in the remoting manner.

Contents

Introduction
Features
Configuration
MMC Snap-in
Implementation
Installation
Test
Conclusion

Introduction

Every model of the Distributed Application needs to handle invoking a method between the object and its consumer in the properly way using either the synch or asynch design pattern. The state transition in this model is the time driven depending on many factors such as connectivity, resources, etc. Typically example can be a model using the database resources, where a database connection is under the time "watcher" to allow effectively shares its expensive resource. Another example is the model using the web services, which needs to handle an unreliable connectivity. Coming to the point, the model needs an asynchronously design pattern to allow watching the state transition in the business processing.

This article describes a design and implementation of the "Watchdog" timer incorporated into the remoting infrastructure using the custom channel design pattern.

The usage of the Watchdog is very generic such as free-run timer to ping a remoting object, retrying a remote call, delaying a remote call, counter of the remote call, watchdog timer and etc. From the consumer side using the Watchdog features in the remoting is full transparently to the remote object and suitable for the distributed and deployment patterns.

To make easy managing the Watchdogs, I built the MMC snap-in to create and manage their host process and configurations.

Let's starting with Watchdog application features. I assume you are familiarly using the .Net Remoting.

Features

The watchdog behavior:

  • Free-run (periodically invoking an action - pinging)
  • One-shot (one action only)
  • Retry (retry a number of times when an action is unsuccessful)
  • Down counter (make a specified number of actions)
  • Re-triggering (keep it alive from the action - watchdog feature)

Managing the watchdog state:

  • Auto configuration from the config file
  • Auto Start during the remoting configuration
  • Runtime control such as start, stop, restart, delete, etc. using the remoting design pattern -IWatchdogControl.
  • Remoting Watchdog to control delivering an IMessage to the endpoint using the specified watchdog behavior such as free-run, one-shot, retry, etc.
  • Interval adjustment where exception throw during the action
  • Interface contract for notification endpoints -IWatchdog
  • Keeping a runtime application state
  • Exception notification
  • Acknowledge notification

Watchdog object

The Watchdog object is a stateful object derived from the System.Timers.Timer class to hold a state for the specified interval. Based on its configuration the state can be distributed to the endpoints such as notify, acknowledge or exception using the remoting design pattern and IWatchdog respectively IMessage interface.

The Watchdogs incorporated into the Watchdog custom channel are using all advantages of the remoting infrastructure included publishing itself where the channel name is used as its endpoint. This design pattern allows accessing a Watchdog object using the remoting paradigm on the run-time.

The Watchdog state can be configured administratively from the config file or programmatically using the IWatchdogControl interface.

IWatchdogControl

The IWatchdogControl interface is an abstract definition of the WatchdogChannel control contract. The WatchdogManagement.Sender class inherits this interface to manage the Watchdogs in the channel using the remoting design pattern.

public interface IWatchdogControl 
{
   void Start(string id);
   void Start(string id, object state);
   void Restart(string id);
   void Restart(string id, object state);
   void Stop(string id);
   bool Exists(string id);
   bool IsRun(string id);
   void Add(WatchdogSettings wds);
   void Remove(string id);
   int RemoveAll();
   int RemoveAll(string name);
   int RemoveAll(string name, string notifyurl);
   WatchdogSettings GetSettings(string id);
   object GetSettingsAll();
   object GetSettingsAllSorted(); 
}

The watchdog is identified by its unique Id (string type) within the channel. Its Id can be assigned either explicitly or random by using the Guid class.

IWatchdog

The IWatchdog interface is an abstract definition of the Watchdog notification contract. The remote object needs to inherit this interface and implement its method. There are three methods in the interface declaration:

public interface IWatchdog 
{
   object WatchdogNotify(WatchdogSettings wds, DateTime signalTime);
   bool WatchdogException(WatchdogSettings wds, Exception ex);
   void WatchdogAck(WatchdogSettings wds, DateTime signalTime);
}

Every method is passing the source of the notification - Watchdog state described by the class WatchdogSettings. The notified object can exanimate its settings for the specific properties such as Id, Name, State, etc. to make a properly notification action.

WatchdogSettings

The WatchdogSettings class is a simple class with smart properties and helpers to get/set the Watchdog state. The following snippet shows their public signatures:

[Serializable]
public class WatchdogSettings
{
   //access to the properties
   public string Name                         // watchdog name 
   public string Id                           // watchdog unique Id
   public string Description                  // description
   public string Message                      // notify message
   public string NotifyObjectUrl              // notify endpoint
   public string AcknowledgeObjectUrl         // acknowledge endpoint
   public string ExceptionObjectUrl           // exception endpoint
   public string ChannelUrl                   // watchdog channel endpoint
   public string LastErrMsg                   // last error message
   public bool Destroy                        // flag to allow destroy it
   public bool Retry                          // flag of the retry mechanism
   public int Downcounter                     // action down counter
   public bool TimerAutoReset                 // timer AutoReset flag
   public bool TimerEnable                    // timer Enable flag
   public int TimerInterval                   // timer interval
   public int TimerErrorInterval              // timer interval during the 
                                              // exception
   public object Tag                          // application tag
   public object State                        // application state
   //helpers
   public IMethodReturnMessage MethodReturnMessage() 
   public IMethodCallMessage MethodCallMessage() 
}

There are two special properties in the WatchdogSettings:

  • Tag specifies either the NameValueCollection object of the additional application specific properties using the name/value pair design or the byte array object represents the IMethodCallMessage image
  • State is the run-time application object to hold either the notification state or the byte array object represents the IMethodReturnMessage image

To de-serialize the IMessage from the byte array object, the WatchdogSettings class has methods such as MethodCallMessage rsp. MethodReturnMessage. Using these helpers in the notification endpoints to retrieve a remoting call rsp. response details makes a properly action such as recovering, re-routing, tracing logs, etc.

Configuration

Using the Watchdog requires to make its setup in the host process config file such as a config section and channel. See the following example:

<configuration>
   <configSections>
      <section name="watchdogManagement" 
               type="RKiss.WatchdogManagement.WatchdogSectionHandler, 
               WatchdogChannel, Version=1.0.0.0, Culture=neutral, 
               PublicKeyToken=2f2c272b6c14cde0" />
   </configSections>
   <watchdogManagement mode="on">
      <watchdog mode="on" 
         name="AutoPing" 
         interval="60" 
         notifyurl="tcp://localhost:3333/endpoint" 
         description="Watchdog to ping a remote object" />
   </watchdogManagement>
   <appSettings>
      <add key="RKiss.Watchdog" value="tcp://localhost:3344/wd" />
   </appSettings>
   <system.runtime.remoting>
      <application>
         <service>
         </service>
         <channels> 
            <channel ref="wd" name="wd" />
            <channel ref="tcp" port="3344" />
         </channels>
      </application>
      <channelSinkProviders>
      </channelSinkProviders>
      <channels>
         <channel id="wd" type="RKiss.WatchdogManagement.Sender, 
                  WatchdogChannel, Version=1.0.0.0,Culture=neutral, 
                  PublicKeyToken=2f2c272b6c14cde0" />
      </channels>
   </system.runtime.remoting>
</configuration>

The above configuration example will create one Watchdog (name = AutoPing) to notify a remote object specified by its url address (notifyurl="tcp://localhost:3333/endpoint"). The "ping" interval is every 60 seconds from the time when the watchdog custom channel has been constructed. This type of the Watchdog can be used to handle a business state persisted in the database, clean-up tables, pinging a host process lifetime, etc.

To configure another watchdog is very simple, just adding a <watchdog . /> element into the watchdogManagement config section, for example:

<watchdogManagement mode="on">
   <watchdog mode="on" 
      name="AutoPing" 
      interval="60" 
      notifyurl="tcp://localhost:3333/endpoint" 
      description="Watchdog to ping a remote object" />
   <watchdog mode="on" 
      name="MyWatchdog" 
      id="911"
      interval="20" 
      autoreset="false"
      message="The time to finish a process has been expired."
      notifyurl="tcp://localhost:3333/endpoint" 
      exceptionurl="tcp://localhost:3333/endpoint" 
      description="General watchdog timer" />
</watchdogManagement>

The second Watchdog (MyWatchdog) has explicitly assigned its unique Id (911), only one-shot notification (autoreset="false") and error exception goes to the endpoint (exceptionurl="tcp://localhost:3333/endpoint"). To prevent the Watchdog to elapse its time (interval="20") and forcing the specified notification action, it has to be re-triggered any time during this interval using the IWatchdogControl method, like it's shown in the following code snippet:

string objWatchdogUrl = "tcp://localhost:3344/wd";
IWatchdogControl wdc = (IWatchdogControl)Activator.GetObject(
                                    typeof(IWatchdogControl), objWatchdogUrl);
wdc.Restart("911", "Checkpoint 1");

The Watchdog endpoint url address can be obtained explicitly from the config file (appSettings) or dynamically from the watchdog state (channelurl property).

Usage of the above watchdog is for instance; to control lifetime of the opened session, response timeout, cleanup specific resources, timeout of the business processing, etc.

The following table shows the predefined Watchdog properties in the config file:

NAME DEFAULT VALUE NOTE
mode "on" Enable/disable configuration settings
id "" Unique ID (for instance: Guid)
name "" Name of the Watchdog
message "" Notification message
description "" Description
lasterrmsg "" Last error message during the post-processing notification action.
destroy "true" Flag to allow destroying the Watchdog
retry "false" Flag indicated a retry mechanism
downcounter "-1" or

"2147483647"

Down counter of the notification calls. Decrementing is locked for the default value.
notifyurl "" url address of the notify remote object
acknowledgeurl "" url address of the acknowledge remote object
exceptionurl "" url address of the exception remote object
channelurl "" url address of the watchdog channel
autoreset "true" Watchdog Timer AutoReset flag. The default value will force a free-run notification (pinging)
enable "true" Watchdog Timer Enable flag
interval "0" Watchdog Timer interval. The value is in seconds. The default value or value zero represents 1ms.
errorinterval "0" Watchdog Timer interval when a notification failed. The value is in seconds.

The above watchdog properties can be extended using the name/value pair pattern for application specific purposes, for instance: connection string, rules, etc.

The Watchdog state can be updated dynamically based on the notification (action) result in the synchronously manner. For instance: the Ping Watchdog holds a state of the previously ping needed to calculate some business/system statistics.

The following picture shows processing the Watchdog notifications.

During the remoting configuration process the WatchdogChannel constructor performs a process of creating Watchdogs based on the host config file. This process scans the watchdogManagement config section for the Watchdog configured for the notify action (property notifyurl). This configuration is used to setup the Watchdog state.

That's the all for the first step - watchdog activation on the start-up. The second step is post-processing its state where notifications are called to the specified endpoints such as notify, exception or acknowledge remote objects. The non-null result from the notified remote object (NRO) is stored in the watchdog state for the application purposes.

Notes:
  • Using the Watchdog state needs to be considered carefully in the case of the scalability (web/app farms).
  • The Watchdog without initializing a notifyurl property (default value is empty string) is considered as a Watchdog template and it will not be registered during the start-up channel. It can be used for Remoting Watchdog purpose.

Remoting Watchdog

The previously Watchdogs (based on the notifyurl property) required to use an interface contract to fire the notify endpoint when their time has been elapsed. That's fine for new or in-house development. What about already existed remote objects? Do we need to build a separate proxy to handle it? The answer is not necessary; here is the solution - the Remoting Watchdog design pattern.

The concept of the Remoting Watchdog is based on storing a remoting IMessage call into the Watchdog state and returned a null ReturnMessage back to the caller (the same behavior like asynch or OneWay call).

Once we have a serialized image of the IMessage in the byte array, the Watchdog can hold it for any time and then forward it to the requested channel and endpoint. Based on the Watchdog properties, the IMessage can be duplicated, retried, counted, etc. like other previously watchdog type. The Remoting Watchdog also can handle an exception notification or post-process call such as acknowledge notification (including its returned values) in the distributed manner.

The following url address example shows how the Watchdog can take a control over the tcp channel using the chaining channels design pattern:

string objectUrl = "wd://retry; tcp://localhost:3333/endpointA";

As you can see the remoting call between the endpointA and its consumer is divided into two processes indicated by a delimiter ';'

  • synch process between the consumer (client) and Watchdog
  • asynch process between the Watchdog and endpointA using the retry mechanism and tcp channel

Based on the watchdog config template "retry" declared in the host process config file, the Remoting Watchdog can setup properly its state. When watchdog is requested to be controled, the watchdog Id can be assigned explicitly in the url address like the following syntax shows:

string objectUrl = "wd://retry:12345; tcp://localhost:3333/endpointA";

The following flowchart shows flowing the IMessage between the remote object and its consumer using the Watchdog channel:

As you can see the IMessage passed by SyncProcessMessage method is serialized into the byte array, stored into the run-time Watchdog state and returned back to the caller as a Null ReturnMessage. Note that the each remoting call will create own unique Watchdog object. Using the IWatchdogControl interface it can be used to update its state such as start, stop, etc. When the Watchdog time elapsed, the post-process will be started based on its state. The binary stored IMessage is de-serialized and passed to the remoting infrastructure by the Dispatcher.

The response IMessage from the remote object is serialized into the byte array and stored in the Watchdog state. Based on the Watchdog state the post-processor will generate either Exception or Acknowledge notification using the configured url addresses. After that the watchdog can be destroyed or run continuously depends from its behavior state.

In our example - retry Watchdog, the IMessage post-process will be repeated until either the successful remote call is done or its Downcounter state has reach zero. Note that only one (finally) Exception notification is sent it to the exception object.

Now you know that the Watchdog Management can registered two kinds of the watchdog type:

  • Notify Watchdog - this is a traditional timer to notify a specific remote object based on the IWatchdog interface contract. This type needs to be considered in the class design pattern.
  • Remoting Watchdog - this is a run-time configurable watchdog incorporated into the remoting infrastructure to notify endpoint using the IMessage interface. This type is full transparently to the class design pattern. It depends only from the configuration setup such as a watchdog template and logical url address for remoting object.

Usage requirements

Using the Watchdog Management in your solution requires the following assemblies and config sections:
  1. WatchdogChannel assembly installed into the GAC (client machine)
  2. WatchdogManagement assembly installed into the GAC (client and server machines)
  3. Modify or create your host process config file based on the template WatchdogHostProcessTemplate.exe.config file.

Also it's possible to declare common element such as configSections and channel into the machine.config file and use their references, which it will simplify your host process config files.

To make easy installation of the Watchdog Management, use the msi file included in my solution package. This is very convenience installation process and besides that you can have very powerful administration tool (snap-in) to manage your watchdogs using the MMC.

MMC Snap-in

Features:

  • Scanning machine for host process related to the Watchdog Management
  • Creating a host process for Watchdog Management included its default config file
  • Drag&Drop already created host process
  • Managing a host process such as start, stop, restart or delete
  • Monitoring the host process for event logs
  • Configuring Watchdog Custom Channel
  • Configuring Watchdogs
  • Monitoring run-time watchdogs
  • Managing run-time watchdogs (only "Delete" in this version)
  • Automatic installation using a .msi file

Using the MMC WatchdogManagement snap-in is straightforward:

  1. Create the host process (if we don't have one)
  2. Configure the watchdogManagement section such as watchdog properties, etc.
  3. Run the host process

The watchdog host process node is switching between the configuration and runtime Watchdog access. In other words, the watchdog properties can be changed only when its host process is not running.

Here are few examples to understand usage of the watchdogs in the Distributed patterns.

Example 1.

Let assume that your application framework need to scan the business state persisted in the database periodically each 200 seconds. The solution will need it:

  1. Enterprise component derived from IWatchdog activated as Library
  2. Implementation of the WatchdogNotify method to handle a business issue
  3. Implementation of the WatchdogException method to handle an exception notification cases
  4. Watchdog to ping this component
  5. Host process to host both objects

From development point of the view, the above solution requires to implement only steps 1-3 using the standard remoting technique. The rest steps are issue of the deployment and they can be accomplished very easy using the MMC WatchdogManagement snap-in.

The following screen snippet shows the AutoPing Watchdog state in runtime:

As you can see, the AutoPing watchdog (hosted by Watchdog_1 process) has been configured with the application specific properties such as ConnectionString and Condition to customize a generic stateless business object - endpointScanner via the WatchdogSettings argument (see IWatchdog interface).

That's been a simple example.

Note: The watchdog of the business state is a perfect solution for the scalable web or application tiers, where each server from the farm can generated the watchdog ping without any state collision. From business state point of the view, it doesn't care who is a "pinger".

Example 2.

Let's make a little bit more requirements for processing business logic such as initializing all business activity during the start-up process under the timeout control. The task can be again accomplished administratively using two watchdogs:

  • Boot with the one-shot feature to trigger a root object - enterprise component to perform all business initialization when host process has been activated.
  • Watchdog to watch the processing activities of the root object.

The both watchdogs are configured from the config file and activated during the remoting configuration process. The Boot watchdog has a small delay interval to notify a root object. This endpoint has a responsibility to re-trigger (restart) the Watchdog for each step of the business processing. Forgetting this duty, the Watchdog will be elapsed and its exception endpoint activated. Based on the Watchdog state is easy to figure out which step failed and perform a recovering process. It's recommend to register the Watchdog in the different host process for reliability issue.

The following sequence diagram shows a situation when business logic during the step2 failed (for instance: database deadlock) which it forces the Watchdog Exception Notification.

 

The WatchdogChannel, Boot and Watchdog components represent a design pattern to control the business processing. They can be configured administratively way using the config file only.

The following snap-in shows the Runtime Watchdogs in the Watchdog_Test host process and details of the Watchdog (911) state:


 

Example 3.

This example shows how the standard remoting call can be turned on to deliver a remoting response asynchronously and distributable using the Watchdog mechanism. The Remoting Watchdog allows building an event driven architecture with a loosely coupled deployment pattern - known as the pushing architecture model. The client makes a remoting call in the Fire&Forget manner and Watchdog will distribute its response resp. exception to the configurable endpoints.

Note: The .Net remoting supports an asynchronously consuming remote objects using the IAsyncResult design pattern, but this solution is not distributed.

To change a standard remoting call to the Watchdog driven call is very simple just adding the watchdog channel into the url address:

string objectUrl = "wd://notify; tcp://localhost:3333/endpointRemoteObject";

where "notify" is the name of the watchdog template from the config file:

<watchdog mode="on" 
   name="Notify" 
   autoreset="false"
   exceptionurl="tcp://localhost:3333/endpointException" 
   acknowledgeurl="tcp://localhost:3333/endpointAcknowledge" 
   description="Watchdog to distribute a response from the remote object" />

The following sequence diagram shows a message flow between the consumer and endpoints. The first channel is WatchdogChannel to initiate a Watchdog Timer with the properly state included also the IMessage image. Note that the client call is returned immediately with a null ReturnMessage. The post-process starts after 1ms (interval = 0, default value) to forward the IMessage to the next chained channel (tcp) of the remoting infrastructure (client channel sink). Based on the result message and state, the Watchdog will distribute a response resp. exception to the endpoints. Note that changing the interval value in the watchdog config file, the remoting can be delayed for the requested time.

To retrieve a response value, the WatchdogSettings has implemented a method to de-serialize a byte array into the IMethodReturnMessage. Once we have it this reference, all information can be obtained it such as name method, return value, output arguments, etc.

The following code snippet shows that:

public void WatchdogAck(WatchdogSettings wds, DateTime signalTime)
{
   IMethodCallMessage msgReq = wds.MethodCallMessage();
   IMethodReturnMessage msgRsp = wds.MethodReturnMessage();

   if(msgRsp != null)
   {
      object retVal = msgRsp.ReturnValue;
      object outArg = msgRsp.Args[1];

      //todo:
   } 
}

The other case, when a remoting call threw exception is simply too. The following code snippet shows how to obtain the name of the method where an exception occured.

public bool WatchdogException(WatchdogSettings wds, Exception ex)
{  
   string strMethodName = "";
   IMethodCallMessage mcm = wds.MethodCallMessage();
   
   if(mcm != null) 
   {
      strMethodName = mcm.MethodName;
      
      //todo: 
   }
   
   //destroy watchdog
   return true;
}

Using the IMethodCallMessage reference helps to make a properly recovering logic. This is a very powerful feature where based on the remoting call represented by the IMethodCallMessage reference can be used for the following solutions:

  • re-route a remoting call to another endpoint (with capability to use also Watchdog)
  • update input arguments and retry it again
  • create or modify the CallContext object and retry it again
  • make details logs

Implementation

The implementation of the Watchdog Management solution has been divided into the following projects:

  1. WatchdogChannel - this is a remoting custom sender channel to handle initiating and managing Watchdog objects - Timers.
  2. WatchdogManagement - this is a common assembly for interface abstract definitions and Watchdog settings.
  3. WatchdogManagementConsole - this is MMC snap-in to manage and configure the watchdogs in the host process. The design and implementation using the same style as been described in my article [1].

The WatchdogChannel has a standard boilerplate implementation of the remoting Sender class extended for the remoting access. The class inherits the MarshaByRefObject class and interfaces IChannelSender, IWatchdogControl. This class is initiated by the remoting infrastructure from the config file and its lifetime is depends from the host process.

Here is its constructor:

#region constructor
public Sender(IDictionary properties, 
                                IClientChannelSinkProvider clientSinkProvider) 
{ 
   //administratively setup using the config values
   if(properties.Contains("name")) 
      m_ChannelName = properties["name"].ToString().ToLower();;
   if(properties.Contains("priority")) 
      m_ChannelPriority = Convert.ToInt32(properties["priority"]);
   if(properties.Contains("maxtimers")) 
      m_NumOfMaxWatchdogTimers = Convert.ToInt32(properties["maxtimers"]);

   //validation 
   if(m_NumOfMaxWatchdogTimers <= 0) 
      m_NumOfMaxWatchdogTimers = WatchdogManagement.NumOfMaxWatchdogTimers;

   //collection of the timers
   m_WatchdogTimers = Hashtable.Synchronized(new Hashtable());

   //check config section
   object objConfigSection = ConfigurationSettings.GetConfig(
                   WatchdogManagement.ConfigSection);
   if(objConfigSection != null)
   {
      //setup "notified watchdogs" from the config file
      WatchdogManagementSettings wdms = objConfigSection as 
                                                   WatchdogManagementSettings;
      foreach(WatchdogSettings wds in wdms.Watchdogs) 
      {
         if(wds.NotifyObjectUrl != "") 
         {
            WatchdogTimer wdt = new WatchdogTimer(wds); 
            wdt.Elapsed += new ElapsedEventHandler(OnWatchdogTimerEvent);
            WatchdogTimers.Add(wds.Id, wdt);
            wdt.Enabled = wds.TimerEnable;
         }
      }
   }

   //publish the Watchdog endpoint using the channel name.
   m_thisObjRef = RemotingServices.Marshal(this, m_ChannelName);

   //echo
   Trace.WriteLine(strLogMsg);
}
#endregion

As you can see the channel name is used to publish the WatchdogChannel endpoint. To keep it this endpoint forever, the following override has been implemented:

#region InitializeLifetimeService
public override object InitializeLifetimeService()
{
   //infinite lifetime of the remoting access
   return null;
}
#endregion 

The WatchdogChannel hash table collects all WatchdogTimer objects to wait for change their state. As I mentioned earlier, the Watchdog object is the time driven. When its time elapsed, the event handler OnWatchdogTimerEvent method is called to perform an action based on the Watchdog state.

Basically there are two kinds of action such as standard remoting notification configured explicitly using the url endpoint address and implicitly address from the IMessage stream.

The following code snippet shows the IMessage pre-processing (serialization) and storing into the Watchdog state when the client invoke the remote method:

#region IMessageSink
public virtual IMessage SyncProcessMessage(IMessage msgReq)
{ 
   IMessage msgRsp = null;

   try 
   {
      //check watchdogId in the collection
      if(m_WDS.Id != "" && m_Sender.WatchdogTimers.Contains(m_WDS.Id))
         throw new Exception(string.Format("The watchdog already exist, 
                             name={0}, id={1}", 
                             m_WDS.Name, m_WDS.Id));

      //uri workaround 
      msgReq.Properties[WatchdogManagement.OBJECTURI] = m_ObjectUri;

      // serialize IMessage
      BinaryFormatter bf = new BinaryFormatter();
      MemoryStream reqstream = new MemoryStream();
      bf.Serialize(reqstream, msgReq);
      reqstream.Position = 0;

      //write stream to the buffer
      byte[] buffer = new byte[reqstream.Length];
      reqstream.Read(buffer, 0, buffer.Length);
      reqstream.Close();

      //store the stream into the WatchdogTimer
      WatchdogTimer wdt = new WatchdogTimer(m_WDS);
      wdt.Tag = buffer;
      wdt.Id = m_WDS.Id == "" ? Guid.NewGuid().ToString() : m_WDS.Id;
      wdt.NotifyObjectUrl = m_ObjectUri;
      wdt.Elapsed += new ElapsedEventHandler(m_Sender.OnWatchdogTimerEvent);
      m_Sender.WatchdogTimers.Add(wdt.Id, wdt);
      wdt.Enabled = m_WDS.TimerEnable;

      //this is a Fire&Forget call, so we have to simulate a return message
      object retVal = null;

      //generating a null return message
      IMethodCallMessage mcm = msgReq as IMethodCallMessage;
      MethodInfo mi = mcm.MethodBase as MethodInfo;
      if(mi.ReturnType != Type.GetType("System.Void"))
         retVal = mi.ReturnType.IsValueType ? Convert.ChangeType(0, 
                                                        mi.ReturnType) : null; 

      //return message
      msgRsp = (IMessage)new ReturnMessage(retVal, null, 0, null, mcm);

   }
   catch(Exception ex) 
   {
      msgRsp = new ReturnMessage(ex, (IMethodCallMessage)msgReq);
   }

   return msgRsp;
}
//.
#endregion

The IMessage post-processing (de-serialization) is implemented in the following code snippet:

#region Forward IMessage to the properly channel
private byte[] IMessageDispatcher(byte[] bufferMsgReq, bool bException) 
{
   byte[] bufferMsgRsp = null;

   #region deserialize IMessage
   BinaryFormatter bf = new BinaryFormatter();
   MemoryStream reqstream = new MemoryStream();
   reqstream.Write(bufferMsgReq, 0, bufferMsgReq.Length);
   reqstream.Position = 0;
   IMessage iMsgReq = (IMessage)bf.Deserialize(reqstream);
   reqstream.Close();

   //endpoint
   string strObjectUrl = 
           Convert.ToString(iMsgReq.Properties[WatchdogManagement.OBJECTURI]);

   //workaround
   iMsgReq.Properties["__Uri"] = strObjectUrl;

   //chain channel
   string strDummy = null;
   IMessageSink sink = null;
   #endregion

   #region find the properly channel
   foreach(IChannel ch in ChannelServices.RegisteredChannels)
   { 
      if(ch is IChannelSender)
      {
         IChannelSender iChannelSender = (IChannelSender)ch;
         sink = iChannelSender.CreateMessageSink(strObjectUrl, null, 
                                                               out strDummy);
         if(sink != null)
         {
            break; 
         }
      }
   }
   #endregion

   #region forward IMessage to the channel sink
   if(sink == null)
   {
      //throw exception
      string strError = string.Format("WatchdogChannel:" + 
                        "A supported channel could not be found for {0}", 
                        strObjectUrl);
      Trace.WriteLine(strError);
      throw new Exception(strError);
   }
   else 
   {
      //response message
      IMessage iMsgRsp = null;

      //processing IMethodCallMessage based on the oneway attribute
      IMethodCallMessage mcm = iMsgReq as IMethodCallMessage;

      #region message processing
      if(RemotingServices.IsOneWay(mcm.MethodBase) == true)
         iMsgRsp = (IMessage)sink.AsyncProcessMessage(iMsgReq, null);
      else
         iMsgRsp = sink.SyncProcessMessage(iMsgReq);
      #endregion

      #region serializing a response
      if(iMsgRsp != null && iMsgRsp is IMethodReturnMessage) 
      { 
         IMethodReturnMessage mrm = iMsgRsp as IMethodReturnMessage;
         if(bException && mrm.Exception != null)
            throw mrm.Exception;

         //serialize IMessage response
         MemoryStream rspstream = new MemoryStream();
         bf.Serialize(rspstream, iMsgRsp);
         rspstream.Position = 0;

         //write stream to the buffer
         bufferMsgRsp = new byte[rspstream.Length];
         rspstream.Read(bufferMsgRsp, 0, bufferMsgRsp.Length);
         rspstream.Close(); 
      }
      #endregion
   } 
   #endregion

   return bufferMsgRsp;
}
#endregion

Installation

The solution contains a msi file to make its installation easy. Based on the selection, the source and test sample can be installed too. Using the installed WatchdogManagement desktop folder you have an access to the MMC snap-in and Sample Test (client and server program)

The installation project is included in the source code, so if you want to modify or recompile the solution, don't forget to build a new msi file and uninstall old one.

The other way of the Watchdog Management installation is using a manual process. Please follow the steps described by Usage requirements.

Test

The WatchdogManagement solution can be tested by included Sample Test project. It's a simple remoting object hosted by console program and consumed by Windows Form:

The form has a UI to generate and manage Watchdogs in the client host process.

Testing instructions:

  1. Be sure that the msi file has been installed.
  2. Launch the ServerWD console program
  3. Launch the ClientWD program
  4. See the Watchdog notifications on the console generated by autostart Watchdogs configured in the ClientWD.exe.config file.
  5. Click GetAll to obtain all runtime watchdogs
  6. Click Stop to stop the Watchdog 123456789
  7. You can use other watchdog control features such as start, restart, etc.
  8. Click Ping to perform a remoting call and check its response on the console.
  9. Select another url addresses and repeat step 8.

Some tips:

  • Double click on the listBox item Id will copy its value to the id textBox
  • Double click on the listBox item Name will copy its value to the name textBox
  • inserting 'throw' into the msg textBox, the remoting object will throw an exception

Using the MMC snap-in in the test:

  1. Be sure that the msi file has been installed.
  2. Launch the ServerWD console program
  3. Launch the WatchdogManagement.msc
  4. Create new watchdog host process or drag&drop old one
  5. Enable watchdogManagement mode (mode = "on")
  6. Apply change
  7. Start the watchdog host process
  8. See the watchdogs responses on the console server program
  9. Stop the watchdog host process
  10. Make some changes in the watchdog configurations
  11. Follow steps 6, ...

Conclusion

In this article I show you a different usage of the remoting infrastructure. Using the Watchdogs in the distributed design pattern allow to loosely coupled your business model with application services. The MMC WatchdogManagement snap-in give you a tool to administrate its deployment easy using the config files. I hope you will enjoy it.

[1] http://www.codeproject.com/csharp/RemotingManagementConsole.asp

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Roman Kiss
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
Questionany updates? Pinmemberalhambra-eidos14-Jan-11 21:56 
QuestionLicense Pinmemberstormyseasailor14-Dec-09 6:55 
Generalnice PinmemberYuriy Levytskyy3-Apr-09 4:40 
General.NET remoting - Monitoring PinmemberJefy Dominic6-Jul-05 4:44 
GeneralMissing Config Files PinsussSteven Carleton13-Jun-04 11:42 
GeneralRe: Missing Config Files PinmemberRoman Kiss14-Jun-04 15:18 
GeneralAmazing! PinmemberNiko Paulanne20-Nov-03 20:00 
GeneralWow and more wow... Pinmemberrsyoung014-Oct-03 13:54 
GeneralWatchdog Management PinmemberSyed.Irfan11-Sep-03 0:02 
GeneralInstalling PinmemberPeter Tewkesbury30-Jun-03 23:17 
GeneralRe: Installing PinmemberRoman Kiss3-Jul-03 5:20 
GeneralRe: Installing PinsussSimon Murrell5-Oct-03 19:28 
GeneralGreat to have a person like you around PinmemberYelpe17-Jun-03 17:10 
General.NET 1.1 Version PinmemberRoman Kiss15-Jun-03 11:31 
GeneralFabulous job! Pinmemberpsusong7-Jun-03 18:01 
Generalvow vow vow Pinmemberfkocak2-Jun-03 20:31 
GeneralAs usually... PinmemberRich Rafaj2-Jun-03 6:41 
GeneralA remoting question PinmemberDavid Gallagher1-Jun-03 7:58 
GeneralRe: A remoting question PinmemberMichael Bruyninckx11-Jun-03 5:52 
GeneralRe: A remoting question PinmemberDavid Gallagher11-Jun-03 6:15 
GeneralReally great job ! PinmemberJuergen Posny30-May-03 19:29 
GeneralRe: Really great job ! PinmemberRoman Kiss31-May-03 19:58 
GeneralAsk of who is lost... PinmemberMikeboo30-May-03 2:51 
GeneralRe: Ask of who is lost... PinmemberRoman Kiss30-May-03 4:42 
Generalum... PinsubeditorMarc Clifton30-May-03 1:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140814.1 | Last Updated 2 Jul 2003
Article Copyright 2003 by Roman Kiss
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid