# Implement Custom Map Provider

If you need to consume a service which does not have a default provider, you can create a custom map provider and set it as the **Provider** property of the **RadMap** control.

## MapProviderBase

The **MapProviderBase** is the base class for all map providers. Two widely-used implementations of the class are the **TiledProvider** and **ImageProvider**.

* **TiledProvider** is a base class for map providers that show a map as a sequence of tiles (e.g. [OpenStreetMap](https://www.telerik.com/winui/documentation/controls/radmap/features/providers/providers#openstreet-maps).

* **ImageProvider** is a base class for providers that show a map as a single image ([UriImageProvider](https://www.telerik.com/winui/documentation/controls/radmap/features/providers/uriimageprovider)).

Once you know the type of provider you require, you can create a custom class to inherit from it. In most cases this will be the **TiledProvider** class. In addition, you need to override the **SpatialReference** property - it returns the actual projection used by the provider and most often returns an instance of the **MercatorProjection** class.

#### **Example 1: Create a custom TiledProvider**

```C#
public class MyMapProvider : TiledProvider
{
	/// <summary>
	/// Initializes a new instance of the MyMapProvider class.
	/// </summary>
	public MyMapProvider()
			: base()
	{
		MyMapSource source = new MyMapSource();
		this.MapSources.Add(source.UniqueId, source);
	}

	/// <summary>
	/// Returns the SpatialReference for the map provider.
	/// </summary>
	public override ISpatialReference SpatialReference
	{
		get
		{
			return new MercatorProjection();
		}
	}
}
```

> The **MyMapSource** class is defined in **Example 2**.

## MultiScaleTileSource

As seen in **Example 1**, the next requirement is to add instances of the abstract [MultiScaleTileSource](https://docs.telerik.com/devtools/WinUI/api/telerik.windows.controls.map.multiscaletilesource) class to the provider's **MapSources** collection. The class exposes two useful properties:

* **RequestCredentials**: Gets or sets credentials for downloading tiles.
* **WebHeaders**: Gets or sets the headers used in the get requests made to the tile servers via System.Net.WebClient. This property was introduced with **R2 2019 SP1**.

The two default implementations of this abstract class are the **TiledMapSource** and the **ImageMapSource**.

* **TiledMapSource** is a base class for map sources that return map tiles (that includes all OpensStreetMap sources: Mapnik and Osmarenderer).

* **ImageMapSource** is a base class for map sources that return a single map image.

When creating a custom map provider, you can choose one of these sources and override their methods depending on the specific map source type. Most implementations will require the following set of actions:

* Override the **Initialize** method.

* Override the **GetTile** method and existing custom logic should be moved here.

* Call the **RaiseInitializeCompleted** method when the respective custom provider is initialized (in case of simple providers it is enough to call this method from the override Initialize method).

**Example 2** demonstrates a possible implementation of a custom TiledMapSource.

#### **Example 2: Create a custom TiledMapSource**

```C#
public class MyMapSource : TiledMapSource
{
	   /// <summary>
	   /// Initializes a new instance of the MyMapSource class.
	   /// </summary>
	   public MyMapSource()
			 : base(1, 20, 256, 256)
	   {
	   }
	   
	   /// <summary>
	   /// Initialize provider.
	   /// </summary>
	   public override void Initialize()
	   {
			 // Raise provider initialized event.
			 this.RaiseInitializeCompleted();
	   }

	   /// <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);
			 // Prepare tile url somehow ...
			 string url = CustomHelper.GetTileUrl(tileLevel, tilePositionX, tilePositionY);
			 return new Uri(url);
	   }
}
```

## Create an OpenStreetProvider Which Uses Https

A common requirement when using the RadMap control is to use the OpenStreetMap service over **https**. **Examples 3-5** demonstrate how this can be achieved by creating a custom map provider.

#### **Example 3: Create a custom TiledProvider and set up its commands**

```C#
public class HttpsOpenStreetProvider : TiledProvider
{
	/// <summary>
	/// Initializes a new instance of the MyMapProvider class.
	/// </summary>
	public HttpsOpenStreetProvider()
		  : base()
	{
		OsmTileMapSource source = new HttpsOpenStreetMapnikSource();
		// required as the OSM service requires a non-stock User-Agent header
		source.WebHeaders.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0");
		this.MapSources.Add(source.UniqueId, source);

		this.SetupCommands();
	}

	/// <summary>
	/// Returns the SpatialReference for the map provider.
	/// </summary>
	public override ISpatialReference SpatialReference
	{
		get
		{
			return new MercatorProjection();
		}
	}

	private void SetupCommands()
	{
		this.CommandBindingCollection.Clear();

		string uriString = "/Telerik.Windows.Controls.DataVisualization;component/themes/road.png";

		this.RegisterSetSourceCommand(
			typeof(HttpsOpenStreetMapnikSource),
			LocalizationManager.GetString("MapOsmStandardCommand"),
			null,
			new Uri(uriString, UriKind.RelativeOrAbsolute),
			null,
			null);
	}
}
```

#### **Example 4: Create a custom OsmTileMapSource which uses an https url**

```C#
public class HttpsOpenStreetMapnikSource : OsmTileMapSource
{
	public HttpsOpenStreetMapnikSource() : base(@"https://{prefix}.tile.openstreetmap.org/{zoom}/{x}/{y}.png")
	{
	}
}
```

#### **Example 5: Set the provider via RadMap's Provider property**

```C#
this.map.Provider = new HttpsOpenStreetProvider();
```

## See Also

* [OpenStreetMap](https://www.telerik.com/winui/documentation/controls/radmap/features/providers/providers)#openstreet-maps)
* [UriImageProvider](https://www.telerik.com/winui/documentation/controls/radmap/features/providers/uriimageprovider)
