Skip to content

DHI.Services.GeoServer for GIS Maps — Internal Developer Guide (WMS → SKBitmap)

Audience: devs using DHI.Services.GIS.Maps with GeoServer (WMS). For placeholders/auth/time/CRS details, see GeoServer Core.


What this provider gives you

  • MapSource — calls GeoServer WMS and decodes the image into an SKBitmap.
  • MapStyleRepository — manages styles via GeoServer REST /rest/styles.

The package also ships the GIS features repo; see the GIS doc for vectors.


Capabilities & limitations

Operation / Area Support Notes
MapSource.GetMap Renders a single WMS image.
MapSource.GetMaps Batch by Dictionary<DateTime,string>; CRS read from parameters["crs"] (default EPSG:4326).
MapSource.GetDateTimes Not implemented.
Styles: Get/Contains/… Backed by REST /rest/styles.
Styles: Add Either StyleFile=.zip (application/zip) or StyleCode (SLD application/vnd.ogc.sld+xml).
Styles: Update/Remove PUT/DELETE to REST endpoints.
Auth Basic Auth; static HttpClient with global Authorization header.
Time Appended as &time=yyyy-MM-ddThh:mm:ss.fffZ (12-hour hh).
Tokens [group], [layer], [width], [height], [boundingbox], [crs] (added if missing), [mapstyle].

Name vs Id (styles): WMS inserts MapStyle.Name into [mapstyle]. Keep Name equal to the GeoServer style you want.


Your WMS query template (tokens)

Example (WMS 1.1.0 – srs):

[group]/wms?service=WMS&version=1.1.0&request=GetMap
&format=image/png
&layers=[group]:[layer]
&bbox=[boundingbox]
&width=[width]&height=[height]
&srs=[crs]   // or &crs=[crs] for WMS 1.3.0
&styles=[mapstyle]

Axis order and srs vs crs depend on your WMS version. Keep template consistent with your server.


Using via the Core MapService

Single render

var mapSvc = new DHI.Services.GIS.Maps.MapService(mapSource, styleSvc /* optional */);

var bbox = BoundingBox.Parse("8,54,13,58");
using var bmp = mapSvc.GetMap(
  style: "coast-sld",                         // Id if style repo plugged in; else treated as StyleCode
  crs: "EPSG:4326",
  boundingBox: bbox,
  width: 1024, height: 768,
  sourceId: "myWorkspace",                    // → [group]
  dateTime: null,
  item: "coastline",                          // → [layer]
  parameters: DHI.Services.Parameters.Empty);

Time stack (batch)

var timeSteps = new Dictionary<DateTime, string> {
  [new DateTime(2020,10,21,10,0,0, DateTimeKind.Utc)] = "coastline",
  [new DateTime(2020,10,21,11,0,0, DateTimeKind.Utc)] = "coastline"
};

var frames = mapSvc.GetMaps(
  style: "coast-sld",
  boundingBox: bbox,
  size: new SKSizeI(1024, 768),
  timeSteps: timeSteps,
  item: "myWorkspace",                                    // In this provider, this 'item' arg maps to [group]
  parameters: new Parameters { { "crs", "EPSG:4326" } }); // GetMaps reads CRS from parameters

Parameter mapping (watch this): GetMap: sourceId → [group], item → [layer]. GetMaps: the dictionary value is [layer], and the final item argument is used as [group].


Wiring

A) Connections (WebApi hosts)

"geo-map": {
  "$type": "DHI.Services.GIS.WebApi.MapServiceConnection, DHI.Services.GIS.WebApi",
  "MapSourceConnectionString": "BaseUrl=http://localhost:8080/geoserver/;Query=[group]/wms?service=WMS&version=1.1.0&request=GetMap&format=image/png&layers=[group]:[layer]&bbox=[boundingbox]&width=[width]&height=[height]&srs=[crs];UserName=admin;Password=geoserver",
  "MapSourceType": "DHI.Services.Provider.GeoServer.MapSource, DHI.Services.Provider.GeoServer",
  "MapStyleConnectionString": "BaseUrl=http://localhost:8080/geoserver/;UserName=admin;Password=geoserver",
  "MapStyleRepositoryType": "DHI.Services.Provider.GeoServer.MapStyleRepository, DHI.Services.Provider.GeoServer",
  "Name": "GeoServer WMS",
  "Id": "geo-map"
}

