|
I do not understand why there is an UnobservedTaskException in that code at all...
A method in a WCF service is defined as
[OperationContract]
[FaultContract(typeof(RemoteException))]
Task SetInfraredFocus(string _clientName, double _focus);
A WPF application calls out to it via:
public void SetFocus(double _focus)
{
try
{
m_RemoteManualPsControl.SetInfraredFocus(UtilsEnvironment.TerminalName, _focus).Wait();
}
catch (Exception ex)
{
Logger.LogException(Name, ex);
}
}
Note the .Wait() and the catch . That in turn calls the WCF client class
public Task SetInfraredFocus(string _clientName, double _focus)
{
Task task = new Task(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus)));
task.Start();
return task;
}
True, I ought to add a CallAsync function to our WCF client base class, but that's quite convoluted code there...
The server (a singleton service, multi-threaded) has a simple implementation for the sake of demonstration:
public async Task SetInfraredFocus(string _clientName, double _focus)
{
try
{
await Task.Delay(1);
throw new Exception("Oh f***!");
}
catch (Exception ex)
{
Logger.LogException(Name, ex);
RemoteException.ThrowFaultExceptionFromException(ex);
}
}
And then I get that UnobservedTaskException... Its detail clearly shows where it comes from: it is the RemoteException created from the "Oh f***!" exception of the server. But why does the "catch" in the function on the top not catch the exception?
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
Bernhard Hiller wrote:
Task task = new Task(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus))); That line looks suspicious to me.
The RemoteChannelProvider doesn't seem to be a built-in class. What's the signature of the Call method?
What I suspect is happening is this:
SetInfraredFocus returns a Task ;Call may or may not discard that task;- Even if it doesn't discard the task, the
new Task constructor definitely discards it - none of the overloads accept a Func<Task> ; - The task returned from the client therefore doesn't observe the result of the task returned from the server. It could even complete before the server call has finished.
If the RemoteChannelProvider.Call method returns the Task , then you should be able to fix this by replacing the client code with:
public Task SetInfraredFocus(string _clientName, double _focus)
{
return Task.Run(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus)));
} Task.Run has overloads which accept a Func<Task> . The task returned from these will not complete until the inner task has completed, and it will propagate any exceptions correctly.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
That overload does not do the trick either...
The "RemoteChannelProvider" is not a built-in class. The signature is:
public delegate void CallProxyDelegate<in T>(T _channel);
...
void Call(CallProxyDelegate<T> _codeBlock, [CallerMemberName] string _functionName = ""); Some implementation details:
m_ConfigurationChannelFactory = new ConfigurationDuplexChannelFactory<T>(m_CallbackObject, ConfigurationName, null, config);
...
m_CommunicationChannel = (ICommunicationObject)m_ConfigurationChannelFactory.CreateChannel();
...
_codeBlock((T)m_CommunicationChannel); I do not know how that handles a Task.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
OK, then it's definitely throwing the Task away.
How does the RemoteChannelProvider class cope with server methods which return a value?
If it doesn't, you might still be able to hack around it:
public Task SetInfraredFocus(string _clientName, double _focus)
{
return Task.Run(delegate
{
Task result = null;
RemoteChannelProvider.Call(_channel => result = _channel.SetInfraredFocus(_clientName, _focus));
return result;
});
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Perfect! That hack really works.
(But I still will need some time to find out how it works...)
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|