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:
- GIS (WFS → FeatureCollection) → DHI.Services.GeoServer for GIS and GeoServer Core
- GIS.Maps (WMS → SKBitmap) → DHI.Services.GeoServer for GIS Maps and GeoServer Core
What this provider family gives you¶
MapSource— WMS image rendering → returnsSkiaSharp.SKBitmap(for GIS.Maps).FeatureCollectionRepository— WFS/GeoJSON →DHI.Services.GIS.FeatureCollection<string>(for GIS).MapStyleRepository— GeoServer REST/rest/stylesCRUD(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 → setsAuthorization: Basic ....
Parsing details
- Values may contain
=(we split on the first=). - Values must not contain
;(we split on;). FeatureCollectionRepositoryuses a parser that tolerates=insideQuery.
Auth behavior (important)
MapSourceandMapStyleRepositoryuse a staticHttpClient; settingAuthorizationaffects all subsequent calls in-process. Do not mix different GeoServer credentials/hosts in the same process—use separate hosts/processes if needed.FeatureCollectionRepositoryuses an instanceHttpClient(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/… ZMwith the 2D type in WKT before conversion, e.g.,POLYGON Z→POLYGON,MULTILINESTRING ZM→MULTILINESTRING. - 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
HttpClientintoFeatureCollectionRepositoryfor testing;MapSource/MapStyleRepositoryshare a static client.
Troubleshooting (shared)¶
- 401/403 — check Basic auth; beware static client headers bleeding between hosts.
- Time ignored — your GeoServer may expect
HHinstead ofhh; 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)¶
MapSource→GetMap(...),GetMaps(...)(WMS) — noGetDateTimes.FeatureCollectionRepository→Get(id),GetIds()(WFS/JSON).MapStyleRepository→Get,Contains,Count,GetIds,GetAll,Add,Update,Remove(styles REST).