Reputation: 934
Over the last year I've learned a lot about WCF, but since I don't use it every day I still know enough to be dangerous. My example is too complicate to show something that will illustrate my full issue and I'll gladly show the pieces of what I do have that you would find helpful. I have a duplex service and built a class called HostedTransactionServiceProcess that encapsulates the service calls so that any client-level class using this doesn't have to understand the intricacies of working with a WCF Service. The service that it is encapsulating its calls to can also communicate back via callback events. The problem tends to be the coordination between service operations and receiving callback events. Whenever a callback event is called by the service, the class-level property/field values for HostedTransactionServiceProcess is null. I think this makes sense as creating the channel/proxy from Service-to-Client is left to the Service and doesn't allow for as much of the control we have when creating a channel/proxy communicating from Client-to-Service. So if it instantiates its callback proxy, then everything defaults and its as though those values were never modified.
First of all, is this correct? Secondly, how do I work around it?
I was able to work around a need to utilize an EventWaitHandle by creating a named one that can work inter-process, but I still need other properties/field data in the class to be seen between operation calls and callback event calls.
Again, I can give more info as needed, just let me know!
Edit: I tried to simplify things into an un-workable class that should at least illustrate my issue. Maybe this will help?
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true)]
public class HostedTransactionServiceProcess : ServiceProcess<IHostedTransactionService, HostedTransactionServiceInvoker, ConfigurationDuplexChannelFactory<IHostedTransactionService>>, IHostedTransactionServiceProcess, IHostedTransactionCallbackService
{
#region Properties
private ICADSession _cadSession;
public ICADSession CADSession
{
get { return _cadSession; }
set { _cadSession = value; }
}
#endregion
#region Operations
public void Commit(ICADSession cadSession, IEnumerable<IDTOEntity> dtoEntityCollection, IDTODocument dtoDocument, IDTOOperationLock operationLock)
{
lock (_serviceInvokerLock)
{
//Since the callback session will be instantiated by the WCF Service, any fields/properties in this class will be instantiated to null.
//This is because the Service is instantiating its own instance, creating its own proxy, based on the applied callback interface contract
//To work around this so that a call to the CAD System can wait until the CAD System responds back through the WCF Service, a named, inter-process
//EventWaitHandle will be used
using (EventWaitHandle waitHandle = ServiceWaitHandleHelper.StartNew(false, EventResetMode.AutoReset, cadSession, "Commit"))
{
//Set a local value... the issue is that this will end up null when the callback event is called!!!!!
//This seems to be because this instance making the Commit() call is different from the callback instance created to make the OnCommitted() call!!!
this.CADSession = cadSession;
//Make the proxy operation call
this.ServiceInvoker.Execute(serviceProxy => serviceProxy.Commit(cadSession, dtoEntityCollection, dtoDocument, operationLock));
//The lock will not be released for the next Commit() operation call until the entire commit process is completed or the operation times out.
waitHandle.WaitOne(TimeSpan.FromMilliseconds(MAX_OPERATION_TIMEOUT));
}
}
}
//The WCF Service Callback will call this
public void OnCommitted(ICADSession cadSession, IEnumerable<IDTOEntity> entityCollection, IDTODocument dtoDocument, IDTOOperationLock operationLock)
{
//First allow the Commit() operation to continue
EventWaitHandle waitHandle = ServiceWaitHandleHelper.GetExisting(cadSession, "Commit");
if (waitHandle != null && this.CADSession == cadSession) //!!!!!! Here is the issue!!! Even though this.CADSession was set to a value, the callback instance says it is null!!!
waitHandle.Set();
else
return;
}
#endregion
}
Upvotes: 0
Views: 589
Reputation: 934
I guess I've answered my own question. I basically have the service and two clients. The callback event seemed to be getting called, but the field values were null. When debugging I verified that it was subscribing the callback, so it ws driving me nuts. Then I discovered that the callback for one client was getting called, but not the other and it turns out though it captured the callback channel, it was making the callback before the previous method was finished while on the same thread... deadlock... So I started my connection and registration to the event on a separate thread than the operation call that initiates this process and now it seems to work.
Upvotes: 1