ThinkGeo.com    |     Documentation    |     Premium Support

Possible Issues with Server Side Caching and IIS Deployment

We encountering an issue that might be related to using server-side caching with our site deployed on an IIS sever. Currently, we have several custom layers and are using an OpenStreettMaps background layer, all of which are using server-side tile caches. We are using pregenerated tiles for all the layers. The issue seems to be related to compiling our website and open connections on the IIS server. I have received the following e-mails recently. Any help in figuring out what the issue is and how to resolve it would be appreciated. I can provide more specific information as needed.

E-mail 1:

Over the last month or so, it is taking an extremely long time (10-20 minutes) to compile the production site, unless the IIS worker task is killed. Prior to this, we could drop an update in and users were not even aware. It seems this issue started around the same time we introduced the map tiling.

Any chance this could be related to the mapping update?

Fyi – it does seem to be a function of open connections. We can drop an update into the training site (same machine) and it compiles immediately

E-mail 2:

Had a situation today where the maps would not render and when running the app from the server saw (see attached screenshot). Issue was resolved by killing IIS process.

Looking for some succinct answers:

  1.  What would be involved in backing off the tiling functionality?
    
  2.  Can one of you research any know issues with this?
    

Only change that we can really seem to tie to issues that we have been having with IIS/web app is mapping.

Jim reported that even over the weekend when the worker threads recycled, it took an extended amount of time.

Hi Michael,

Without seeing what you were doing, I guess this problem should be really complicated for us to reproduce it.
According the attached screenshot, there are two exceptions “Parameter is not valid” and “Out of memory”, I guess there are two reasons for those exceptions: it occurs after your server runs a very long time or the faulty logic of pre- generate caching.

Please give a sample that shows how did you generate the cache in advance and how to use it, we can work based on it.

Thanks,
Emil

I am putting together a package with the tile generator, the shapefiles used, and a sample of our map setup. The tile generator will compile fine, you will just need to update the references to the Map Suite DLLs. The map related code is an excerpt from our main project so that you can see how we are setting up and using the maps. I just need to get permission to send these items.

What about the issues described in the first e-mail, and mentioned again in the second, with regard to compiling the site and IIS?

Edit: I have gotten permission to release this and have e-mailed the requested samples. The samples showing how we are setting up our map will obviously not compile as they are taken from our main project.

Hi Michael,

Sorry, I have not received package from our mailbox, could you please update it to forumsupport@thinkgeo.com or ask sales@thinkgeo.com for a FTP address to upload.
Please make sure that we can know which layers you use through the sample.

For"it is taking an extremely long time (10-20 minutes) to compile the production site":
I guess you should make sure the data files are not compiled into the assemblies as Embedded Resource. Please check “Build action” property of the files in Visual Studio.

Thanks,
Emil

I tried resending it, I think I had a typo in the e-mail address.

Let me ask a question, related to the compiling issue. Are queries on layers through the QueryTools thread safe? We have a static utility class that performs some queries on static ShapeFileFeatureLayer fields. We were not sure if this is a thread safe operation, so we placed a lock around the query. I spoke with a colleague, and we think the issues we are seeing when they try to update the production server might be from them attempting to overwrite the shapefiles while they are locked. The changed files, may then be causing issues with releasing the lock.

Hi Michael,

Thanks for sharing, I have received your package. I cannot reproduce the problem.

I viewed your codes and extracted the codes associated with the function “SetupOverlays()” in BaseMap.cs(Ln 330), and displayed the map successfully.
In addition, I found the overlays do not use server-cache, because the server-cache code is commented out. I modified those codes to use server-cache which generated by “MapTileCacheGenerator”, but I still failed to reproduce the problem.
I will continue to extract the logic associated with the map(including MarkerOverlay, HighlightOverlay ect), and try my best to find the cause of the problem.

For “QueryTools thread”, I di0d some tests and found that is a thread safe operation.

Thanks,
Emil

Sorry about that, I forgot that we temporarily disabled the server side caching before I put this package together while we are trying to track down the compiling issue.

Thank you for looking into the Layer QueryTools thead safety issue…

Hi Michael,

It looks your classes contains so many code, I think at first we need to make it simple so we can focus on solve the issue.

Our developer tried to built a simple sample contains some mainly logic from your class, but it failed to reproduce this exception. Mvc.zip (1.5 MB)

Could you please view it and add some code based on your project to help us reproduce the exception?

Regards,

Don

