Runtime Workaround #5: Tile Cache Hang-ups

Blog Post created by MCederholm on Nov 13, 2019

Recently, I found myself painted into a corner.  Some time ago, I'd created custom tile caches for use with Runtime .NET, which had one scale level defined.  They worked just fine in 10.2.7, but on preparing to upgrade to 100.x, I discovered that they caused 100.6 to hang up.  The workaround was simple enough, namely to define additional scale levels, even if they weren't populated.  However, the task of modifying the caches for nearly 150 users proved so daunting, that I decided to let the app itself make the modification.  Updates to the app are automatically detected and downloaded, which provides a simpler mechanism than deploying a script to everyone's machine. It's not a perceptible performance hit as it is, and later on, as part of another update, I can simply deactivate it.  So here's the code:



using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace NavAddin

      * Runtime 100.6 BUG: Tile caches that have only one scale level level defined will hang up on loading.
      * WORKAROUND: Define additional scale levels
      * [Assumes that 100 < scale level < 24000]

     public static class TileCacheHelper

          public const string L0Scale = "24000";
          public const string L0Resolution = "20.833375000083333";
          public const string L2Scale = "100";
          public const string L2Resolution = "0.086805729167013887";

          public static bool CheckTileCache(string sPath)

               // Check if tile cache (i.e. a folder)

               if (!Directory.Exists(sPath))
                    return true; // Not a tile cache

               // Check if one scale level defined

               string sConfigPath = Path.Combine(sPath, "conf.xml");
               StreamReader sr = new StreamReader(sConfigPath);
               XDocument xDoc = XDocument.Load(sr);
               XElement xRoot = xDoc.Root;
               XElement xTCInfo = xRoot.Element("TileCacheInfo");
               XElement xLODInfos = xTCInfo.Element("LODInfos");
               int iLevelCount = xLODInfos.Elements("LODInfo").Count();
               if (iLevelCount > 1)
                    return true; // Not a problem
               if (iLevelCount < 1)
                    return false; // This should never happen?

               // Check if scale level is between 100 (L2) and 24000 (L0)

               XElement xLODInfo, xLevelID, xScale, xResolution;

               xLODInfo = xLODInfos.Element("LODInfo");
               xScale = xLODInfo.Element("Scale");
               string sScale = xScale.Value;
               double dScale = Convert.ToDouble(sScale);
               double dL0Scale = Convert.ToDouble(L0Scale);
               double dL2Scale = Convert.ToDouble(L2Scale);
               if (dScale >= dL0Scale)
                    return false;
               if (dScale <= dL2Scale)
                    return false;

               // Redefine scale levels

               xLevelID = xLODInfo.Element("LevelID");
               xLevelID.Value = "1";
               XElement xLOD0 = new XElement(xLODInfo);
               xLevelID = xLOD0.Element("LevelID");
               xLevelID.Value = "0";
               xScale = xLOD0.Element("Scale");
               xScale.Value = L0Scale;
               xResolution = xLOD0.Element("Resolution");
               xResolution.Value = L0Resolution;
               XElement xLOD2 = new XElement(xLODInfo);
               xLevelID = xLOD2.Element("LevelID");
               xLevelID.Value = "2";
               xScale = xLOD2.Element("Scale");
               xScale.Value = L2Scale;
               xResolution = xLOD2.Element("Resolution");
               xResolution.Value = L2Resolution;

               // Write config file

               StreamWriter sw = new StreamWriter(sConfigPath);

               // Rename L00 folder to L01

               string sLayersPath = Path.Combine(sPath, "_alllayers");
               string sL00Path = Path.Combine(sLayersPath, "L00");
               string sL01Path = Path.Combine(sLayersPath, "L01");
               Directory.Move(sL00Path, sL01Path);

               return true;