I have a WCF
service that I need to combine in an existing application.
Service's interface:
[ServiceContract(CallbackContract = typeof(IClientCallback))]
public interface IExecutionService
{
[OperationContract]
ExecutionStatus Execute(string path);
[OperationContract]
ExecutionStatus Abort();
}
And callback:
[ServiceContract]
public interface IClientCallback
{
[OperationContract(IsOneWay = false)]
string GetUserInput(string message, string information, bool isPause);
[OperationContract(IsOneWay = true)]
void OutputAvailable(OutputAvailableEventArgs args);
[OperationContract(IsOneWay = true)]
void ResultAvailable(ResultAvailableEventArgs args);
[OperationContract(IsOneWay = true)]
void ExecutionStarted(ExecutionStartedEventArgs args);
[OperationContract(IsOneWay = true)]
void ExecutionEnded(ExecutionEndedEventArgs args);
}
The service is performing some work and reports when there's something to report.
Args classes are marked as DataContract
with namespaces. They contain .Net native types (int
, string
, DateTime
).
I created a testing application and everything works great (time from asking the service to execute until ExecutionStarted
is called ~1 second).
When creating a client in my existing application, there are 2 issues:
- Slowness - about 1 minute from
Execute()
toExecutionStarted()
. - The last call -
ExecutionEnded
- just doesn't happen. What does happen? The lastOutputAvailable
call happens instead. During debug, I see the service calling theExecutionEnded
method, but what is invoked on the client side isOutputAvailable
(which should have been called, only earlier and not instead of the finish method).
I'm using the same test in my test client and my real application.
Some code that might help, I hope:
Service:
class declaration:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class ExecutionService : IExecutionService
public ExecutionStatus Execute(string path)
{
lock (locker)
{
var tempClient = OperationContext.Current.GetCallbackChannel<IClientCallback>();
if (client == null)
client = tempClient;
else if (client != null && client != tempClient)
{
throw new FaultException(new FaultReason("Execution Service is busy processing a request."));
}
else if (tempClient == null)
throw new FaultException(new FaultReason("No client found, execution is aborted."));
Log.InfoFormat("client: "+ DateTime.Now);
Log.InfoFormat(client == null ? "null" : client.ToString());
}
((IContextChannel)client).OperationTimeout = new TimeSpan(0,3,0);
Task<ExecutionStatus> executionTask = Task.Factory.StartNew(() => HandleExecution(path));
return executionTask.Result;
}
(Making sure I have only one client at a time. I need the reentrant mode so I can use callbacks during the service's methods.)
Client: Creating the connection to the service:
var myBinding = new WSDualHttpBinding();
var myEndpoint = new EndpointAddress("http://localhost:3050/ExecutionService");
var myChannelFactory = new DuplexChannelFactory<IExecutionService>(this, myBinding, myEndpoint);
service = myChannelFactory.CreateChannel();
var executionStatus = service.Execute(@"C:\Users\nosh\Desktop\launcher.py");
I'll publish more code if necessary.
Another issue is that in my real app, I get:
A first chance exception of type 'System.TimeoutException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.TimeoutException' occurred in mscorlib.dll
just before the 'execute' method returns, and later I get:
A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
This doesn't happen in my test application.
Any idea what's wrong here?
Edit
I think I know what's wrong, just not how to fix it. The problem is that my real app is WPF
and it has some issues working with WCF
. I tried switching to NetTcpBinding
but it didn't help. I'd appreciate other suggestions.
Edit 2
For the WPF
issue you should add the following in your callback implementation:
[CallbackBehavior(UseSynchronizationContext = false)]
(Thanks to Ian Ringrose for providing the answer here.)
Now I'm still facing a non responsive WPF
client but the connection to the service doesn't hang. I'd appreciate more suggestions.
Edit 3
Now it's only a single method that isn't being called on the client. The connection is alive (I have other calls after it), the method isn't doing anything special.