OK I will take a look at the supplied code. Trying to recreate the exception may be difficult as I did not see it happen firsthand. I am going to need to contact my colleagues to see if I can find out more about what they were doing when the exception occurred. I do not believe that this was a recurring issue, so it may be very difficult or impossible for us to reproduce. I will let know when I find out more information.

Hi Michael,

Thanks for your update, we will keep one eye on it.

Thanks,
Emil

Given the image I posted in the first message, my assumption was that the issue was with the base overlay (a LayerOverlay containing a OpenStreetMapLayer). I found out that this is from a real-time AVL map I made that is using an InMemoryMarkerOverlay to display route information. This marker overlay is setup to use a ClassBreakMarkerStyle that has two different class breaks defined. One displays the green markers for routes that are on time, you can see these in the picture. The other MarkerClassBreak is setup to display a similar marker, but in red for routes that are late. I am checking with my colleagues to see if we can find if there were any routes running late at this time.

Would it be possible for an error in the InMemoryMarkerOverlay, specifically related to one of class breaks used, to cause the blank background tiles with the exceptions shown?

Hi Michael,

It looks your background layer is cached tiles, if you double check the cached tiles and hadn’t found any tile shows “Parameter is not valid” or “Out of memory”, I think it won’t throw exception when our map just render the cached images.

And in the broken tile, the blue line and marker shows correct, so the two layers hadn’t problem there.

You mentioned you have a red lines for routing result, it looks there aren’t red lines in your screen shots, so does that means the exception come from this layer?

If you want to double check that, I think you can tried to disable the other layers and only show this layer, if you can reproduce this that means the problem is from this layer.

And follow this way, you can loop all the layers and found where is the problem and we can try to solve that after you find the reason.

Regards,

Don

Let me post the code used to setup the AVL layer and the code used to populate this layer.

Just to clarify my question, the map this occurred on displays green markers or red markers using the ClassBreakMarkerStyle. The green markers are setup in SetupOnTimeClassBreak() and are used for routes that are not late, while the red markers are setup in SetupLateClassBreak() and are used for routes that are late. As you can see in the screenshot there are no red markers showing. It is possible that there are no red markers displayed because there were no routes that were late when this occurred. Alternatively, there might not be any red markers because of some error.

Is it possible for the displayed errors to be caused by the map trying to render a marker that corresponds to a Feature created with bad or incomplete data?

Could errors in an InMemoryMarkerOverlay prevent the background tile, an OpenStreetMapLayer in a LayerOverlay, from rendering properly?

