I have the following WCF contract:
[ServiceContract(Namespace = "http://abc/Services/AdminService")]
public interface IAdminService
{
[OperationContract]
string GetServiceVersion();
// More methods here
}
The GetServiceVersion
is a simple method returning some string. It is used as a ping to check whether the service is reachable.
Now I would like to call it asynchronously, thinking it would be more efficient than using .NET threads to call it in background.
So, I have come up with the following interface just for that purpose:
[ServiceContract(Namespace = "http://abc/Services/AdminService")]
public interface IMiniAdminService
{
[OperationContract(Action = "http://abc/Services/AdminService/IAdminService/GetServiceVersion", ReplyAction = "http://abc/Services/AdminService/IAdminService/GetServiceVersionResponse")]
Task<string> GetServiceVersionAsync();
}
This makes it possible to invoke the GetServiceVersion
API asynchronously:
var tmp = new ChannelFactory<IAdminService>("AdminServiceClientEndpoint");
var channelFactory = new ChannelFactory<IMiniAdminService>(tmp.Endpoint.Binding, tmp.Endpoint.Address);
var miniAdminService = channelFactory.CreateChannel();
return miniAdminService.GetServiceVersionAsync().ContinueWith(t =>
{
if (t.Exception != null)
{
// The Admin Service seems to be unavailable
}
else
{
// The Admin Service is available
}
});
The code works.
My question is this - does it utilize the IOCP to invoke the continuation?
In general, is there a way to know whether a continuation is invoked through IOCP or not (in the debugger, if needed) ?
P.S.
Here is the stack trace of my async WCF method continuation:
> *** My Code *** Line 195 C#
mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromResultTask<string>.InnerInvoke() + 0x111 bytes
mscorlib.dll!System.Threading.Tasks.Task.Execute() + 0x69 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) + 0x4f bytes
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x28d bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x47 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) + 0x3b5 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) + 0x104 bytes
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x2a bytes
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x249 bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x1e bytes
[Native to Managed Transition]
Now, this stack trace looks very similar to the one I get for a method called from Task.Factory.StartNew
, which is indeed Thread Pool based:
> *** My Code *** Line 35 C#
mscorlib.dll!System.Threading.Tasks.Task<int>.InnerInvoke() + 0x59 bytes
mscorlib.dll!System.Threading.Tasks.Task.Execute() + 0x60 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) + 0x37 bytes
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x1a2 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x33 bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) + 0x2ff bytes
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) + 0xd3 bytes
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x22 bytes
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x22e bytes
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x18 bytes
[Native to Managed Transition]