After startup, an example request:

GET /api/maps?request=GetMap&service=wms&version=1.3.0
  &width=1024&height=768
  &styles=coast-sld
  &layers=geo-map
  &crs=EPSG:4326
  &bbox=8,54,13,58
  &item=coastline

B) Programmatic

var styleSvc = new DHI.Services.GIS.Maps.MapStyleService(
  new DHI.Services.Provider.GeoServer.MapStyleRepository(
    baseUrl: "https://my.geoserver/geoserver/", userName: "admin", password: "geoserver"));

var query =
  "[group]/wms?service=WMS&version=1.1.0&request=GetMap&format=image/png" +
  "&layers=[group]:[layer]&bbox=[boundingbox]&width=[width]&height=[height]&srs=[crs]&styles=[mapstyle]";

var mapSource = new DHI.Services.Provider.GeoServer.MapSource(
  baseUrl: "https://my.geoserver/geoserver/",
  query:   query,
  userName: "admin", password: "geoserver");

ServiceLocator.Register(new DHI.Services.GIS.Maps.MapService(mapSource, styleSvc), "geo-map");

Managing styles

// Add via SLD string
styleSvc.Add(new MapStyle("coast-sld", "Coastline (SLD)") {
  StyleCode = File.ReadAllText(@"C:\styles\coastline.sld")
});

// Or via zipped style package
styleSvc.Add(new MapStyle("rain", "Rain SLD") {
  StyleFile = @"C:\styles\rain.zip" // must be .zip
});

// Get / Contains / Count / Update / Remove
var ok  = styleSvc.Contains("coast-sld");
var one = styleSvc.Get("coast-sld");        // Maybe<MapStyle>
var cnt = styleSvc.Count();
styleSvc.Update(new MapStyle("coast-sld", "Coastline (updated)") { StyleCode = "<new sld xml>" });
styleSvc.Remove("coast-sld");

Notes (matching code)

  • MapStyleRepository.Get(id) calls /rest/styles/{id}.json (i.e., {id}.json). Remove/Update target /rest/styles/{id} (no .json).
  • Add requires either StyleFile (.zip) or StyleCode (SLD). If both empty, it throws.

Troubleshooting

  • Blank/gray image — check axis order vs WMS version and srs/crs name; ensure layer is visible at that scale.
  • Style not applied — WMS uses MapStyle.Name; make sure it matches the GeoServer style name exactly.
  • CRS ignored in batchGetMaps reads CRS from parameters["crs"].
  • Time not honored — confirm layer supports &time= and your server accepts hh (12-hour).

Design notes (under the hood)

  • MapSource builds the query via string replacement; if [crs] is absent, it appends &crs=<value>.
  • On DateTime, appends &time=yyyy-MM-ddThh:mm:ss.fffZ (12-hour).
  • Static HttpClient with global Authorization. Avoid mixing hosts/creds.

Copy-paste snippets

Minimal map endpoint (ASP.NET Core)

[HttpGet("map")]
public IActionResult GetMap([FromQuery] double xmin, double ymin, double xmax, double ymax)
{
    var src = new MapSource(
        "http://localhost/geoserver/",
        "[group]/wms?service=WMS&version=1.1.0&request=GetMap&format=image/png&layers=[group]:[layer]&bbox=[boundingbox]&width=[width]&height=[height]&srs=[crs]",
        "admin", "geoserver");

    var bmp = src.GetMap(
        new MapStyle("default","default"), "EPSG:4326",
        new BoundingBox(xmin,ymin,xmax,ymax), 800, 400,
        "topp", null, "states", Parameters.Empty);

    using var image = bmp.Encode(SKEncodedImageFormat.Png, 90);
    return File(image.ToArray(), "image/png");
}

Final navigation

  • Core: placeholders, auth, time/CRS, shared behavior → GeoServer Core
  • GIS (features/WFS): this page
  • GIS.Maps (raster/WMS): the Maps page above