Layer Setup:

    /// <summary>
    /// Setup the AVL Overlay using an InMemoryMarkerOverlay.
    /// </summary>
    /// <param name="visible">Boolean indicating whether the Overlay is visible when the map loads.</param>
    /// <param name="visibleInOverlaySwitcher">Boolean indicating whether the Overlay is visible in the OverlaySwitcher tool on the map.</param>
    /// <returns>InMemoryMarkerOverlay for containing AVL data Markers.</returns>
    protected InMemoryMarkerOverlay SetupAVLOverlay(bool visible, bool visibleInOverlaySwitcher)
    {
        string overlayID = "avlOverlay", overlayName = "AVL Overlay";

        //Setup the FeatureSourceColumns.
        List<FeatureSourceColumn> columns = new List<FeatureSourceColumn>();

        //Add  the columns to the list.
        columns.Add(new FeatureSourceColumn("Id"));
        columns.Add(new FeatureSourceColumn("RouteId"));
        columns.Add(new FeatureSourceColumn("TimeStamp"));
        columns.Add(new FeatureSourceColumn("Longitude"));
        columns.Add(new FeatureSourceColumn("Latitude"));
        columns.Add(new FeatureSourceColumn("Speed"));
        columns.Add(new FeatureSourceColumn("Heading"));
        columns.Add(new FeatureSourceColumn("Route"));
        columns.Add(new FeatureSourceColumn("isLate"));

        //Create the InMemoryMarkerOverlay from the FeatureSourceColumns list.
        InMemoryMarkerOverlay avlOverlay = new InMemoryMarkerOverlay(overlayID, columns);

        //Set the Overlay's name, which will be displayed in the Overlay Switcher.
        avlOverlay.Name = overlayName;

        //Setup styles.

        //Create the ClassBreakMarkerStyle.
        ClassBreakMarkerStyle cbms = new ClassBreakMarkerStyle("isLate", BreakValueInclusion.IncludeValue);

        //Add MarkerClassBreak objects, they need to be added from smallest value to largest value.
        cbms.ClassBreaks.Add(SetupOnTimeClassBreak()); //Break Value: 0
        cbms.ClassBreaks.Add(SetupLateClassBreak()); //Break Value: 1

        //Setup the MarkerStyle on the ZoomLevels.
        avlOverlay.ZoomLevelSet.ZoomLevel01.CustomMarkerStyle = cbms;

        avlOverlay.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

        //Apply projection to layers, the projection must be opened before this is done and should be closed afterwards.
        try
        {
            WGS84toSphMercator.Open();

            avlOverlay.FeatureSource.Projection = WGS84toSphMercator;
        }
        finally
        {
            WGS84toSphMercator.Close();
        }

        //Set visibility, and return the constructed overlay.
        avlOverlay.IsVisible = visible;
        avlOverlay.IsVisibleInOverlaySwitcher = visibleInOverlaySwitcher;

        return avlOverlay;
    }

    /// <summary>
    /// Setup MarkerClassBreak for OnTime Routes. Break Value: 0
    /// </summary>
    /// <returns>A MarkerClassBreak object.</returns>
    protected MarkerClassBreak SetupOnTimeClassBreak()
    {
        //Create the WebImage used for the styles.
        WebImage wi = new WebImage();

        //Setup the FontStyle and TextOffset.
        wi.FontStyle = DefaultFont;
        wi.TextOffsetX = 20;

        //Set the Text property to use the value in the FeatureSource's Route column.
        wi.Text = "[#Route#]";

        //Offset the image displayed for the marker, this places the point of the teardrop at the location.
        wi.ImageOffsetX = -10.5f;
        wi.ImageOffsetY = -25f;

        //Set the path for this image.
        wi.ImageVirtualPath = @"~/Content/MapIcons/AVLMarkerOnTime.gif";

        //Create the MarkerClassBreak with the break value.
        MarkerClassBreak mcb = new MarkerClassBreak(0);

        //Set the DefaultMarkerStyle's WebImage property to our WebImage.
        mcb.DefaultMarkerStyle.WebImage = wi;

        //Setup the ContextMenu.
        ContextMenu menu = new ContextMenu();

        //Setup the Schedule Maintenance ContextMenuItem and add it to the ContextMenu.
        ContextMenuItem schedMaint = new ContextMenuItem();
        schedMaint.InnerHtml = "Schedule Maintenance";
        schedMaint.OnClientClick = "openScheduleMaintenance";
        schedMaint.CssClass = "mapMenu";
        schedMaint.HoverCssClass = "mapMenuHover";
        menu.MenuItems.Add(schedMaint);

        //Setup the Extended AVL Info ContextMenuItem and add it to the ContextMenu.
        ContextMenuItem extendAVLInfo = new ContextMenuItem();
        extendAVLInfo.InnerHtml = "Info";
        extendAVLInfo.OnClientClick = "getExtendedAVLInfo";
        extendAVLInfo.CssClass = "mapMenuLastItem";
        extendAVLInfo.HoverCssClass = "mapMenuHover";
        menu.MenuItems.Add(extendAVLInfo);

        //Set the ContextMenu width.
        menu.Width = 150;

        //Set the DefaultMarkStyle.ContextMenu of the MarkerClassBreak to the ContextMenu.
        mcb.DefaultMarkerStyle.ContextMenu = menu;

        return mcb;
    }

    /// <summary>
    /// Setup MarkerClassBreak for OnTime Routes. Break Value: 1
    /// </summary>
    /// <returns>A MarkerClassBreak object.</returns>
    protected MarkerClassBreak SetupLateClassBreak()
    {
        //Create the WebImage used for the styles.
        WebImage wi = new WebImage();

        //Setup the FontStyle and TextOffset.
        wi.FontStyle = DefaultFont;
        wi.TextOffsetX = 20;

        //Set the Text property to use the value in the FeatureSource's Route column.
        wi.Text = "[#Route#]";

        //Offset the image displayed for the marker, this places the point of the teardrop at the location.
        wi.ImageOffsetX = -10.5f;
        wi.ImageOffsetY = -25f;

        //Set the path for this image.
        wi.ImageVirtualPath = @"~/Content/MapIcons/AVLMarkerLate.gif";

        //Create the MarkerClassBreak with the break value.
        MarkerClassBreak mcb = new MarkerClassBreak(1);

        //Set the DefaultMarkerStyle's WebImage property to our WebImage.
        mcb.DefaultMarkerStyle.WebImage = wi;

        //Setup the ContextMenu.
        ContextMenu menu = new ContextMenu();

        //Setup the Schedule Maintenance ContextMenuItem and add it to the ContextMenu.
        ContextMenuItem schedMaint = new ContextMenuItem();
        schedMaint.InnerHtml = "Schedule Maintenance";
        schedMaint.OnClientClick = "openScheduleMaintenance";
        schedMaint.CssClass = "mapMenu";
        schedMaint.HoverCssClass = "mapMenuHover";
        menu.MenuItems.Add(schedMaint);

        //Setup the Extended AVL Info ContextMenuItem and add it to the ContextMenu.
        ContextMenuItem extendAVLInfo = new ContextMenuItem();
        extendAVLInfo.InnerHtml = "Info";
        extendAVLInfo.OnClientClick = "getExtendedAVLInfo";
        extendAVLInfo.CssClass = "mapMenuLastItem";
        extendAVLInfo.HoverCssClass = "mapMenuHover";
        menu.MenuItems.Add(extendAVLInfo);

        //Set the ContextMenu width.
        menu.Width = 150;

        //Set the DefaultMarkStyle.ContextMenu of the MarkerClassBreak to the ContextMenu.
        mcb.DefaultMarkerStyle.ContextMenu = menu;

        return mcb;
    }

