Provide OpenStreetmap Implementation with User-Agent

1044
4
01-21-2020 09:41 PM
ScottBrady2
New Contributor

Hi,

Referring to the following post. OpenStreetMap as Basemap in WPF with ArcGis 

I currently have this problem occurring.

I am currently on the 10.2.7 version of the .NET SDK and migrating to 100.7 at the moment is not an option.

The solution mentioned in this article was to subclass the TiledLayer class  and override the GetFileDataAsync() method in order to inject a user-agent string into the web request. I can see no way to do this with within this function. Does anyone have any sample code illustrating how to do this.

Kind Regards

Scott Brady.

0 Kudos
4 Replies
dotMorten_esri
Esri Notable Contributor

The issue is addressed in the 100.x releases.

The 10.2.x release is no longer supported, and will not be seeing any updates, patches or hotfixes.

0 Kudos
ScottBrady2
New Contributor

From a business perspective, unfortunately migration to the 100 series while on the horizon, is not currently an option. We will continue to investigate workarounds and provide a resolution to this forum such that it may be of use to anybody else with a similar problem, resulting from the change in the implementation of the openstreetmap api as I am sure we are not the only people dealing with this issue at the moment.

0 Kudos
dotMorten_esri
Esri Notable Contributor

As mentioned in the other thread, I believe your only option then is to build your own OpenStreetMap layer that downloads the tiles with a user agent.

0 Kudos
dotMorten_esri
Esri Notable Contributor

Here's a quick and dirty implementation that should work:

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Layers;

namespace WpfApp5
{
    public class OpenStreetMapLayer2 : TiledLayer, ICopyright
    {
        private const double WebMercatorCorner = 20037508.3427892;
        private const string UserAgentName = "ArcGISRuntime-NET";
        private const string UserAgentVersion = "10.2";
        private static readonly string[] SubDomains = { "a", "b", "c" };
        private static readonly TiledLayerInitializationInfo tileInfo;
        private static readonly HttpClient client;

        static OpenStreetMapLayer2()
        {
            var envelope = new Envelope(-WebMercatorCorner, -WebMercatorCorner, WebMercatorCorner, WebMercatorCorner, SpatialReferences.WebMercator);
            double scale = 156543.03392804062;
            double resolution = scale * 96.0 * 39.37;
            Lod[] lods = new Lod[19];
            for (int i = 0; i < lods.Length; i++)
            {
                lods[i] = new Lod(scale, resolution);
                scale /= 2.0;
                resolution /= 2.0;
            }
            tileInfo = new TiledLayerInitializationInfo(256, 256, -WebMercatorCorner, WebMercatorCorner, envelope, 96, lods);
            client = new HttpClient(new WebRequestHandler()
            {
                AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate,
                CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.Default)
            });
            client.DefaultRequestHeaders.UserAgent.Add(new System.Net.Http.Headers.ProductInfoHeaderValue(UserAgentName, UserAgentVersion));
        }

        string ICopyright.CopyrightText => "Map data © OpenStreetMap contributors, CC-BY-SA";


        protected override Task<TiledLayerInitializationInfo> OnInitializeTiledLayerRequestedAsync() => Task.FromResult(tileInfo);

        protected override async Task<ImageTileData> GetTileDataAsync(int level, int row, int column, CancellationToken cancellationToken)
        {
            using (var response = await client.GetAsync(CreateUri(level, row, column), cancellationToken).ConfigureAwait(false))
            {
                using (var content = response.EnsureSuccessStatusCode().Content)
                {
                    return new ImageTileData() { Column = column, Row = row, Level = level, ImageData = await content.ReadAsByteArrayAsync().ConfigureAwait(false) };
                }
            }
        }

        private static string CreateUri(int level, int row, int column)
        {
            string subdomain = SubDomains[(level + column + row) % SubDomains.Length];
            return $"http://{subdomain}.tile.openstreetmap.org/{level}/{column}/{row}.png";
        }
    }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos