Hi,
I think that it could be more than useful to be able to test if a redraw layer that has been initialized on the client side is currently active on a server side. I have an application that is using the OnExtentChanged map event to retrieve the data point belonging to the current bounding box but I am facing synchronization issues. I have used all the open layers overlay events like ‘loadstart’, ‘loadend’ to avoid calling the server when redraw layer has been requested by the client but I was not able to ensure 100% success using this method! If you could set a lock on the server side when the internal thinkgeo code is using the customer overlays / layers then it could be possible to avoid colliding between what I call customer code (my code) and internal code (thinkgeo code).
let me know what do you think.
jm.
Client / server synchronization
I am working on updating / loading the data points belonging to the current map extent (bounding box) by using the on map "OnExtentChanged" event which in theory make sense… one want to load only the data point inside the current viewport!
However, I think that I have exhausted all options to make it to work without issues at all… When the map move the "OnExtentChanged" event is triggered then we use Ajax to call the controller then the controller query the data then update the inmemory feature layer then send an answer back to the client asking for a redraw layer on the client side. So far so good but this is where things start to break down… when the redraw layer is active something is executed on the server side, mostly thinkgeo internal process linked with the redraw layer action but what if the map is pan and zoom at this very same time … well the extent event is triggered then ajax call the server and then we want to work with the layer that is currently used by the redraw layer… and of course the process break with stuff like: "you have open the layer,… not in transaction and much much more…". Of course the layer has been opened and the begin / commit stuff is setup well as expected…
This is the current state of my finding and very soon I shall give up on this capabilities that I would like to use for my applications…
let me know what is your point of view or ideas to solve this issue that is really haunting me since I stared using ajax and thinkgeo MVC…
thanks in advance.
jm.
Hi Jm,
You mentioned using the events like “loadstart” and “loadend” which should be fine to set the Ajax call flag by them. But we should make the edit layer which is operated in the action is the same one with the events registered layer in client.
Also, I guess we can also try to lock the layer in the action before we operate the layer in the server side. Here I have created a sample for you including both of the two ways above.
During my test, I did find the exception which shows there is a conflict during the tile rendering and Ajax call in the action and this will bring the “exception” tile will not return to the client. I am not sure does this is exactly the same issue or behavior from you?
Would you please check the sample to see if it is works for you?
We are sorry about the synchronization issues from Mvc Edition haunting you and hope we can help you on it.
Regards,
Johnny
DisplayASimpleMapForMvc11672.zip (164 KB)
Hi Johnny,
Thanks! I shall try your samples this morning. However, I strongly believe that if we could use a lock on a server side that will simplify things a lot. For instance if the map library could expose let say a global lock for overlays then the server side customer code could sync on any action / request coming from the client. Moreover, the lock will provide a serialization process. I think also that if the code on a server side is using a lock then the internal thinkgeo code should not try to use overlays or layers until the lock has been released by the customer code.
Jm
And yes I think that when I get an exception on the server side it is because the one or more overlays are currently rendering tiles!
I think that Thinkgeo should provide a map status property on the server side that could be checked for tile rendering process active or not.
jm
Johnny I take a look at your sample and I think that there is an issue because you could miss an Ajax call… let say that the map has been pan then you call the server using ajax then in the mean time the map is pan again and in this case you will not issue a new Ajax call that should return the data points for the new extent and of course the user is not moving the map anymore… then when the first ajax call has been completed the new extent will not be refreshed… I think that one should use some kind of queuing process to queue all new extent changed messages and wait until the redraw on the client side has been completed…but then the next extent message in the queue has to wait until both server / client are quiet again… Now what if? if we have more than one layer to deal with…
you see this could become very complex to deal with and if we just could have on the client side and or server side a flag to test for let say : are we currently rendering tiles?
thanks.
jm
Hi Jm,
I guess I can feel your feeling. Locking the layer during the tile rendering in the server side is a simplest way to solve the issue directly, however, In Mvc Edition, rendering tiles is a multithread operation in IIS thread Pool and we should understand many tiles might would be requested at a very short time. Therefore, if we lock the layer which will be drawn, that would bring a very bad performance. Currently, we just lock the layer only in the open method and unlock it after the opening when the server handler a tile request, but can’t lock the drawing method for the above reasons.
For the sample, I send for you, yes, it might miss some Ajax calls if the extent changed events trigger quickly and your explains make sense. Actually, this sample includes two ways for this issue: one is using the “tileloadend” event to set the request flag which might cause the Ajax call missing, the other one is locking the layer in the action and I guess this would work. So, we can skip the method one and use the second one.
I want to do an explanation about how the issue happens if you are interesting in the details:
We can treat this issue like a reading and writing issue, for the tile request, we can think it is just a reading operation and the writing is for the Ajax call. Of cause, in general, the conflict shouldn’t happen when one is doing the reading and the other one is doing the writing. However, in the tile rendering(the reading), we will traverse all the features in a layer. So, there is a possible that we are inserting a feature into the features in the Ajax call(writing)during we traverse the features and this situation will throw out a “Collection was modified; enumeration operation may not execute.” Exception. Then, the current tile request will be failed. Hope the explanation is clear.
Hope it helps.
Regards,
Johnny
hi Johnny,
Thanks for your answer but I still do not see how to deal with updating the map when the extent is moving… I do clear the layer then I do insert new data points… And if you are not done with the previous tile rendering then crash … Now I don’t think that you have to lock the layer when you are rendering you should just post a lock that the customer code could check?.. Anyway this is an issue because when we have hundred thousands of data points noway to load all of them at once… I think that single tile rendering maybe could work…
I think also that you could duplicate or create a temporary layer that you should use just for rendering operation doing so could leave the customer layer free to be updated at any point in time without crashes?..
Thanks again
Jm
Hi Jm,
The second solution I mentioned before is we lock the layer when we insert the features(new data points) into the layer. Some codes like below:
lock (pointLayer)
{
pointLayer.Open();
Random random = new Random();
for (int i = 0; i < 1000; i++)
{
PointShape pointShape = new PointShape(currentExtent.LowerLeftPoint.X + random.NextDouble() * currentExtent.Width, currentExtent.LowerLeftPoint.Y + random.NextDouble() * currentExtent.Height);
pointLayer.InternalFeatures.Add(new Feature(pointShape));
}
}
Also, you mentioned the single tile, Yes, you are right, single tile would not encounter this issue and how can I forget this way! :(
So, You should get two solutions for this issue, would you please try them one by one?
As for the suggestions that duplicating or creating a temporary layer to render tiles, I am afraid it still be not fit for that as the temporary layer would occupy pretty much memory for each tiles or even we just create one temporary layer for every tiles, but there is no way to find out the last tile update the temporary layer. So, it still not works.
Hope it helps and thanks for your suggestions.
Regards,
Johnny