I'm looking for a way to keep track of the total time spent on the database, and merge it over one Service Operation call or maybe even an entire session. Since I'm currently using the default PerCall InstanceContextMode, the constructor of the Service class is called every time a service method is called, so I was thinking something like hooking into some pipeline method that is called before and after each service method, calling a non-empty constructor. And then injecting an object to pass further into the hierarchy:
[ServiceContract]
public interface IJobsService { ... }
public partial class JobsService : IJobsService
{
public PerformanceContext PerformanceContext { get; private set; }
JobsService() { ... }
JobsService(PerformanceContext context) : this()
{
RequestContext = context;
}
}
public class PerformanceContext
{
private object syncObj = new object();
private long? userID;
public long? UserID { ... }
public string Source { get; set; }
private long totalTicksUsed = 0;
public long TotalTicksUsed
{
get { return totalTicksUsed; }
private set { totalTicksUsed = value; }
}
public void AddTicksUsed(long ticks, long? userID)
{
Interlocked.Add(ref totalTicksUsed, ticks);
UserID = userID;
}
}
Then I would have the reference of it outside the scope of the service contract, and be able to log it there.
As it is now, the "simplest" way for me to implement this behavior is to call a logging function in the very end of every single service method, but I don't find it very pretty, if there's a better way.
I've tried following Explicitly calling a service constructor when hosting a WCF web service on IIS, Hooking into wcf pipeline and some of the Carlos Figueira MSDN blog: WCF Extensibility, without much success. I'm also having trouble finding much documentation on it general. In other words, I'm stuck.
I am a bit torn between the
IOperationInvokerand theIInstanceProvider.The
IOperationInvokerhas turned out to be fairly complicated for what I need, since I need to extend both synchronous and asynchronous calls. But it's advantage is that it is specifically made to perform actions before and after each method call. Although I'm still not entirely sure how to pass on an object to any service method, which I can use to track the use, lower in the hierarchy. And Carlos Figueira's blog on WCF Extensibility unfortunately doesn't touch on this in his example (he shows how to cache calls).The
IInstanceProviderturned out to be more simple for me to implement, and also makes it possible to perform actions before and after each operation - as long as theInstanceContextModeisPerCall. If I were to change it toPerSession, I would suddenly perform the actions once per session instead. But in my case, that's acceptable, since the primary objective is to merge the data as much as possible:One of my Service classes with the custom
ServiceBehaviorAttributeand inheriting an abstract type that dictates we have a constructor that takes aPerformanceContext:IInstanceProviderwhich allows calling a specific constructor and injecting anIExtensioninto the pipeline, which we can obtain after the Service instance is released:The
IServiceBehaviorandAttributethat will be added to all services that needs aPerformanceContextinjected.The
IExtensionthat we can attach to theInstanceContextthrough the instance provider pipeline:The abstract service type that should allow this injection:
A factory for services that inherit
PerformanceMonitoredService: