Hi,
This week i was debugging some crashes in an app that are related to networking (and in particular when the WiFi is disabled _System.Net.WebException: Error: ConnectFailure (Network is unreachable) ---> System.Net.Sockets.SocketException: Network is unreachable_ ). The culprit was an unhanded exception from within the async function of a ReactiveCommand.
var LoadSomeData = ReactiveCommand.CreateAsyncTask(async _ =>
{
var client = Locator.Current.GetService<ISomeRefitClient>();
return await client.GetSomeData();
});
LoadSomeData.ThrownExceptions.Subscribe(this.Log().Error);
LoadSomeData
.ObserveOn(RxApp.MainThreadScheduler)
.Select(result =>
{
...
}
...
LoadSomeData.ExecuteAsync();
If I am correct, the app should not crash since I am subscribed to the ThrownExceptions observable. But when I write another exception handler inside the async function, everything keeps running fine.
var LoadSomeData = ReactiveCommand.CreateAsyncTask(async _ =>
{
var client = Locator.Current.GetService<ISomeRefitClient>();
try{
return await client.GetSomeData();
}
catch (Exception e)
{
this.Log().Error(e);
return null;
}
});
LoadSomeData.ThrownExceptions.Subscribe(this.Log().Error);
LoadSomeData
.Where(result => result != null)
.ObserveOn(RxApp.MainThreadScheduler)
.Select(result =>
{
...
}
...
LoadSomeData.ExecuteAsync();
Did I do something wrong?
What does GetSomeData return? Any chance it's an IEnumerable that gets lazily executed in the subscription?
client is a refit client. (https://github.com/paulcbetts/refit)
Its signature looks like:
public interface ISomeRefitClient
{
[Get("/some/entrypoint")]
Task<List<SomeDataObject>> GetSomeData();
[Get("/some/other/entrypoint")]
IObservable<IEnumerable<SomeDataObject>> GetSomeOtherData();
}
Both methods (one with task, and one with observable) have this odd behaviour.
@jorisvergeer are you able to provide a stand-alone repro, preferably as a unit test? It certainly seems like invalid behavior to me, and I'd be interested in checking it against the new ReactiveCommand implementation in v7.
Hi,
I created an unit test that shows this issue
https://gist.github.com/jorisvergeer/0056f696f5025fedc7f6
But while writing it I came across this issue and pull request
and quoting @paulcbetts:
The expected behavior is that both:
- The exception ends up as an OnNext to ThrownExceptions
- command.ExecuteAsync should throw the Exception
I was under the impression that ExecuteAsync should not throw the exception when ThrownSubscriptions is Subscribed.
Ah, that makes sense. And the behavior is the same in RxUI 7. Closing this then, but please reopen if you don't think it's resolved.
Found a way to handle these exceptions :-)
For every Execute you need to add a Catch to return a value.
I implemented it like this:
The command property:
public ReactiveCommand<Unit, MyDataObject> LoadSomeData { get; }
The command initialization with ThrownExceptions:
LoadSomeData = ReactiveCommand.CreateFromTask<Unit, MyDataObject>(_ => OnLoadDataAsync());
LoadSomeData.ThrownExceptions.Subscribe(ex => ex.HandleException(...));
The Execute with a Catch statement:
await LoadSomeData.Execute().Catch(Observable.Return(new MyDataObject());
Most helpful comment
Found a way to handle these exceptions :-)
For every Execute you need to add a Catch to return a value.
I implemented it like this:
The command property:
The command initialization with ThrownExceptions:
The Execute with a Catch statement: