Skip to content

DHI.Services.GeoServer — Internal Guide

AKA GeoServer Core. This is the single place for cross-cutting behavior: connection strings & auth, templated query placeholders, time/CRS/bbox conventions, HTTP/client behavior, and shared troubleshooting. Module-specific usage lives in the leaf docs:


What this provider family gives you

  • MapSource — WMS image rendering → returns SkiaSharp.SKBitmap (for GIS.Maps).
  • FeatureCollectionRepository — WFS/GeoJSON → DHI.Services.GIS.FeatureCollection<string> (for GIS).
  • MapStyleRepository — GeoServer REST /rest/styles CRUD(ish).

Under the hood: HTTP Basic auth (optional), templated URL substitution, NetTopologySuite (GeoJSON) → DHI.Spatial conversion, and standard DHI.Services repository patterns.


Quick start (local GeoServer)

docker run -d -p 80:8080 docker.osgeo.org/geoserver:2.25.2
# UI at http://localhost/
# default creds from image are typically admin/geoserver (change in your env)

Publish one workspace + layer. In docs/code we’ll call:

  • workspace[group]
  • layer name[layer]

Connections & auth (shared)

All constructors support explicit args or a connection string.

Connection string schema

BaseUrl=<root geoserver url> ; Query=<templated query string> [;UserName=...;Password=...]
  • BaseUrl (e.g., http://localhost/geoserver/) — we .TrimEnd('/').
  • Query — a templated relative path & query. See Placeholders below.
  • UserName/Password — optional → sets Authorization: Basic ....

Parsing details

  • Values may contain = (we split on the first =).
  • Values must not contain ; (we split on ;).
  • FeatureCollectionRepository uses a parser that tolerates = inside Query.

Auth behavior (important)

  • MapSource and MapStyleRepository use a static HttpClient; setting Authorization affects all subsequent calls in-process. Do not mix different GeoServer credentials/hosts in the same process—use separate hosts/processes if needed.
  • FeatureCollectionRepository uses an instance HttpClient (you can inject one); no process-global header sharing.

Templated query placeholders (shared)

You control the right-hand side of the URL; the provider does string substitution:

Placeholder Replaced with…
[group] Workspace (GeoServer workspace name)
[layer] Layer/type name (without workspace prefix)
[crs] Target CRS string (e.g., EPSG:4326)
[width] [height] Bitmap size (used by WMS or templates that require size)
[boundingbox] xmin,ymin,xmax,ymax (no spaces)
[mapstyle] Style name (MapStyle.Name) for WMS styles= parameter

Time: When a DateTime is supplied, both MapSource and FeatureCollectionRepository append &time=yyyy-MM-ddThh:mm:ss.fffZ (note 12-hour hh).

If your GeoServer expects 24-hour HH, add a custom [time] token to your template and provide the correctly formatted value on your side (or adjust the provider code).


Shared geometry behavior (FeatureCollection side)

When converting GeoJSON → NTS → DHI.Spatial, we standardize to 2D:

  • Replace … Z/… ZM with the 2D type in WKT before conversion, e.g., POLYGON ZPOLYGON, MULTILINESTRING ZMMULTILINESTRING.
  • A defensive json.Replace("MULTILINESTRING Z", "MULTILINESTRING") is applied prior to NTS parsing.

CRS propagation: if GeoJSON includes "crs": { "properties": { "name": "EPSG:XXXX" }}, we assign that to every feature’s Geometry.CRS. RFC-7946 GeoJSON omits crs; in that case features have no CRS set — interpret coordinates in the CRS you requested.


Capability matrix (at a glance)

Area Type/Class Read Write Notes
Maps (WMS) MapSource Image rendering to SKBitmap; GetDateTimes not implemented; static HttpClient + Basic auth.
Features (WFS/JSON) FeatureCollectionRepository Main Get(id); GetIds() via /rest/layers; JSON→NTS→DHI; optional size tokens; instance client.
Styles (REST) MapStyleRepository Add (SLD string or zipped style), Update, Remove; Get/Contains/Count/GetAll/GetIds.

See module pages for per-module capability tables.


Testing tips (shared)

  • Prefer tiny, deterministic fixtures (e.g., a small polygon layer).
  • For CI dockerized GeoServer, use http://localhost/geoserver/ and seed fixed data.
  • Inject your own HttpClient into FeatureCollectionRepository for testing; MapSource/MapStyleRepository share a static client.

Troubleshooting (shared)

  • 401/403 — check Basic auth; beware static client headers bleeding between hosts.
  • Time ignored — your GeoServer may expect HH instead of hh; customize or adjust code.
  • Empty/odd results — ensure you’re calling WFS with outputFormat=application/json (features) vs WMS (images).
  • CRS missing — RFC-7946 GeoJSON omits crs; interpret coordinates in the CRS you requested.

API surface (cheat sheet)

  • MapSourceGetMap(...), GetMaps(...) (WMS) — no GetDateTimes.
  • FeatureCollectionRepositoryGet(id), GetIds() (WFS/JSON).
  • MapStyleRepositoryGet, Contains, Count, GetIds, GetAll, Add, Update, Remove (styles REST).