Why no timeout for loading online layers?

799
3
04-27-2020 09:11 AM
JoeHershman
MVP Regular Contributor

We use online basemaps for a mobile application.  It is possible, however, that a user may not have connection at some locations.  What happens in this situation is that the Layer:LoadAsync() for the ArcGISVectorTiledLayer simply hangs up.   It never times out and shows a failure to load.

var layerUri = new Uri("https://basemaps.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer");

var tiledLayer = new ArcGISVectorTiledLayer(layerUri);

//hanges up at this line of code.  LoadStatus goes into Loading but never changes
await tiledLayer.LoadAsync();

Instead I am having to add code to determine if it times out.   I used an HttpClient to see if I can hit the endpoint.

try
{
	//will timeout if unable to connect
	using (HttpClient client = new HttpClient(){Timeout = TimeSpan.FromSeconds(1)})
	{
		await client.GetStringAsync(layerUri);

		await tiledLayer.LoadAsync();
		map.Basemap.BaseLayers.Add(tiledLayer);

	};
}
catch (Exception e)
{
	Log.Error(e, e.Message);
	await DialogService.DisplayAlertAsync("Not Connected", "No connection exists so basemap will not be loaded", "Ok");
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

It seems to me the API should provide a way to know that a layer timed out trying to load.  Am I just missing something?  

Thanks

-Joe

Thanks,
-Joe
0 Kudos
3 Replies
dotMorten_esri
Esri Notable Contributor

We rely on the default http connection timeout (which typically is 90s), so you should see a load error by that time.

0 Kudos
JoeHershman
MVP Regular Contributor

Looks like 100 seconds.

I would make a request that future release includes a Timeout in the API.  Based on my recent user testing, users are not going to wait 100 seconds before assuming the application has just frozen.  Even with a slow connection it should not take a more than a few seconds to load.

Thanks

-Joe

Thanks,
-Joe
0 Kudos
dotMorten_esri
Esri Notable Contributor

Ah right. Close enough. Yes it's 100: https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/Http...

Reducing the timeout would be quite dangerous. Just because you generally get a fast response, doesn't mean others will, or that there can't be network hiccups now and then. Reducing it too much would mean you quite often wouldn't get a layer failing to load even though there's nothing wrong with the service. Also if you're the first to hit a service in the morning, the server might need to start up an app pool etc, and that can take longer than usual.

the application has just frozen

The application shouldn't be frozen but continue to work and respond. One thing you can do is to set the SpatialReference and InitialViewpoint on your Map instance explicitly before loading it - that'll enable the MapView to start rendering immediately and render whichever layers have loaded at that point. If you don't, the MapView needs to load the first layer to figure those things out, and it'll be a while before the map can start rendering, so if the first layer is slow to load, that would affect the entire view.

I'd also recommend that you use the loadstatus events to report layer status. Like a spinning circle next to each layer while they are loading, to show data is currently being fetched to start up the layer.

If you really want to cancel, you're also free to call layer.CancelLoad() after a set interval if you want to stop the loading.
Here's one way that could be done:

CancellationTokenSource tcs = null;
layer.LoadStatusChanged += (s, e) =>
{
    if(e.Status == LoadStatus.Loading)
    {
        tcs = new CancellationTokenSource();
        tcs.CancelAfter(TimeSpan.FromSeconds(5));
        tcs.Token.Register(layer.CancelLoad);
     }
     else
     {
         tcs?.Dispose();
         tcs = null;
     }
};‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos