I have a NET.TCP WCF server and client application and would like开发者_StackOverflow社区 to provide stats in the server side component for the bandwidth, TTL etc for each client connected.
To get TTL I could implement a new method to bounce between the client and server and measure the time difference, and to measure the traffic I could simply count the bytes in my messages but I wondered if there are any built in stats in the ServiceHost that would provide what I need.
Counting the bytes I have in my objects might also be misleading since the binding will apply binary encoding for the data anyway.
Combining this blog post and trawling the online docs I have implemented a Message Inspector, custom behaviour and applied it to my service.
Since my service is Duplex, to capture all the traffic, I need to add message inspectors to both the server side end point and the callback client runtime. This point seems to be missing from many of the online examples.
Custom Inspector
public class EndPointMessageInspector : IDispatchMessageInspector, IClientMessageInspector
{
static long _bytesWritten = 0;
static long _bytesRead = 0;
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
_bytesRead += buffer.CreateMessage().ToString().Length;
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
if (reply != null)
{
MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
reply = buffer.CreateMessage();
_bytesWritten += buffer.CreateMessage().ToString().Length;
}
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
// No replies expected from Duplex call backs
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
if (request != null)
{
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
_bytesWritten += buffer.CreateMessage().ToString().Length;
}
return null;
}
}
Custom Service Behaviour
[AttributeUsage(AttributeTargets.Class)]
public class GatherThroughputBehaviour : Attribute, IServiceBehavior, IEndpointBehavior
{
#region IServiceBehavior Members
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
{
ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
EndPointMessageInspector inspector = new EndPointMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
#endregion
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new EndPointMessageInspector());
endpointDispatcher.DispatchRuntime.CallbackClientRuntime.MessageInspectors.Add(new EndPointMessageInspector());
}
public void Validate(ServiceEndpoint endpoint)
{
return;
}
#endregion
}
Apply the Behaviour to my Service
[GatherThroughputBehaviour]
public class TunnelServer : IMyContract
{
...
}
精彩评论