Hey Everyone
I'm in the process of writing an application that allows a user to have a base map displayed one of three ways.
1. The client identifies a local tpk they wish to use
2. The client identifies a URL for an ArcGISTileMapServiceLayer
3. If the two options above fail, we have a defaulted URL identified for loading a ArcGISTileMapServiceLayer.
I have proper handling in for dealing if a local TPKs can't be found; however I'm struggling with dealing with a bad URL being passed in. I'm coding for the notion that a client put in a type-o and provide them at worst with a default base map which we have identified.
Here is my first function for testing for a local tpk:
private bool LoadLocalTilePackage(string localTilePackage)
{
var agsTpkLayer = new ArcGISLocalTiledLayer(localTilePackage) { ID = localTilePackage };
var localTileTask = agsTpkLayer.InitializeAsync();
if (localTileTask.Exception != null)
{
foreach (var innerException in localTileTask.Exception.InnerExceptions)
{
FdmLogger.LogError("Trouble loading the local tile package: ", innerException.Message," ", localTilePackage, " Will attempt to load an online map");
}
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTpkLayer);
MdsOverviewMapView.Map.Layers.Add(agsTpkLayer);
return true;
}
}
Here is one version of the function I have tried so far in dealing with online tpk:
private bool LoadOnlineTilePackage(string onlineTilePackage)
{
var tiledUri = new Uri(onlineTilePackage);
var agsTiledLayer = new ArcGISTiledMapServiceLayer(tiledUri) { ID = onlineTilePackage };
var onlineTileTask = agsTiledLayer.InitializeAsync();
//the "Wait" below never comes back!!
if (!onlineTileTask.IsCompleted) onlineTileTask.Wait();
if (onlineTileTask.Exception != null)
{
foreach (var innerException in onlineTileTask.Exception.InnerExceptions)
{
FdmLogger.LogError("Trouble loading the defined online tile package: ", innerException.Message, " ",
onlineTilePackage, " Will attempt to load the default online map");
}
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTiledLayer);
MdsOverviewMapView.Map.Layers.Add(agsTiledLayer);
return true;
}
}
Here is a much more simplified version but the await never waits:
private bool LoadDefaultOnlineTilePackage()
{
var tiledUri = new Uri(_onlineDefaultTilePackage);
var agsTiledLayer = new ArcGISTiledMapServiceLayer(tiledUri) { ID = _onlineDefaultTilePackage };
await agsTiledLayer.InitializeAsync();
MdsMapView.Map.Layers.Add(agsTiledLayer);
MdsOverviewMapView.Map.Layers.Add(agsTiledLayer);
return true;
}
Solved! Go to Solution.
Thanks for the reply Antti
I ended up coming up with a solution last night that seemed to work. I will add my code example below so others can see what I've done. The real issues comes from connecting to an invlaid url and capturing it within a try catch resolved the issue.
private bool _alreadyLoadedMap;
private async void MdsMapView_OnLoaded(object sender, RoutedEventArgs e)
{
//this gets triggered every time you leave the map view
if (_alreadyLoadedMap) return;
if (!string.IsNullOrEmpty(_localArcGisTileLocation))
{
if(LoadLocalTilePackage(_localArcGisTileLocation))
{
_alreadyLoadedMap = true;
return;
}
}
Task<bool> loadBaseMapTask = null;
if (!string.IsNullOrEmpty(_onlineArcGisTileUrl))
{
loadBaseMapTask = LoadOnlineTilePackage(_onlineArcGisTileUrl);
if (!loadBaseMapTask.IsCompleted)
{
await loadBaseMapTask;
}
}
if ((loadBaseMapTask != null && !loadBaseMapTask.Result) || loadBaseMapTask == null)
{
LoadDefaultOnlineTilePackage();
}
_alreadyLoadedMap = true;
}
private bool LoadLocalTilePackage(string localTilePackage)
{
var agsTpkLayer = new ArcGISLocalTiledLayer(localTilePackage) { ID = localTilePackage };
var localTileTask = agsTpkLayer.InitializeAsync();
if (localTileTask.Exception != null)
{
foreach (var innerException in localTileTask.Exception.InnerExceptions)
{
FdmLogger.LogError("Trouble loading the local tile package: ", innerException.Message, " ", localTilePackage, " Will attempt to load an online map");
}
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTpkLayer);
MdsOverviewMapView.Map.Layers.Add(agsTpkLayer);
return true;
}
}
private async Task<bool> LoadOnlineTilePackage(string onlineTilePackage)
{
var tiledUri = new Uri(onlineTilePackage);
var agsTiledLayer = new ArcGISTiledMapServiceLayer(tiledUri) { ID = onlineTilePackage };
try
{
await agsTiledLayer.InitializeAsync();
if (agsTiledLayer.InitializationException != null)
{
FdmLogger.LogError("Trouble loading the online ArcGISTiledMapServiceLayer: ", agsTiledLayer.InitializationException.Message, " ", onlineTilePackage, " Will attempt to load the default online map");
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTiledLayer);
MdsOverviewMapView.Map.Layers.Add(agsTiledLayer);
return true;
}
}
catch (Exception ex)
{
FdmLogger.LogError("Trouble loading the online ArcGISTiledMapServiceLayer: ", ex.Message, " ", onlineTilePackage, " Will attempt to load the default online map");
return false;
}
}
Hi Jim,
You should be careful when not using Task as a return type when using the await keyword.
Async void is a "fire-and-forget" mechanism: the caller is unable to know when an async void has finished, and the caller is unable to catch any exceptions from it. The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task".
Thanks for the reply Antti
I ended up coming up with a solution last night that seemed to work. I will add my code example below so others can see what I've done. The real issues comes from connecting to an invlaid url and capturing it within a try catch resolved the issue.
private bool _alreadyLoadedMap;
private async void MdsMapView_OnLoaded(object sender, RoutedEventArgs e)
{
//this gets triggered every time you leave the map view
if (_alreadyLoadedMap) return;
if (!string.IsNullOrEmpty(_localArcGisTileLocation))
{
if(LoadLocalTilePackage(_localArcGisTileLocation))
{
_alreadyLoadedMap = true;
return;
}
}
Task<bool> loadBaseMapTask = null;
if (!string.IsNullOrEmpty(_onlineArcGisTileUrl))
{
loadBaseMapTask = LoadOnlineTilePackage(_onlineArcGisTileUrl);
if (!loadBaseMapTask.IsCompleted)
{
await loadBaseMapTask;
}
}
if ((loadBaseMapTask != null && !loadBaseMapTask.Result) || loadBaseMapTask == null)
{
LoadDefaultOnlineTilePackage();
}
_alreadyLoadedMap = true;
}
private bool LoadLocalTilePackage(string localTilePackage)
{
var agsTpkLayer = new ArcGISLocalTiledLayer(localTilePackage) { ID = localTilePackage };
var localTileTask = agsTpkLayer.InitializeAsync();
if (localTileTask.Exception != null)
{
foreach (var innerException in localTileTask.Exception.InnerExceptions)
{
FdmLogger.LogError("Trouble loading the local tile package: ", innerException.Message, " ", localTilePackage, " Will attempt to load an online map");
}
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTpkLayer);
MdsOverviewMapView.Map.Layers.Add(agsTpkLayer);
return true;
}
}
private async Task<bool> LoadOnlineTilePackage(string onlineTilePackage)
{
var tiledUri = new Uri(onlineTilePackage);
var agsTiledLayer = new ArcGISTiledMapServiceLayer(tiledUri) { ID = onlineTilePackage };
try
{
await agsTiledLayer.InitializeAsync();
if (agsTiledLayer.InitializationException != null)
{
FdmLogger.LogError("Trouble loading the online ArcGISTiledMapServiceLayer: ", agsTiledLayer.InitializationException.Message, " ", onlineTilePackage, " Will attempt to load the default online map");
return false;
}
else
{
MdsMapView.Map.Layers.Add(agsTiledLayer);
MdsOverviewMapView.Map.Layers.Add(agsTiledLayer);
return true;
}
}
catch (Exception ex)
{
FdmLogger.LogError("Trouble loading the online ArcGISTiledMapServiceLayer: ", ex.Message, " ", onlineTilePackage, " Will attempt to load the default online map");
return false;
}
}