ThinkGeo.com    |     Documentation    |     Premium Support

Problem with multi access

Hi,


I created the function GetMapImage() based on the sample codes provided.  It works very well with one client application.  But now when I test my web server with two clients and when I pan the maps almost simultaneously,  an exception is raised and my client program crashes.  I found out that the crash happens when the function MapEngine.DrawStaticLayers() is called


Here is my code:



            try
            {
                mapEngine.OpenAllLayers();

                lock (mapEngine)
                {
                    mapEngine.DrawStaticLayers(bitmap, GeographyUnit.Meter);

                }
                mapEngine.CloseAllLayers();
            }
            catch (Exception ex)
            {
                string strTest = "";

                strTest = "SOMETHING IS WRONG";
            }


The error in the stack is “The Layer must be opened before you can perform this method. 


What does it mean by that? I suppose all layers are opened when OpenAllLayers() is called.


Thanks!


 



Tracy, 
  
 Thanks for your post! 
  
 I think as you said, this problem will happen ONLY when more than 1 clients will access the server.  When one of the clients closes the layer, the other clients may be trying to draw it while finding the layers is closed. 
  
 So, I think 2 solutions for your problems. 
 1) Try to make asynchronous access for your server that is to say that, guarantee only one client access the server at one time. 
 2) DONOT close the layers at server side. 
  
 Let me know if you have any problems. 
  
 Thanks. 
  
 Yale 


Hi Yale, 
  
 I chose the 2nd solution provided by you so now I don’t close my layers at server side.  However, it still raises an exception when I pan my maps simultaneously.  I want my server to be accessed by more than 1 client at a time.   
  
 Thanks, 
 Tracy

Tracy, 
  
 Which version you are using?  Did you use the latest public release version of Service Edition 3.1.182 or some other version (3.0.124)? 
  
 We did some tests against it as following: we setup a server which deals with clients request, we use 2 clients to send request with a timer tick set differently but still failed to recreate it. 
  
 I suspect you close the layer some hidden places. 
  
 Any more information will be appreciated! 
  
 Thanks. 
  
 Yale 


Hi Yale,


Our Dll version is MapSuiteCore.dll is 3.1.182



      private void DrawLayer(ref Bitmap bitmap, string layerName)
      {
            MapEngine TempmapEngine;
            DateTime startTime1 = DateTime.Now;

            try
            {
                if (appHash["Open_NA"] == null)
                {
                    TempmapEngine = (MapEngine)appHash["NA_mapEngine"];

                    TempmapEngine.OpenAllLayers();      < ----- This is the only place that opens all the layers (only gets called on first open)

                    appHash["Open_NA"] = 1;  < ----- when I check this break point before open layers all layers isOpen = false
                }                                                                              
                switch (layerName.ToUpperInvariant())

                {
                    case "RICHMOND":
                        TempmapEngine = (MapEngine)appHash["NA_mapEngine"]; < ----- break point isopen for each layer = true
                        break;
                    default:
                        TempmapEngine = new MapEngine();
                        break;
                }

                 TempmapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(gRecShp, gimgWidth, gimgHeight);

                TempmapEngine.DrawStaticLayers(bitmap, GeographyUnit.Meter);
            }
            catch (Exception ex)
            {
                string strTest = "";

                strTest = "Error draw Shape MSG: " + ex.Message; < --- error message when more then one connection "Error draw Shape MSG: Object is currently in use elsewhere."
            }   
    }

You mentioned you set up the a web server and send client requests by using timers.  Can I have your code for reference?


Thanks again,


Tracy



Tracy, 



After long test, we still CANNOT recreate the problem sometimes as you said! 



We will try to do more investigation and send you a demo as soon as possible. Thanks for your reporting! 



Any more questions just let me know. 



Thanks. 



Yale 

 



Tracy,


 Attachment is the demo we used for testing! If we uncomment the ClosedAllLayers , then the exception will be throw sometimes.
 
Any more questions just let me know.
 
Thanks.
 
Yale

1088-Post_5981_Demo.zip (203 KB)

Hi Yale, 
  
 Thanks for the sample code.  Regarding the executing of CloseAllLayers(), we know how that works. 
  
 our main issue is with the DrawStaticLayers.  We want to know how we can modify our code to be able to simultaneously draw different bitmaps. 
 In your sample code you used lock() function, which we have tried before, but that would prevent simultaneously drawing from mapengine.   
  
 also note that our shape file is open as readonly. 
  
 Thanks again, 
  
 Tracy

Tracy, 
  
 Yes, I know the problem now. 
  
 The solution for this you should create a MapEngine every time a request comes in, while currently , what you have done is probably shared the same “MapEngine” to draw bitmaps for different clients requests comes in, whiles the MapEngine have to keep its own properties. 
  
 Any more questions feel free to let me know. 
  
 Thanks. 
  
 Yale 


Hi Yale,


Thanks for the reply...


2 things:

1) the above solution, is something we did in the first test run... but found that adding each layer to the MapEngine every time slows down the loading process. so changed our implementation to using single open layer process.  Is there something else that we can do to speed up creating new MapEngine with every client call?


2) question: if we use the above solution can we initialize all layers globally, then each client request, create a new MapEngine and add the globally defined layers into the new MapEngine?


e.g.


if (appHash["Open_NA"] == null)

{

    ShapeFileFeatureLayer layer = null;

    layer = new ShapeFileFeatureLayer(shpfileName, ShapeFileReadWriteMode.ReadOnly);

    layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

    layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.State1;

    layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle.OutlinePen.LineJoin = DrawingLineJoin.Round;

    Application["Open_NA"] = layer;

}


TempmapEngine = new MapEngine();

TempmapEngine.StaticLayers.Add((ShapeFileFeatureLayer)Application["Open_NA"]);

TempmapEngine.OpenAllLayers();

TempmapEngine.CurrentExtent = ExtentHelper.GetDrawingExtent(gRecShp, gimgWidth, gimgHeight);

TempmapEngine.DrawStaticLayers(bitmap, GeographyUnit.Meter);

TempmapEngine.CloseAllLayers();


I did something like above but the map display gets all mixed up from different request (see attached picture "mapstuff.jpg")..


Thanks again, 



Tracy


 



Hi, Tracy, 



I did not see you attachment “mapstuff.jpg” in your previous post :-)



3 things I want to clear up here hope it helps. 

1) In the above solution, we still cannot share the shape file layers or raster layers as you try to define globally, while if it is GoogleLayer or VELayer , probably it could. 

The reason is that in the shape file, we will keep of bunch of stream (.shp, .shx, .dbf, .idx & .ids), we should keep the stream unique for each layer. 



2) We tested that it would probably slow down about 10% for the loading process every time. 



3) If we can have one MapEngine for each client, then we can call the  CloseAllLayers after its drawing finish. 



Let me know if any more questions. 



Thanks. 



Yale