10 Answers, 1 is accepted
By default Silverlight security system blocks cross-scheme requests. Actually, it is possible to use OpenStreet map tiles through the HTTPS, but using custom provider. There are a couple ways to do it:
1. You can host your own OpenStreet tile server which will return tiles using HTTPS protocol. In this case you will need to have whole bundle of the OS map images locally and then configure your web server to return this tiles using HTTPS. Then you should create custom map source and map provider which will use this tile server. With this approach you will not need to deal with the Silverlight security.
2. If you don't like to create your own tile server, then you have to take a deal with Silverlight security. The default OpenStreet map provider always uses the same protocol as major application use. So the first thing you have to do is to create the custom map tile source and tile provider which will always use HTTP protocol regardless of the protocol used. The second thing you have to do is to configure the Silverlight security to allow using the HTTP from the application which is run using HTTPS. You can find more information here:
http://msdn.microsoft.com/en-us/library/cc645032(v=vs.95).aspx
Kind regards,
Andrey Murzov
the Telerik team
http://www.telerik.com/community/forums/silverlight/map/2011-q1-custom-map-provider-example.aspx
as a starting point I tried to apply second solution.
My clientaccesspolicy.xml file:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="http://*"/>
<domain uri="https://*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
It doesn’t work. Can you post working example with the second solution or maybe you know what I am doing wrong?
I'm sorry for misleading you. After a detailed research into the problem of the using of the cross-schema (HTTPS-HTTP) call in Silverlight I found that cross-schema access is not allowed for image classes (MultiScaleImage is one of them). Since RadMap is based on the MultiScaleImage you can't show OpenStreet map tiles directly from the HTTPS Silverlight application. So the only way to show OpenStreet map tiles from the HTTPS-based Silverlight application is creation of your own tile server. This server can store OpenStreet tiles locally or be a proxy to the OpenStreet real server.
All the best,
Can you provide some help on getting started in developing a proxy tile server and custom provider that would be required to use RadMap using HTTPS with OpenStreetMap data?
It is quite simple to create tile server on localhost or another web server when you have images which can be identified by the zoom level and (x,y) position of the tile. All that you need to do is put your tiles in a separate directory in the C:\inetpub\wwwroot folder. So if you have the OpenStreet map tiles organized in a way similar to the structure on the OpenStreet servers (zoom\x_pos\y_pos.png) then you can create tile server on localhost in a couple of steps:
1. Create new folder like "os_images" in the "C:\inetpub\wwwroot" folder.
2. Copy whole structure of the OpenStreet images to this new folder.
Now you can create new map tile source and map provider which will access images from this folder:
/// <summary>
/// Tile source which read map tiles from the given URI.
/// </summary>
public
class
LocalhostTileSource : TiledMapSource
{
private
string
tileUriFormat;
/// <summary>
/// Initializes a new instance of the LocalhostTileSource class.
/// </summary>
/// <param name="tileUriFormat">Format string to access tiles on the localhost.</param>
public
LocalhostTileSource(
string
tileUriFormat)
:
base
(1, 20, 256, 256)
{
this
.tileUriFormat = tileUriFormat;
}
/// <summary>
/// Initialize provider.
/// </summary>
public
override
void
Initialize()
{
// Raise provider intialized event.
this
.RaiseIntializeCompleted();
}
/// <summary>
/// Gets the image URI.
/// </summary>
/// <param name="tileLevel">Tile level.</param>
/// <param name="tilePositionX">Tile X.</param>
/// <param name="tilePositionY">Tile Y.</param>
/// <returns>URI of image.</returns>
protected
override
Uri GetTile(
int
tileLevel,
int
tilePositionX,
int
tilePositionY)
{
int
zoomLevel = ConvertTileToZoomLevel(tileLevel);
string
url =
this
.tileUriFormat.Replace(
"{zoom}"
, zoomLevel.ToString(CultureInfo.InvariantCulture));
url = url.Replace(
"{x}"
, tilePositionX.ToString(CultureInfo.InvariantCulture));
url = url.Replace(
"{y}"
, tilePositionY.ToString(CultureInfo.InvariantCulture));
return
new
Uri(url);
}
}
/// <summary>
/// Map provider which read map tiles from the file system.
/// </summary>
public
class
LocalhostProvider : TiledProvider
{
/// <summary>
/// Initializes a new instance of the LocalhostProvider class.
/// </summary>
/// <param name="tileUriFormat">Format string to access tiles on the localhost.</param>
public
LocalhostProvider(
string
tileUriFormat)
:
base
()
{
LocalhostTileSource source =
new
LocalhostTileSource(tileUriFormat);
this
.MapSources.Add(source.UniqueId, source);
}
/// <summary>
/// Returns the SpatialReference for the map provider.
/// </summary>
public
override
ISpatialReference SpatialReference
{
get
{
return
new
MercatorProjection();
}
}
}
Now you can use new map provider in your application:
<
UserControl
x:Class
=
"LocalhostMapProvider.MainPage"
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable
=
"d"
d:DesignHeight
=
"300"
d:DesignWidth
=
"400"
>
<
Grid
x:Name
=
"LayoutRoot"
Background
=
"White"
>
<
telerik:RadMap
x:Name
=
"radMap"
Center
=
"48.95,2.3"
ZoomLevel
=
"13"
>
</
telerik:RadMap
>
</
Grid
>
</
UserControl
>
using
System;
using
System.Collections.Generic;
using
System.Windows;
using
System.Windows.Controls;
namespace
LocalhostMapProvider
{
public
partial
class
MainPage : UserControl
{
public
MainPage()
{
InitializeComponent();
this
.radMap.Provider =
new
LocalhostProvider(
"http://localhost/os_images/{zoom}/{x}/{y}.png"
);
}
}
}
The ConvertTileToZoomLevel method is inherited from TiledMapSource class so you need not bother about its implementation.
The proxy tile server can be created in the same way. In this case you should create in addition simple page on your web site which will get image requests from your application, transfer it to the OpenStreet server and then return response. The code for the custom tile provider will be the same.
All the best,
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
Second I saw that MapQuest open provider uses Openstreet and does not have data limits and does support HTTPS. All good, except when the query is run from within the app I never am able to get the map to load in HTTPS, only from HTTP.
The only change I have made to your code is this one line:
change this (from localhost):
this
.radMap.Provider =
new
LocalhostProvider(
"http://localhost/os_images/{zoom}/{x}/{y}.png"
);
to this (mapquest host):
this
.radMap.Provider
= new LocalhostProvider("https://otile1.mqcdn.com/tiles/1.0.0/osm/{zoom}/{x}/{y}.png");
The only way it will load the map is if both my app and the url above are both HTTP, but if you just navigate to the url directly with valid substitutions, HTTPS works fine and you see the requested tile.
Ideally I would like to be able to get both of these solutions working as many of our customers are not running the app with internet access so an offline solution is appealing for that case, but otherwise HTTPS is minimally required.
Thanks!
The cross-schema (HTTPS-HTTP or HTTP-HTTPS) call in Silverlight is not allowed for image classes (MultiScaleImage is one of them). You can find more information here:
http://msdn.microsoft.com/en-us/library/cc189008(v=vs.95).aspx
So when you use HTTPS to access MapQuest open provider you should be sure that your Silverlight application is running using HTTPS as well.
Greetings,
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
I was able to create an offline tile server running on my website, but only to zoom level 7, as the space requirements for the images get too large beyond this (over 500 TB for the full map).
At present, I am without a solution to retrieve the fully detailed map over SSL. Trying to setup and host our own tile server looks like a huge can of worms, so that would be a last resort.
Any suggestions on alternative options?
You can try to create your own tile server which will be a HTTPS proxy for the OpenStreet real server. I.e. your tile server will handle request sent via HTTPS from your Silverlight application and request tile from OpenStreet using HTTP. When tile is obtained your server will return it to the Silverlight application.
Regards,
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
I recently made a proxy server so I could get open street maps working with https Silverlight maps.
Here is how to do it:
make a webForms page, do not put anything in the markup. Just add this to the code behind.
then you can call the service with: https://server/mapImageProxy.aspx?zoom=12&x=4000&y=4000
use the documentation on how to build a custom map provider, and use your new proxy server URL instead of the open street maps one.
using
System;
using
System.Collections.Generic;
using
System.Drawing;
using
System.Drawing.Imaging;
using
System.IO;
using
System.Linq;
using
System.Net;
using
System.Security.Permissions;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
namespace
WCFServiceWebRole1.MapTileDownloader
{
public
partial
class
MapTileDownload : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
string
x = Context.Request.QueryString[
"x"
];
string
y = Context.Request.QueryString[
"y"
];
string
zoom = Context.Request.QueryString[
"zoom"
];
string
url = @
"http://Map Tile Server Of Your Choice/"
+ zoom +
"/"
+ x +
"/"
+ y +
".png"
;
WebRequest theRequest = WebRequest.Create(url);
WebResponse theResponse = theRequest.GetResponse();
Stream theStream = theResponse.GetResponseStream();
System.Drawing.Image theImage = System.Drawing.Image.FromStream(theStream);
MemoryStream stream =
new
MemoryStream();
Response.ContentType =
"image/jpeg"
;
theImage.Save(stream, ImageFormat.Png);
stream.Position = 0;
byte
[] imageArray = stream.ToArray();
Response.OutputStream.Write(imageArray, 0, imageArray.Length);
}
}
}