|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Contents
IntroductionConsuming remote objects in the distributed .NET applications is fully transparent. This great feature of the .NET technology allows an easy deployment and mapping the logical business model to its physical environment. Behind all this "hidden work" is the remoting paradigm. When the client makes the remoting call, the remoting infrastructure packs all information into the message Subscribing to the remote probes, we can obtain a knowledge base of the business workflows, which can be used for their post-processing tasks such as monitoring, analyzing, modeling, simulation, tuning, error catch tracer (like an aircraft black box) etc. This article describes how to design and implement this custom sink called as remoting probe. Also I will give you a lite tool - Remoting Analyzer Studio to see how to subscribe and use the remoting probe notifications and business workflows between the remote objects and their consumers. For instance, you can catch the consumer call - Let's look in-depth of the remoting probe. I am assuming that you have a knowledge of the .NET remoting infrastructure. Probe internalsConcept and designThe concept of the loosely coupled message notifications is based on using the COM+ Event Publisher/Subscriber design pattern, where the event call is fired in the proper place of the message sink. The following picture shows that:
There are two places to publish the messages in the probe. As the picture shows, the first one is a "call" checkpoint to publish the The solution is to divide the published info into the following knowledge bases:
Based on the above definitions, the event meta class has been designed as shown in the following snippet: #region interfaces
[Guid("43603CAC-1D53-4cb0-A3A3-147B2B27A6EF")]
public interface IRemotingProbe
{
void WriteLogMessage(
DateTime timestamp, //timestamp of the sample
string strSource, //sourcer
string strMsgType, //type
string strMsgId, //identifier
object objMsgBody); //message body
}
#endregion
#region classes
[Guid("768DFCE9-279E-4818-8964-FA6D368BAC78")]
[EventClass]
[Transaction(TransactionOption.NotSupported)]
[ObjectPooling(Enabled=true, MinPoolSize=25, MaxPoolSize=100)]
[EventTrackingEnabled]
public class RemotingEventClass : ServicedComponent, IRemotingProbe
{
public void WriteLogMessage(
DateTime timestamp, //timestamp of the sample
string strSource, //sourcer
string strMsgType, //type
string strMsgId, //identifier
object objMsgBody //message body
)
{
throw new Exception("This class can be called
only by the COM+ Event System");
}
}
#endregion
where:
The remoting probe fires the event call in the following situations:
The probe's checkpoints are controllable via the config file - statically or programmatically using the remoting The probe is listening for the following call [Serializable]
public class ProbeLogicalCallContext : ILogicalThreadAffinative
{
string m_strKey; //probe key
string m_strCtrl; //control
string m_strStatus; //status
public string Key
{
get {return m_strKey; }
set { m_strKey = value; }
}
public string Ctrl
{
get {return m_strCtrl; }
set { m_strCtrl = value; }
}
public string Status
{
get {return m_strStatus; }
set { m_strStatus = value; }
}
}
The Using the above design, the subscriber or any remoting consumer can control the probe behavior such as turn the probe on/off or only its particular checkpoint. The default setup of the probe is off (disabled). Position probeThe probe is a custom message sink driven by the <configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown mode="SingleCall" type="TestRemoteObject.EchoObject,
TestRemoteObject, Version=1.0.977.40765,
Culture=neutral, PublicKeyToken=b2195ac3e95b2650"
objectUri="endpointEcho" />
</service>
<channels>
<channel ref="tcp" port="1234" >
<serverProviders>
<formatter ref="binary" />
<provider ref="probe" name="ProbeS1234"
call="true" return="true" error="true"
binary="true" endpoint="endpointEcho"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Configuring probeThe remoting probe uses the following standard and custom properties:
PublisherThe publisher is located in the probe. It's a light function to invoke the event call in the fire & forget manner using the delegate design pattern like shown in the following code snippet: public void Write(string strSource, string strMsgType,
string strMsgId, object msg)
{
try
{
//publishing in manner of the fire & forget
delegatePublisher delegator = new delegatePublisher(Publisher);
delegator.BeginInvoke(DateTime.Now, strSource, strMsgType, strMsgId,
msg, null, null);
}
catch(Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
public void Publisher(DateTime objTimeStamp, string strSource,
string strMsgType, string strMsgId, object msg)
{
try
{
//publishing
using(RemotingEventClass pec = new RemotingEventClass())
{
pec.WriteLogMessage(objTimeStamp,
strSource, strMsgType, strMsgId, msg);
}
}
catch(Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
The probe logic packs required arguments in the specified format and then calls the publisher wrapper function to perform fire & forget event call. After that, the call is back to the normal message flow which is the forwarding message to the next sink. Note that the publisher doesn't care whether the subscriber included its business logic purpose too, that's the LCE system notification feature. In other words, the publisher's target is the COM+ Event System and this service makes the bridge to the subscriber based on its subscription registered in the event store. CheckpointsThe probe checkpoints are places where remoting message is strobed and send to the publisher. There are actually two checkpoints: call and return. The return checkpoint can publish any return message including the error message. Internally this checkpoint has another checkpoint to decide that only the error message will be published. The following code snippet shows the checkpoints in the server probe, when public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
IMessage requestMsg,
ITransportHeaders requestHeaders,
Stream requestStream,
out IMessage responseMsg,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
ServerProcessing servproc = ServerProcessing.Complete;
responseMsg = null;
responseHeaders = null;
responseStream = null;
//Are we in the business?
if(m_Next != null)
{
//workaround
requestMsg.Properties["__ObjUri"] =
requestMsg.Properties["__Uri"];
//create a checkpoint id if doesn't exit in the IMessage
if(requestMsg.Properties.Contains(ProbeTicket.checkpoint) == false)
{
requestMsg.Properties[ProbeTicket.id] = Guid.NewGuid();
requestMsg.Properties[ProbeTicket.checkpoint] = (int)0;
}
//pre-processing probe (call)
m_Probe.Write(m_Provider.m_ProbeState, requestMsg, null);
//mark the checkpoint
if(requestMsg.Properties[ProbeTicket.checkpoint] is int)
{
int cp = (int)requestMsg.Properties[ProbeTicket.checkpoint];
requestMsg.Properties[ProbeTicket.checkpoint] = ++cp;
}
//check the Probe Call Context for this probe and change its state
string result = UpdateProbeState(requestMsg);
if(result == null)
{
//processing message in the current channel
servproc = m_Next.ProcessMessage(sinkStack,
requestMsg, requestHeaders,
requestStream, out responseMsg,
out responseHeaders, out responseStream);
}
else
{
//this messages has been dedicated for probe only
RemotingException rex = new
RemotingException(ProbeCallContext.exceptionMsg);
rex.Source = result;
responseMsg = new ReturnMessage(rex,
(IMethodCallMessage)requestMsg);
responseHeaders = requestHeaders;
}
//check our properties
if(responseMsg != null)
{
if(responseMsg.Properties.Contains(ProbeTicket.checkpoint)
== false)
{
responseMsg.Properties[ProbeTicket.id]=
requestMsg.Properties[ProbeTicket.id];
responseMsg.Properties[ProbeTicket.checkpoint] =
requestMsg.Properties[ProbeTicket.checkpoint];
}
//mark the checkpoint
if(responseMsg.Properties[ProbeTicket.checkpoint] is int)
{
int cp = (int)responseMsg.Properties[ProbeTicket.checkpoint];
responseMsg.Properties[ProbeTicket.checkpoint] = --cp;
}
//post-processing probe (return or error)
m_Probe.Write(m_Provider.m_ProbeState, responseMsg, requestMsg);
}
}
else
{
//We have no active sink
Trace.WriteLine
(string.Format("{0}:RouterServerSink ProcessMessage null",
m_Provider.ProviderName));
}
return servproc;
}
Client-Activated ObjectThe remoting infrastructure is based on the //check if we running the client-activated object
if(mcm.Args != null && mcm.ArgCount == 1 && mcm.Args[0]
is IConstructionCallMessage)
{
//activator argument
msg = mcm.Args[0] as IConstructionCallMessage;
//workaround
msg.Properties["__ObjUri"] = mcm.Properties["__ObjUri"];
msg.Properties[ProbeTicket.id] = mcm.Properties[ProbeTicket.id];
msg.Properties[ProbeTicket.checkpoint] =
mcm.Properties[ProbeTicket.checkpoint];
}
The same situation is done for a message back. The server activator returns its result in the return value of the Note that there is a small workaround when the server activator throws exception. This message can't be serialized for its publishing using the binary formatter, so the SOAP formatter is automatically used to publish this error message. InstallationThe remoting probe solution consists of the following projects:
Installation steps:
Also, you can use the InstallIntoTheGAC.bat file included in this solution to complete steps 1 and 4. After the above steps, the remoting probe is ready to use in the remoting config files. Plugging in the probe into the provider can be done with the default setup like shown: <provider ref="probe" name="ProbeS1234" />
In this config case, the probe will monitor the host process firing the This is a minimum publishing notification from the remoting probes. They can be ran without any impact for the remoting performance. UsageThe remoting probe usage is dependent on its subscriber. The probe without using any subscriber is a passive sink, publishing the messages going to nowhere. The usage of the remoting probe has two phases:
SubscribersThere can be many number of different subscribers designed and implemented for the remoting probes. From the simplest one, like the host process monitoring, to more complicated business control loops based on the strobed business knowledge base. Some solutions can be lead to more sophisticated model than the main application. Basically, the subscribers are divided into the following two groups:
How powerful is the remoting details published by the probe, is shown in my included solution called Remoting Analyzer Studio. Here are its details: Remoting Analyzer StudioThe Remoting Analyzer Studio is the GUI Subscriber to the remoting probe(s) to explore the remoting messages between the remote objects and their consumers. It has been designed and implemented (using "as it is" methodology) to demonstrate power of the published knowledge base by remoting probe. It can be used for developing, testing and tracing the remoting issues during the product lifecycle. Note that the Analyzer is a full isolated - loosely coupled design pattern from your remoting objects and consumers.
The concept of the Remoting Analyzer Studio is based on exploring the incoming event calls into the The following screenshot shows the Probes tab, where each accessible probe has its own entry. It's the read-only
The next tab is for scanning the remoting probes. You can create your entry of the remoting URI address and click for its scanning. This
The Simulation tab has capability to drop the
The following code snippet shows the implementation of invoking the private void menuItemSimulatorRun_Click(object sender, System.EventArgs e)
{
TreeNode tnSel = treeViewSimulator.SelectedNode;
IMethodReturnMessage responseMsg = null;
try
{
if(tnSel.Tag is IMethodCallMessage)
{
IMethodCallMessage requestMsg = tnSel.Tag as IMethodCallMessage;
string strDummy = null;
IMessageSink iMsgSink = null;
string strObjUrl = "?";
foreach(TreeNode tnUri in tnSel.Nodes)
{
if(tnUri.Tag is string)
{
strObjUrl = tnUri.Tag as string;
}
}
//create a checkpoint id in the IMessage
requestMsg.Properties[ProbeTicket.id] = Guid.NewGuid();
requestMsg.Properties[ProbeTicket.checkpoint] = (int)1000;
//find the properly outgoing channel registered in this process
foreach(IChannel channel in ChannelServices.RegisteredChannels)
{
if(channel is IChannelSender)
{
iMsgSink = (channel as IChannelSender).CreateMessageSink
(strObjUrl, null, out strDummy);
if(iMsgSink != null)
break;
}
}
if(iMsgSink == null)
{
statusBarPanelResponse.Text = "There is no properly
channel to invoke the remote method";
}
else
{
//Pass the IMessage to the following channel
//based on the method's attribute
//The SyncProcessMessage can not be done on
//the OneWay attributed method (deadlock process)
if(RemotingServices.IsOneWay(requestMsg.MethodBase) == true)
{
iMsgSink.AsyncProcessMessage(requestMsg, null);
}
else
{
responseMsg = (IMethodReturnMessage)
iMsgSink.SyncProcessMessage(requestMsg);
}
if(responseMsg != null && responseMsg.Exception == null)
{
statusBarPanelResponse.Text = "Done";
}
else
if(responseMsg != null && responseMsg.Exception != null)
{
throw responseMsg.Exception;
}
}
}
}
catch(Exception ex)
{
statusBarPanelResponse.Text = "Error: " + ex.Message;
}
}
Analyzing first sampleI built the test solution to demonstrate capability of the Remoting Analyzer Studio. You can find it in a separate folder \Test\bin:
Note that the test requires to install the assembly TestRemoteObject into the GAC in prior. The probe and Analyzer has been implemented using .NET SP2 and tested on the Windows 2000 Advanced Server. It should work without any problem also on XP machines. The following picture shows the test schema of the components and programs:
The Analyzer can be launched to the test environment any time. Subscribing the Analyzer to the event system will start its scanner routine to find the probes on the specified remoting addresses (see Scanning tab). Also, the probe pinging will notify existence of the probe in the remoting channels (see Probes tab). Echo buttonThe client invokes the remote method F5 Key (Tracer)Selecting the sample on the Analyzer and pressing the key F5, all samples related for this remoting session will be expanded and ready to walk through them:
As you can see the above screenshot, the Analyzer received the remoting and business knowledge base for this call. For instance: Drag & Drop MethodCallThe F9 Key (Mark)Pressing the F9 key, the sample is marked and the mouse tool tip shows some important info about the pointed sample:
To exit this mode, just press the Ctrl + F9 or click on the MarkExit menu. This feature also calculates a delta time from the marked sample message, so it is easy to see a timing between the ON/OFF switcherThe Remoting Analyzer can be subscribed/unsubscribed to/from the Event System using this button. It's a good practice to receive the required remoting samples and then turn off the Analyzer to work off-line. (analyzing the samples). What next ...Now, configure your remoting project with the probe and make the same process described above. Note that the Analyzer is type driven, so your assembly has to be accessible locally or through the GAC. The other choice is to use the SOAP formatter in the probe. Another note - is about the enhancing feature of the Analyzer. I am planning to add a capability of triggering, filtering and circulating samples, full simulation of the ConclusionUsing the LCE remoting probes in the Distributed Application Framework to strobe the business workflow gives you an additional post-processing knowledge base which can be used for many things. This is an incrementally development pyramid based on developing the suitable subscribers. In this article, I presented one of them - Remoting Analyzer Studio, which is a small tool to examine the contents of the remoting messages. | ||||||||||||||||||||