private byte[] TryRequestTileData(TileInfo tileInfo) { byte[] result = null; try { openTileRequests.TryAdd(tileInfo.Index, 1); result = provider.GetTile(tileInfo); } catch { // Nothing has to be done with the exception. // Result should stay null } //Try at least once again if (result == null) { try { result = provider.GetTile(tileInfo); } catch { // Nothing has to be done with the exception. // Result should stay null } } return(result); }
private void GetTileOnThread(object parameter) { object[] parameters = (object[])parameter; if (parameters.Length != 4) { throw new ArgumentException("Four parameters expected"); } ITileProvider tileProvider = (ITileProvider)parameters[0]; TileInfo tileInfo = (TileInfo)parameters[1]; MemoryCache <byte[]> bitmaps = (MemoryCache <byte[]>)parameters[2]; AutoResetEvent autoResetEvent = (AutoResetEvent)parameters[3]; byte[] bytes; try { bitmaps.Add(tileInfo.Key, tileProvider.GetTile(tileInfo)); } catch (Exception ex) { //todo: log and use other ways to report to user. } finally { autoResetEvent.Set(); } }
private void GetTileOnThread(object parameter) { object[] parameters = (object[])parameter; if (parameters.Length != 5) { throw new ArgumentException("Five parameters expected"); } ITileProvider tileProvider = (ITileProvider)parameters[0]; TileInfo tileInfo = (TileInfo)parameters[1]; //MemoryCache<Bitmap> bitmaps = (MemoryCache<Bitmap>)parameters[2]; Dictionary <TileIndex, Bitmap> bitmaps = (Dictionary <TileIndex, Bitmap>)parameters[2]; AutoResetEvent autoResetEvent = (AutoResetEvent)parameters[3]; bool retry = (bool)parameters[4]; var setEvent = true; try { byte[] bytes = tileProvider.GetTile(tileInfo); Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null) { AddImageToFileCache(tileInfo, bitmap); } } catch (WebException ex) { if (retry) { GetTileOnThread(new object[] { tileProvider, tileInfo, bitmaps, autoResetEvent, false }); setEvent = false; return; } if (_showErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(_source.Schema.Width, _source.Schema.Height); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, _source.Schema.Width, _source.Schema.Height)); } bitmaps.Add(tileInfo.Index, bitmap); } } catch (Exception ex) { Logger.Error(ex.Message); } finally { if (setEvent) { autoResetEvent.Set(); } } }
private static bool EqualTileProviders(ITileProvider tp1, ITileProvider tp2, out string message) { if (!ReferenceEquals(tp1, tp2)) { if (tp1 == null) { message = "The reference tile provider is null!"; return(false); } if (tp2 == null) { message = "One of the tile providers is null, and the other not"; return(false); } if (tp1.GetType() != tp2.GetType()) { message = "Tile providers are of different type"; return(false); } for (var i = 0; i < 8; i++) { TileInfo ti = null; try { ti = RandomTileInfo(); var t1 = tp1.GetTile(ti); var t2 = tp2.GetTile(ti); if (!TilesEqual(t1, t2)) { message = "Request builders produce different results for same tile request"; return(false); } } catch (WebException ex) { if (ti == null) { Console.WriteLine("No tile info!"); } else { Console.WriteLine("TileInfo: {0}, {1}, {2}\n{3}\n{4}", ti.Index.Level, ti.Index.Col, ti.Index.Row, ex.Message, ex.Response.ResponseUri); } } } } message = "Tile providers appear to be equal"; return(true); }
public byte[] GetTile(TileInfo tileInfo) { byte[] bytes = cache.Find(tileInfo.Index); if (bytes == null) { bytes = provider.GetTile(tileInfo); if (bytes != null) { cache.Add(tileInfo.Index, bytes); } } return(bytes); }
private void GetTileOnThread(object parameter) { object[] parameters = (object[])parameter; if (parameters.Length != 4) { throw new ArgumentException("Four parameters expected"); } ITileProvider tileProvider = (ITileProvider)parameters[0]; TileInfo tileInfo = (TileInfo)parameters[1]; ITileCache <byte[]> bitmaps = (ITileCache <byte[]>)parameters[2]; AutoResetEvent autoResetEvent = (AutoResetEvent)parameters[3]; try { byte[] bytes = tileProvider.GetTile(tileInfo); Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bytes); } catch (WebException ex) { if (ShowErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var width = TileSource.Schema.GetTileWidth(tileInfo.Index.Level); var height = TileSource.Schema.GetTileHeight(tileInfo.Index.Level); Bitmap bitmap = new Bitmap(width, height); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, width, height)); graphics.Dispose(); using (MemoryStream m = new MemoryStream()) { bitmap.Save(m, ImageFormat.Png); bitmaps.Add(tileInfo.Index, m.ToArray()); } } } catch (Exception ex) { StackFrame CallStack = new StackFrame(1, true); Trace.WriteLine("Error: " + ex.Message + ", File: " + CallStack.GetFileName() + ", Line: " + CallStack.GetFileLineNumber()); } finally { autoResetEvent.Set(); } }
private void GetTileOnThread(object parameter) { object[] parameters = (object[])parameter; if (parameters.Length != 4) { throw new ArgumentException("Three parameters expected"); } ITileProvider tileProvider = (ITileProvider)parameters[0]; TileInfo tileInfo = (TileInfo)parameters[1]; MemoryCache <Bitmap> bitmaps = (MemoryCache <Bitmap>)parameters[2]; AutoResetEvent autoResetEvent = (AutoResetEvent)parameters[3]; byte[] bytes; try { bytes = tileProvider.GetTile(tileInfo); Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null) { AddImageToFileCache(tileInfo, bitmap); } } catch (WebException ex) { if (_showErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. Bitmap bitmap = new Bitmap(_source.Schema.Width, _source.Schema.Height); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, _source.Schema.Width, _source.Schema.Height)); bitmaps.Add(tileInfo.Index, bitmap); } } catch (Exception ex) { //todo: log and use other ways to report to user. } finally { autoResetEvent.Set(); } }
public void FetchTile() { Exception error = null; byte[] image = null; try { if (_tileProvider != null) { image = _tileProvider.GetTile(_tileInfo); } } catch (Exception ex) // On this worker thread exceptions will not fall through to the caller so catch and pass in callback { error = ex; } _fetchTileCompleted(this, new FetchTileCompletedEventArgs(error, false, _tileInfo, image)); }
public void FetchTile(object state) { Exception error = null; byte[] image = null; try { if (_tileProvider != null) { image = _tileProvider.GetTile(_tileInfo); } } catch (Exception ex) //This may seem a bit weird. We catch the exception to pass it as an argument. This is because we are on a worker thread here, we cannot just let it fall through. { error = ex; } _fetchTileCompleted(this, new FetchTileCompletedEventArgs(error, false, _tileInfo, image)); }
/// <summary> /// Gets the image content of the tile /// </summary> public byte[] GetTile(TileInfo tileInfo) { return(_provider.GetTile(tileInfo)); }
private static bool EqualTileProviders(ITileSchema schema, ITileProvider tp1, ITileProvider tp2, out string message) { if (!ReferenceEquals(tp1, tp2)) { if (tp1 == null) { message = "The reference tile provider is null!"; return(false); } if (tp2 == null) { message = "One of the tile providers is null, and the other not"; return(false); } if (tp1.GetType() != tp2.GetType()) { message = "Tile providers are of different type"; return(false); } var keys = schema.Resolutions.Keys.ToArray(); var minkey = GetIndex(keys[0]); var maxKey = GetIndex(keys[keys.Length - 1]); var prefix = GetPrefix(keys[0]); for (var i = 0; i < 3; i++) { TileInfo ti = null; try { ti = RandomTileInfo(prefix + "{0}", minkey, Math.Min(maxKey, 12)); var req1 = tp1 as IRequest; var req2 = tp2 as IRequest; if (req1 != null && req2 != null) { if (req1.GetUri(ti) != req2.GetUri(ti)) { message = "Request builders produce different uris for the same request"; return(false); } } else { var t1 = tp1.GetTile(ti); var t2 = tp2.GetTile(ti); if (!TilesEqual(t1, t2)) { message = "Request builders produce different results for same tile request"; return(false); } } } catch (TimeoutException ex) { System.Diagnostics.Trace.WriteLine(string.Format( "TileInfo({4}): {0}, {1}, {2}\n{3}", ti.Index.Level, ti.Index.Col, ti.Index.Row, ex.Message, i)); } catch (WebException ex) { if (ti == null) { System.Diagnostics.Trace.WriteLine("No tile info!"); } else { System.Diagnostics.Trace.WriteLine(string.Format( "TileInfo({5}): {0}, {1}, {2}\n{3}\n{4}", ti.Index.Level, ti.Index.Col, ti.Index.Row, ex.Message, ex.Response.ResponseUri, i)); } } } } message = "Tile providers appear to be equal"; return(true); }
/// <summary> /// /// </summary> /// <param name="cancelToken"></param> /// <param name="tileProvider"></param> /// <param name="tileInfo"></param> /// <param name="bitmaps"></param> /// <param name="retry"></param> /// <returns>true if thread finished without getting cancellation signal, false = cancelled</returns> private bool GetTileOnThread(CancellationToken cancelToken, ITileProvider tileProvider, TileInfo tileInfo, MemoryCache <Bitmap> bitmaps, bool retry) { byte[] bytes; try { if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } //We may have gotten the tile from another thread now.. if (bitmaps.Find(tileInfo.Index) != null) { return(true); } if (Logger.IsDebugEnabled) { Logger.DebugFormat("Calling gettile on provider for tile {0},{1},{2}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row); } bytes = tileProvider.GetTile(tileInfo); if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } using (var ms = new MemoryStream(bytes)) { Bitmap bitmap = new Bitmap(ms); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } OnMapNewTileAvaliable(tileInfo, bitmap); } return(true); } catch (WebException ex) { if (Logger.IsDebugEnabled) { Logger.DebugFormat("Exception downloading tile {0},{1},{2} {3}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row, ex.Message); } if (retry) { return(GetTileOnThread(cancelToken, tileProvider, tileInfo, bitmaps, false)); } else { if (_showErrorInTile) { var tileWidth = _source.Schema.GetTileWidth(tileInfo.Index.Level); var tileHeight = _source.Schema.GetTileHeight(tileInfo.Index.Level); //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(tileWidth, tileHeight); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, tileWidth, tileHeight)); } //Draw the Timeout Tile OnMapNewTileAvaliable(tileInfo, bitmap); //With timeout we don't add to the internal cache //bitmaps.Add(tileInfo.Index, bitmap); } return(true); } } catch (System.OperationCanceledException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } return(false); } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); //This is not due to cancellation so return true return(true); } }
private void GetTileOnThread(CancellationToken cancelToken, ITileProvider tileProvider, TileInfo tileInfo, MemoryCache <Bitmap> bitmaps, bool retry) { byte[] bytes; try { if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } bytes = tileProvider.GetTile(tileInfo); if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } OnMapNewTileAvaliable(tileInfo, bitmap); } catch (WebException ex) { if (retry) { GetTileOnThread(cancelToken, tileProvider, tileInfo, bitmaps, false); } else { if (_showErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(_source.Schema.Width, _source.Schema.Height); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, _source.Schema.Width, _source.Schema.Height)); } //Draw the Timeout Tile OnMapNewTileAvaliable(tileInfo, bitmap); //With timeout we don't add to the internal cache //bitmaps.Add(tileInfo.Index, bitmap); } } } catch (ThreadAbortException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); } }
private void GetTileOnThread(CancellationToken cancelToken, ITileProvider tileProvider, TileInfo tileInfo, MemoryCache<Bitmap> bitmaps, bool retry) { byte[] bytes; try { if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); bytes = tileProvider.GetTile(tileInfo); if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); OnMapNewTileAvaliable(tileInfo, bitmap); } catch (WebException ex) { if (retry) { GetTileOnThread(cancelToken, tileProvider, tileInfo, bitmaps, false); } else { if (_showErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(_source.Schema.Width, _source.Schema.Height); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, _source.Schema.Width, _source.Schema.Height)); } //Draw the Timeout Tile OnMapNewTileAvaliable(tileInfo, bitmap); //With timeout we don't add to the internal cache //bitmaps.Add(tileInfo.Index, bitmap); } } } catch (ThreadAbortException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); } }
/* * private void OnMapNewtileAvailableHelper(object parameter) * { * //this is to wait for the main UI thread to finalize rendering ... (buggy code here)... * System.Threading.Thread.Sleep(100); * object[] parameters = (object[])parameter; * if (parameters.Length != 2) throw new ArgumentException("Two parameters expected"); * TileInfo tileInfo = (TileInfo)parameters[0]; * Bitmap bm = (Bitmap)parameters[1]; * OnMapNewTileAvaliable(tileInfo, bm); * } */ private void GetTileOnThread(BackgroundWorker worker, object parameter) { Thread.Sleep(50 + (_r.Next(5) * 10)); object[] parameters = (object[])parameter; if (parameters.Length != 4) { throw new ArgumentException("Four parameters expected"); } ITileProvider tileProvider = (ITileProvider)parameters[0]; TileInfo tileInfo = (TileInfo)parameters[1]; MemoryCache <Bitmap> bitmaps = (MemoryCache <Bitmap>)parameters[2]; bool retry = (bool)parameters[3]; byte[] bytes; try { if (worker.CancellationPending) { return; } bytes = tileProvider.GetTile(tileInfo); if (worker.CancellationPending) { return; } Bitmap bitmap = new Bitmap(new MemoryStream(bytes)); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (worker.CancellationPending) { return; } OnMapNewTileAvaliable(tileInfo, bitmap); //if (worker.CancellationPending) // return; } catch (WebException ex) { if (retry) { parameters[3] = false; GetTileOnThread(worker, parameters); } else { if (_showErrorInTile) { //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(_source.Schema.Width, _source.Schema.Height); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, _source.Schema.Width, _source.Schema.Height)); } //Draw the Timeout Tile OnMapNewTileAvaliable(tileInfo, bitmap); //With timeout we don't add to the internal cache //bitmaps.Add(tileInfo.Index, bitmap); } } } catch (ThreadAbortException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); } }
/// <summary> /// /// </summary> /// <param name="cancelToken"></param> /// <param name="tileProvider"></param> /// <param name="tileInfo"></param> /// <param name="bitmaps"></param> /// <param name="retry"></param> /// <returns>true if thread finished without getting cancellation signal, false = cancelled</returns> private bool GetTileOnThread(CancellationToken cancelToken, ITileProvider tileProvider, TileInfo tileInfo, MemoryCache<Bitmap> bitmaps, bool retry) { byte[] bytes; try { if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); //We may have gotten the tile from another thread now.. if (bitmaps.Find(tileInfo.Index) != null) { return true; } if (Logger.IsDebugEnabled) Logger.DebugFormat("Calling gettile on provider for tile {0},{1},{2}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row); bytes = tileProvider.GetTile(tileInfo); if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); using (var ms = new MemoryStream(bytes)) { Bitmap bitmap = new Bitmap(ms); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (cancelToken.IsCancellationRequested) cancelToken.ThrowIfCancellationRequested(); OnMapNewTileAvaliable(tileInfo, bitmap); } return true; } catch (WebException ex) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Exception downloading tile {0},{1},{2} {3}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row, ex.Message); if (retry) { return GetTileOnThread(cancelToken, tileProvider, tileInfo, bitmaps, false); } else { if (_showErrorInTile) { var tileWidth = _source.Schema.GetTileWidth(tileInfo.Index.Level); var tileHeight = _source.Schema.GetTileHeight(tileInfo.Index.Level); //an issue with this method is that one an error tile is in the memory cache it will stay even //if the error is resolved. PDD. var bitmap = new Bitmap(tileWidth, tileHeight); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, tileWidth, tileHeight)); } //Draw the Timeout Tile OnMapNewTileAvaliable(tileInfo, bitmap); //With timeout we don't add to the internal cache //bitmaps.Add(tileInfo.Index, bitmap); } return true; } } catch (System.OperationCanceledException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } return false; } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); //This is not due to cancellation so return true return true; } }
/// <summary> /// Method to actually get the tile from the <see cref="_provider"/>. /// </summary> /// <param name="parameter">The parameter, usually a <see cref="TileInfo"/> and a <see cref="AutoResetEvent"/></param> private void GetTileOnThread(object parameter) { var @params = (object[])parameter; var tileInfo = (TileInfo)@params[0]; byte[] result = null; //Try get the tile try { _openTileRequests.TryAdd(tileInfo.Index, 1); result = _provider.GetTile(tileInfo); } // ReSharper disable once EmptyGeneralCatchClause catch { } //Try at least once again if (result == null) { try { result = _provider.GetTile(tileInfo); } catch { if (!AsyncMode) { var are = (AutoResetEvent)@params[1]; are.Set(); } } } //Remove the tile info request int one; if (!_activeTileRequests.TryRemove(tileInfo.Index, out one)) { //try again _activeTileRequests.TryRemove(tileInfo.Index, out one); } if (!_openTileRequests.TryRemove(tileInfo.Index, out one)) { //try again _openTileRequests.TryRemove(tileInfo.Index, out one); } if (result != null) { //Add to the volatile cache _volatileCache.Add(tileInfo.Index, result); //Add to the perma cache _permaCache.Add(tileInfo.Index, result); if (AsyncMode) { //Raise the event OnTileReceived(new TileReceivedEventArgs(tileInfo, result)); } else { var are = (AutoResetEvent)@params[1]; are.Set(); } } }
/// <summary> /// /// </summary> /// <param name="cancelToken"></param> /// <param name="tileProvider"></param> /// <param name="tileInfo"></param> /// <param name="bitmaps"></param> /// <param name="retry"></param> /// <returns><c>true</c> if task finished without getting a cancellation signal, otherwise <c>false</c></returns> private bool GetTileOnThread(CancellationToken cancelToken, ITileProvider tileProvider, TileInfo tileInfo, ITileCache <Bitmap> bitmaps, bool retry) { try { if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } //We may have gotten the tile from another thread now. if (bitmaps.Find(tileInfo.Index) != null) { return(true); } if (Logger.IsDebugEnabled) { Logger.DebugFormat("Calling ITileProvider.GetTile for tile {0},{1},{2}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row); } byte[] bytes = tileProvider.GetTile(tileInfo); if (bytes == null) { return(true); } if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } using (var ms = new MemoryStream(bytes)) { var bitmap = new Bitmap(ms); bitmaps.Add(tileInfo.Index, bitmap); if (_fileCache != null && !_fileCache.Exists(tileInfo.Index)) { AddImageToFileCache(tileInfo, bitmap); } if (cancelToken.IsCancellationRequested) { cancelToken.ThrowIfCancellationRequested(); } OnMapNewTileAvailable(tileInfo, bitmap); } return(true); } catch (WebException ex) { if (Logger.IsDebugEnabled) { Logger.DebugFormat("Exception downloading tile {0},{1},{2} {3}", tileInfo.Index.Level, tileInfo.Index.Col, tileInfo.Index.Row, ex.Message); } if (retry) { return(GetTileOnThread(cancelToken, tileProvider, tileInfo, bitmaps, false)); } if (!_showErrorInTile) { var index = tileInfo.Index; Logger.Debug(fmh => fmh("Failed to get tile ({0},{1},{2}), returning true anyway", index.Level, index.Col, index.Row)); return(true); } // create the timeout tile int tileWidth = _source.Schema.GetTileWidth(tileInfo.Index.Level); int tileHeight = _source.Schema.GetTileHeight(tileInfo.Index.Level); var bitmap = new Bitmap(tileWidth, tileHeight); using (var graphics = Graphics.FromImage(bitmap)) { graphics.DrawString(ex.Message, new Font(FontFamily.GenericSansSerif, 12), new SolidBrush(Color.Black), new RectangleF(0, 0, tileWidth, tileHeight)); } //Draw the Timeout Tile OnMapNewTileAvailable(tileInfo, bitmap); return(true); } catch (OperationCanceledException tex) { if (Logger.IsInfoEnabled) { Logger.InfoFormat("TileAsyncLayer - Thread aborting: {0}", Thread.CurrentThread.Name); Logger.InfoFormat(tex.Message); } return(false); } catch (Exception ex) { Logger.Warn("TileAsyncLayer - GetTileOnThread Exception", ex); //This is not due to cancellation so return true return(true); } }