ThinkGeo.com    |     Documentation    |     Premium Support

Google map failure in v10

Hi,

Google map layer fails in v10, but works in v9.

at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, Object[] args)
at ThinkGeo.MapSuite.Portable.PclSystem.<>c__182.<Register>b__18_0(IPclSystem s, Object[] args) at fSQ=.lCQ=.<>c__DisplayClass2_0.<.ctor>b__0(IPclSystem ioc, Object[] args) at fSQ=.iiQ=.kyQ=(IPclSystem ioc, Object[] args, Boolean createNew) at fSQ=.lCQ=.lyQ=(IPclSystem ioc, Object[] args, Boolean createNew) at ThinkGeo.MapSuite.Portable.PclSystem.Resolve[T](Boolean createNew, String label, Object[] args) at ThinkGeo.MapSuite.Portable.PclSystem.Resolve[T](String label, Object[] args) at ThinkGeo.MapSuite.Portable.PclSystem.get_GeoRasterProjectionWrapper() at ThinkGeo.MapSuite.Shapes.Proj4Projection.ConvertToExternalProjectionCore(GeoImage image, RectangleShape imageExtent) at ThinkGeo.MapSuite.Shapes.Projection.ConvertToExternalProjection(GeoImage image, RectangleShape imageExtent) at ThinkGeo.MapSuite.Layers.GoogleMapsLayer.IDY=(GeoCanvas canvas) at ThinkGeo.MapSuite.Layers.GoogleMapsLayer.DrawCore(GeoCanvas canvas, Collection1 labelsInAllLayers)
at ThinkGeo.MapSuite.Layers.Layer.ciU=(GeoCanvas canvas, Collection1 labelsInAllLayers) at ThinkGeo.MapSuite.Layers.Layer.Draw(GeoCanvas canvas, Collection1 labelsInAllLayers)
at ThinkGeo.MapSuite.WinForms.LayerOverlay.DrawCore(GeoCanvas canvas)
at ThinkGeo.MapSuite.WinForms.Overlay.YlM=(GeoCanvas canvas)
at ThinkGeo.MapSuite.WinForms.Overlay.Draw(GeoCanvas canvas)
at ThinkGeo.MapSuite.WinForms.WinformsMap.G1M=(IEnumerable`1 drawingOverlays, RectangleShape extent)
at ThinkGeo.MapSuite.WinForms.WinformsMap.GlM=(RectangleShape drawingExtent, RectangleShape extent)
at ThinkGeo.MapSuite.WinForms.WinformsMap.OVM=(RectangleShape extent)
at ThinkGeo.MapSuite.WinForms.WinformsMap.gRU=(Int32 delayInterval, RectangleShape extent)
at ThinkGeo.MapSuite.WinForms.WinformsMap.Refresh()
at GoogleMapOverlay_v9.Form1.btnAdd_Click(Object sender, EventArgs e) in c:\Users\damian\OneDrive - acteq.net\Visual Studio Projects\Projects\GoogleMapOverlay_v10\GoogleMapOverlay_v9\Form1.cs:line 95
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at GoogleMapOverlay_v9.Program.Main() in c:\Users\damian\OneDrive - acteq.net\Visual Studio Projects\Projects\GoogleMapOverlay_v10\GoogleMapOverlay_v9\Program.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

See attached test project.

Regards,
Damian

GoogleMapOverlay_v10.zip (372.4 KB)

Hi Damian,

Thanks to let us know your question. Could you please let us know whether you type in your clientid and private key for test, because when we used them it works.

For the GoogleMapsLayer the client id and private key is necessary for now.

Regards,

Ethan

Hi Ethan,

I have heard of this client id/key pair before, but when I search for it on google, all I get back is information about embedding on web pages, ios, android, etc. Nothing for WinForms distribution.

Can you point me to what I need to do to sign-up to get a client id/key pair and indicate what service I actually need to be able to distribute my WinForms app with this feature enabled for my users?

Thanks,
Damian

Hi Damian,

For our GoogleMapsLayer, the license should be for Google Maps Static API.

Wish that’s helpful.

Regards,

Ethan

Hi Ethan,

That helped and I signed up successfully, but I’ve now got a few more issues.

  1. When I add the layer to the map and refresh, it made 35 calls (with tiny coordinate variations) to google just to display the image. This was with no mouse movements at all. Each subsequent zoom/pan makes about 10 calls. Can this be controlled? I don’t want to get killed on billing.

  2. The second time I ran the program, I got the following error at map refresh: {“failed to load NAD27-83 correction file”}. This makes no sense to me because the projection is converting from spherical mercator to WGS84 utm. I have isolated this to occur only when selecting the GoogleMapsMapType to Terrain and it is intermittent.

  3. How does the tile cache feature work? I notice that if you don’t specify the directory in the constructor that you can’t set it later on. I did set this directory in the constructor, and it created some data, but what exactly is it doing and how do I benefit from it as there are still web requests being generated. At some point does the cache take over?

  4. After half a dozen trial runs, I now get this error and can’t get any more maps: {“The remote server returned an error: (403) Forbidden.”}. I thought that once I had an API key in place that this wasn’t supposed to happen any more. This initially happened right after specifying the tile cache directory, so maybe it’s related.

  5. This 403 error occurs at map refresh, so I am wondering how can I trap it and prevent the program from totally crashing. Not only that, but how can we refresh the rest of the map if google doesn’t respond. Putting a try/catch block around every refresh statement isn’t a viable option. And I don’t see how I can just remove the layer every time there is an issue with the connection. I really need a solution for this as the WMS layer has the same potential for problem.

Regards,
Damian

Hi Damian,

  1. Set bigger size of tile or use single tile mode should solved it, you can find the tile size limitation in GoogleMap’s page.

  2. I hand’t met this exception before, it looks it’s related with projection, please make sure whether you assign projection to your GoogleMap, and possible provide us a sample or some sample code for reproduce it.

  3. We suggest you assign tile cache on LayerOverlay level, and it should works only for multiply tile mode.

  4. The “The remote server returned an error: (403) Forbidden.” is a network exception from remote server, you can view the sent request by SendingRequst event, or in “NetWork” tab of browser f12, or in 3rd part utility for example fiddler. And you can try to visit the link directly in browser to see whether it’s from remote server, you can also view your Google map page to see whether you touch some limitation.

  5. Try to set DrawingExceptionMode to draw instead of throw in Overlay level and Layer level.

Wish that’s helpful.

Regards,

Ethan

Ethan,

I need some clarifications on what you’ve suggested and a sample project. Remember, there are absolutely no samples for working with tiled images on the wiki and also no help on these layer features… And I would really like to take advantage of the speed a tile cache can provide.

  1. Instructions please and a sample project. I see no tile size property. Right now, the returned requests show the size is 256x256 and Google says I can request size 640x640 on free tier. Also, there is TileCache and ProjectedTileCache. What’s the difference and how do I deal with both?

  2. You already have the sample… It was in the first email. Only difference is adding the private key and fiddling with the tile cache path in the constructor.

  3. Instructions please and a sample project. Keep in mind that the constructor asks for a directory. I need to know the significance of this (and why you can’t set it outside the constructor). What other settings must I manage?

  4. I’ve been running the test some more today, and so far have no errors. But, I look at my google api dashboard and I see no requests have been made. How can that be? There’s one other thing I forgot to mention. Even with my private key in place, the returned map image still has that annoying google black bar across the images rather than the logo in the bottom right. Are you sure that my key is being used properly to submit the request? This may also explain the errors as that was what was happening before i put the key in.

  5. Okay, that get’s me part way. I think what I would rather do is handle DrawingException by making the offending layer invisible so the rest of the map will render. How do I raise a DrawingExceptionError to test since I don’t see one.

Regards,
Damian

Hi Damian,

  1. You can set the tile size like this:

    GoogleMapsLayer lyr = new GoogleMapsLayer();
         lyr.TileWidth = 640;
         lyr.TileHeight = 640;
    

You can just ignore the projectedTileCache, set it equal null and just use TileCache.

  1. I hadn’t reproduce your exception in your sample project, so if you found any more information to reproduce it please let us know.

  2. In fact I am not sure the reason of this API design, but please just assign a tile cache folder for it.

  3. If you hadn’t found the request is sent, that means the image comes from cache. For the black bar, it looks that’s the declare from Google, remove or cover it is not allowed. Increase the tile size it helpful.

  4. Try to close network when the map is loading for test.

Regards,

Ethan

Hi Ethan,

  1. Got it. Missed that one totally.

  2. Okay.

  3. Okay.

  4. Okay. Confirm that with cache enabled, the web requests aren’t made when going to a previous zoom.

  5. I am having no luck trapping web request errors. I have tried handling SentWebRequest, DrawingException, and DrawnException events and they are never fired with network off. See below screenshot. Also, I note that setting DrawingExceptionMode to either ThrowException or DrawException has no effect and I still get the unhandled error from HttpWebRequest with network off. Also note that SentWebRequest only fires after request is successfully returned so if network is down you always get error. This is my biggest issue with implementing this feature. I need a reliable way to notify user and carry on without the layer being enabled on the map.

Regards,
Damian

Hi Damian,

Please try to set the DrawingExceptionMode also in the LayerOverlay which include your layer.

I guess maybe the exception is catch by the overlay level.

Regards,

Ethan

Ethan,

You need to test this and tell me what the answer is. “I guess you should do this” is not how you respond to clients…

It’s bad enough that we are on completely opposite time zones and I have to wait a day for your less than helpful response to this particular case. I chose Mapsuite 7 years ago in part because it was a company that is supposed to be based in Frisco Texas where I am near by and I expected good support for my maintenance dollars and not “I guess”…

Make a test, try it and see what needs to be done to make it work.

Regards,
Damian

Hi Damian,

I apologize for my words to make you feel bad.

We hadn’t test it is because we don’t have a valid Google license for test this month, but it looks for the exception problem we don’t need a valid key.

So if you set it like this:

            LayerOverlay lo = new LayerOverlay();
        lo.DrawingExceptionMode = DrawingExceptionMode.DrawException;

And you will get the exception drawn on map instead of be thrown.

Wish that’s helpful.

Regards,

Ethan

Hi Ethan,

We are making some progress here. Thanks.

There are two issues though:

  1. In my implementation the GoogleMapLayer is in the same layer overlay as the boundary and when you enable drawing exception on the layer overlay, both layers disappear and are replaced with the red x. My implementation requires all the layers to be in the same layer overlay because I allow the user to control the zorder of layers. If the Google is in it’s own layer overlay, I don’t have full control of zorder.

  2. There is no DrawingException event in LayerOverlay, so I still can’t do anything to tell the user what may be the problem. I really think it best that the developers make it work so that drawing exception mode and the associated events work from the layer level (since they are there…).

Regards,
Damian

Hi Damian,

  1. For legal reason, we will stop to use multiply tile mode for GoogleMapLayer (static API), so it only can be the single tile mode in future. We will double check whether the drawing exception works in layer level, it don’t works because multiply mode before.

  2. You can override the function in GoogleMapLayer, and then handle it like this:
    public class MyGoogleMapsLayer : GoogleMapsLayer
    {
    protected override void DrawExceptionCore(GeoCanvas canvas, Exception e)
    {
    base.DrawExceptionCore(canvas, e);
    }
    }

Wish that’s helpful.

Regards,

Ethan

Hi Damian,

As below is a sample class for you, which can draw exception on map and show message-box when exception is catch.

Here is the class:

using System;
using System.Collections.ObjectModel;
using ThinkGeo.MapSuite.Drawing;
using ThinkGeo.MapSuite.Layers;
using ThinkGeo.MapSuite.Styles;

namespace GoogleMapOverlay_v9
{
class CustomGoogleMapsLayer : GoogleMapsLayer
{
    protected override void DrawCore(GeoCanvas canvas, Collection<SimpleCandidate> labelsInAllLayers)
    {
        try
        {
            base.DrawCore(canvas, labelsInAllLayers);
        }
        catch (Exception e)
        {
            switch (DrawingExceptionMode)
            {
                case DrawingExceptionMode.DrawException:
                    DrawException(canvas, e);
                    break;
                case DrawingExceptionMode.ThrowException:
                default:
                    throw e;
            }
        }
    }

    protected void DrawException(GeoCanvas canvas, Exception e)
    {
        bool cancel = false;
        DrawingExceptionLayerEventArgs drawingExceptionLayerEventArgs = new DrawingExceptionLayerEventArgs(canvas, e, cancel);
        OnDrawingException(drawingExceptionLayerEventArgs);

        if (!drawingExceptionLayerEventArgs.Cancel)
            DrawExceptionCore(canvas, e);

        DrawnExceptionLayerEventArgs drawnExceptionLayerEventArgs = new DrawnExceptionLayerEventArgs(canvas, e);
        OnDrawnException(drawnExceptionLayerEventArgs);
    }

    protected override void DrawExceptionCore(GeoCanvas canvas, Exception e)
    {

        GeoFont warterMarkFont = new GeoFont("Arial", 9);

        canvas.DrawTextWithScreenCoordinate(e.Message.ToString(), warterMarkFont, new GeoSolidBrush(GeoColor.FromArgb(255, 0, 0, 0)), canvas.Width / 2, canvas.Height / 2, DrawingLevel.LabelLevel);
        canvas.Flush();
    }
}
}

And here is how to use it:

CustomGoogleMapsLayer lyr = new CustomGoogleMapsLayer();
        lyr.DrawingException += Lyr_DrawingException;



 private void Lyr_DrawingException(object sender, DrawingExceptionLayerEventArgs e)
    {
        MessageBox.Show(e.Exception.Message);
    }

Wish that’s helpful.

Regards,

Ethan