My last posting demonstrating what I thought was a pretty cool technique for intercepting WCF operation calls so you can report them on a console; that is when you host on a console application for development. Looking back at that technique, however useful to me, there was something that bugged me. The behaviors I showed you how to write had the reporting-to-the-console part built right into them, and I wasn’t exactly satisfied that. I still maintain the usefulness of reporting every operation call to my host console but wouldn’t it be a more powerful technique to report every operation call and allow the actual host application to do the reporting? That way, whenever you finally deploy you services, you can track operation calls with any hosting application and do whatever you want with them. In the case of a dev-console host, I can still report the calls to the console, but in the case of an IIS or NT-Service deployment I can chose to log them somewhere, even a custom event log.
So building on the same technique and code from the previous post, I changed the parameter inspector to raise an event instead of accessing the console. Since the operation behavior is what instantiated and installed the parameter inspector, its job is to bubble the event up through another event. In turn, the service behavior instantiated and installed the operation behavior on every operation so it also takes the information from the captured event and raises its own event. Finally, the console host (in my case), which instantiates and installs the service behavior, captures its event and reports to the console. The end-result in my case is the same, but the ability to simply capture an event from my hosting application gives me the ability to do whatever I want with the information. Remember, each class raises an event to its parent which in turn raises its own event all the way up to the actual host.
If you haven’t read my last blog posting, I strongly suggest you go back and read it because I will not be re-explaining the details of the inspector and behavior classes, nor their installation details in this posting.

The first I thing I did was create an event argument class called OperationInformationEventArgs which contains all the information about an operation that I want to send up the chain. This class is used by all three of the other classes, the parameter inspector, the operation behavior, and the service behavior.
Here is the code for the event argument class:
public class OperationInformationEventArgs : EventArgs
{
public OperationInformationEventArgs(string serviceName, string operationName, DateTime timeStamp)
{
ServiceName = serviceName;
OperationName = operationName;
TimeStamp = timeStamp;
}
public string ServiceName { get; set; }
public string OperationName { get; set; }
public DateTime TimeStamp { get; set; }
}
Next, I renamed the two behavior classes and the parameter inspector so their names were more general and did not imply console-reporting. I called them OperationReportInspector, OperationReportOperationBehavior, and OperationReportServiceBehavior. Also notice that I removed the word Attribute from their class name because I decided to no longer make them attribute capable. Since I’m going to need to do some event wiring, using them in an attribute context would not have worked.
The parameter inspector class now takes the information that it was previously reporting directly to the console, and instead sticks it in the event argument and raises an event.
Here is the code for the new parameter inspector class:
public class OperationReportInspector : IParameterInspector
{
public OperationReportInspector(string serviceName)
{
_ServiceName = serviceName;
}
public event EventHandler<OperationInformationEventArgs> ServiceOperationCalled;
protected virtual void OnServiceOperationCalled(OperationInformationEventArgs e)
{
if (ServiceOperationCalled != null)
ServiceOperationCalled(this, e);
}
string _ServiceName = string.Empty;
void IParameterInspector.AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
object IParameterInspector.BeforeCall(string operationName, object[] inputs)
{
//Console.WriteLine(string.Format("{0} - '{1}.{2}' operation called.", DateTime.Now.ToLongTimeString(), _ServiceName, operationName));
OnServiceOperationCalled(new OperationInformationEventArgs(_ServiceName, operationName, DateTime.Now));
return null;
}
}
For comparison purposes, I left the old line that wrote out to the console in there and commented it out so you can see the difference.
Now I modified the operation behavior that would install the parameter inspector so just after it instantiates, it wires into the ServiceOperationCalled event. This class also raises an event with the same information (with the same event arguments class in fact) in the method wired to the parameter inspector’s event.
Here is the code for the new operation behavior class:
public class OperationReportOperationBehavior : IOperationBehavior
{
public event EventHandler<OperationInformationEventArgs> ServiceOperationCalled;
protected virtual void OnServiceOperationCalled(OperationInformationEventArgs e)
{
if (ServiceOperationCalled != null)
ServiceOperationCalled(this, e);
}
void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
string serviceName = dispatchOperation.Parent.Type.Name;
OperationReportInspector inspector = new OperationReportInspector(serviceName);
inspector.ServiceOperationCalled += inspector_ServiceOperationCalled;
dispatchOperation.ParameterInspectors.Add(inspector);
}
void IOperationBehavior.Validate(OperationDescription operationDescription)
{
}
void inspector_ServiceOperationCalled(object sender, OperationInformationEventArgs e)
{
OnServiceOperationCalled(e);
}
}
Finally, I modified the service behavior class so just after it instantiates the operation behavior, it wires its event to a method where its own event is raised; again with the same event argument information.
Here is the code for the new service behavior class:
public class OperationReportServiceBehavior : IServiceBehavior
{
public event EventHandler<OperationInformationEventArgs> ServiceOperationCalled;
protected virtual void OnServiceOperationCalled(OperationInformationEventArgs e)
{
if (ServiceOperationCalled != null)
ServiceOperationCalled(this, e);
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
OperationReportOperationBehavior behavior = new OperationReportOperationBehavior();
behavior.ServiceOperationCalled += behavior_ServiceOperationCalled;
operation.Behaviors.Add(behavior);
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
void behavior_ServiceOperationCalled(object sender, OperationInformationEventArgs e)
{
OnServiceOperationCalled(e);
}
}
So now, all that is left to do is to change the actual console host application so when it instantiates and installs the service behavior, it wires into its ServiceOperationCalled event, then displays the information to the console using the wired method.
Here’s the new code for the console host:
OperationReportServiceBehavior behavior = serviceHost.Host.Description.Behaviors.Find<OperationReportServiceBehavior>();
if (behavior == null)
{
behavior = new OperationReportServiceBehavior();
behavior.ServiceOperationCalled += behavior_ServiceOperationCalled;
serviceHost.Host.Description.Behaviors.Add(behavior);
}
void behavior_ServiceOperationCalled(object sender, OperationInformationEventArgs e)
{
Console.WriteLine(string.Format("{0} - '{1}.{2}' operation called.",
e.TimeStamp.ToLongTimeString(), e.ServiceName, e.OperationName));
}
As I said, the end-result is the same as in my previous posting but now the hosting application can chose to do what it wants with the contents of the event argument. In my humble opinion, what was a cool technique is now a cooler technique.
Until next time…