Layer Population (potentitally called every 60 seconds):

    /// <summary>
    /// Populates the maps AVL data layer.
    /// </summary>
    /// <param name="map">The ThinkGeo Map object.</param>
    /// <param name="data">List of datapoints to populate the overlay.</param>
    protected RectangleShape PopulateMapAVLOverlay(Map map, List<vAvlMapData> data)
    {
        RectangleShape newExtent;

        //Get the overlay from the map.
        InMemoryMarkerOverlay avlOverlay = (InMemoryMarkerOverlay)map.CustomOverlays[avlOverlayID];

        //Clear the InternalFeatures of the overlay. Note we do not need to open and close the FeatureSource when using the InternalFeatures property of the InMemoryFeatureSource.
        avlOverlay.FeatureSource.InternalFeatures.Clear();

        //Create features from data and add to the overlay.
        if (data != null && data.Count > 0)
        {
            foreach (vAvlMapData datum in data)
            {
                Dictionary<string, string> dict = new Dictionary<string, string>();

                //AVL data.
                dict.Add("Id", datum.avlId.ToString());
                dict.Add("RouteId", datum.avlrteId.ToString());
                dict.Add("TimeStamp", datum.avlTimeStamp.ToString());
                dict.Add("Longitude", datum.avlLongitude.ToString());
                dict.Add("Latitude", datum.avlLatitude.ToString());
                dict.Add("Speed", datum.avlSpeed.ToString());
                dict.Add("Heading", datum.avlHeading.ToString());
                dict.Add("Route", datum.rteName.ToString());

                if (SPs.GetAVLIsLate(datum.avlrteId))
                {
                    dict.Add("isLate", "1");
                }
                else
                {
                    dict.Add("isLate", "0");
                }

                //Create a PointShape for the Features position.
                PointShape position = MappingUtility.PointShapeFromDBCoords(datum.avlLatitude, datum.avlLongitude);


                //Create the Feature and add it the overlay's InternalFeatures.
                Feature newFeature = new Feature(new Vertex(position), datum.avlId.ToString(), dict);

                avlOverlay.FeatureSource.InternalFeatures.Add(newFeature);
            }
        }

        //Get the bounding box for the Overlay's Features.
        if (avlOverlay.FeatureSource.InternalFeatures.Count > 0)
        {
            try
            {
                //The FeatureSource must be opened before the GetBoundingBox method is called, and needs to be closed afterwards.
                avlOverlay.FeatureSource.Open();

                newExtent = avlOverlay.FeatureSource.GetBoundingBox();
            }
            finally
            {
                avlOverlay.FeatureSource.Close();
            }
        }
        else
        {
            //No data in FeatureSource, so use the projected default extent.
            newExtent = MappingUtility.GetProjectedDefaultExtent(MappingUtility.WGS84toSphMercator);
        }

        //Return new map extent
        return newExtent;
    }

Hi Michael,

Whether the layer can cover the background tile is decided with it’s type, I think the marker layer cannot cover the background layer, so I just suggest you to remove some layers which you found work well, then you can find which layer shows the message like “Our of Memory” and “Parameter is not valid”, without a sample which can reproduce that, we can only try to find the problem follow this process.

And I am not sure how the feature will be bad, because the feature for marker should only contains a coordinates information or some other message, if it’s not correct, it won’t be shown, or the program will throw exception.

We will try to reproduce that again based on the project we provided before, and if you found which layer make this error tile by exclusive method please let us know.

Regards,

Don