TechBash 2026 Presentation Links
Spatial Data in .NET and Real-Time Data Visualization in Blazor
Thanks for coming to my TechBash 2026 sessions!
Kalahari Resorts, Pocono Manor, Pennsylvania · October 13 to 16, 2026
Both demos are set in northeastern Pennsylvania, not far from the conference.
Everything from both sessions is on this page: the full slide decks, the sample applications, files you can download, and the reading list I promised from the stage. The slides open right in your browser. Use the arrow keys or Space to move through them, T for a thumbnail rail, and F for full screen.
Wednesday, October 14 · 1:30 PM · Rosewood · Data track
Spatial Data in .NET: From Database to Dashboard
A field-service dispatch board for a fictional company around Scranton answers one question: which service territory covers this customer, and which available technician assigned there is closest? The answer comes out of SQL Server geography columns through EF Core and NetTopologySuite, a Minimal API, and GeoJSON, with GeoBlazor drawing the map. My claim for the hour was that spatial is just a data type, and it composes with ordinary business data and ordinary LINQ.
Thursday, October 15 · 11:30 AM · Sagewood
Real-Time Data Visualization in Blazor
A Blazor WebAssembly dispatcher dashboard tracks a simulated delivery fleet around the Poconos, using GeoBlazor Core for the map. The goal is live telemetry without drowning the browser in redraws: keep only the latest report per vehicle, hand the map one batch per cadence tick, and give every visual its own clock. All of the vehicle data is simulated, so the sample runs anywhere with no live feed behind it.
Running the Samples
Both applications live in the dymaptic/GeoBlazor-Samples repository, and each project's README.md has the full setup. A few things worth knowing before you clone:
- SpatialDispatch needs Docker for the SQL Server container (
docker compose up -dfrom the project folder), thendotnet run --project SpatialDispatch. Startup applies the migration and seeds the demo records, so there's no manual database work. The map uses GeoBlazor Pro, so it needs a Pro license key inappsettings.Development.json. Without one, the dispatch answer, the candidate list, and assignment all still work, because the spatial work happens in SQL Server, not in the map. - FleetDashboard runs on a free GeoBlazor registration key. Its preview controls and the
?mode=URL parameter let you switch between the pipeline stages from the talk without rebuilding.
Spatial Data Downloads
These are the artifacts behind the query and indexing slides.
generated-spatial-queries.sql: the SQL that EF Core emits for the two dispatch queries, "which territory contains this job?" and "who is the closest available technician?"territories.geojson: the two demo service territories. Paste it into geojson.io to see them.- Execution plans, which open as graphical plans in SQL Server Management Studio:
ranking-clustered-scan.sqlplanandranking-spatial-seek.sqlplan: sorting by distance alone scans every row, while adding a distance filter to theWHEREclause lets the optimizer seek on the spatial index.containment-clustered-scan.sqlplanandcontainment-spatial-seek.sqlplan: the same comparison for the containment query.
capture-execution-plan.ps1: rebuilds those plans yourself. It creates a throwawaySpatialDispatchPlandatabase with 200,000 technicians and 40,000 territories on the sample's SQL Server container, captures all four plans, and fails if a seek plan loses its spatial index. The row counts are hardcoded in its setup SQL, so edit them to match your own data before you trust the 45.3 km distance bound from the slides.
Spatial Data Resources
Packages
NetTopologySuite: the geometry library, withPoint,LineString,Polygon, and the spatial predicates.Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite: SQL Server spatial support for EF Core.Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite: PostGIS support for EF Core.NetTopologySuite.IO.GeoJSON4STJ: GeoJSON serialization withSystem.Text.Json.NetTopologySuite.IO.GeoJSON: GeoJSON withNewtonsoft.Json, if you're still there.ProjNet: coordinate system transformations and reprojection.NetTopologySuite.IO.Esri.Shapefile: reading and writing shapefiles. It replaces the older, now deprecatedNetTopologySuite.IO.ShapeFile.
Documentation
- EF Core spatial data is the single best starting point. It covers both providers, the geometry hierarchy, and which methods translate to SQL. Open it before you trust any translation.
- SQL Server spatial data is the reference for the
geometryandgeographytypes and their methods. - SQL Server spatial indexes explains grid tessellation, the clustered primary key prerequisite, and
GEOGRAPHY_AUTO_GRID. - NetTopologySuite API docs for method-level reference.
- The PostGIS manual has a deeper function library than SQL Server's. It's worth reading even if you're on SQL Server, because the concepts are named the same way.
- RFC 7946 (GeoJSON) is short, readable, and settles arguments about coordinate order. Longitude comes first!
If You're on PostgreSQL
- Npgsql's NetTopologySuite mapping is the page behind the provider comparison slide:
UseNpgsql(connectionString, o => o.UseNetTopologySuite()), the translation table (NTSContainstoST_Contains,DistancetoST_Distance), and the trap that NTS types map to PostGISgeometryby default. Opt intogeographyper property with[Column(TypeName = "geography")]when you want distances in meters on the spheroid. - PostGIS
geographycovers whengeographybeatsgeometryand what it costs. - PostGIS GiST indexes replace SQL Server's grid tessellation, and they're a plain
CREATE INDEX ... USING GIST (geom)with no hand-edited migration. - KNN nearest neighbor answers "closest" with the
<->operator (EF.Functions.DistanceKnnfrom the provider), which is a different mechanism from SQL Server'sORDER BYplus a distance filter.
If Someone Already Publishes the Data
- ArcGIS Location Platform has a free tier for geocoding, routing, and hosted feature layers. The demo uses its routing service to compare drive time against straight-line distance.
- A published feature layer is data your app reads over and over (boundaries, technician locations). Geocoding and routing are one-off calls per request. They have different cost models and different ways to fail.
- GeoBlazor is the Blazor component library drawing the dashboard map. The open-source Core package covers
MapView,GeoJSONLayer,GraphicsLayer, and events, and Pro adds things like theSketchwidget for drawing and editing territory boundaries. Disclosure: it's my library, built at dymaptic.
Where to Get Spatial Data
- US Census TIGER/Line has states, counties, tracts, block groups, roads, and ZIP Code Tabulation Areas. It's authoritative and free.
- Census Cartographic Boundary files are generalized versions of the same shapes, with much smaller payloads. Use these for web maps.
- Natural Earth is public domain country, state, and coastline data at three levels of detail, and my default for world maps.
- OpenStreetMap has everything, through Geofabrik's regional extracts or Overpass Turbo for targeted queries. Check the ODbL attribution terms.
- State GIS portals publish parcels, roads, and administrative boundaries. The demo's home state has PASDA, and mine has the Iowa Geospatial Data Clearinghouse.
- data.gov and city open data portals have municipal boundaries, service districts, and incident data.
- ArcGIS Living Atlas is a large curated collection. Some layers are open, and some need an ArcGIS account.
Almost everything above ships as a shapefile. ogr2ogr from GDAL is the tool that gets it into SQL Server or PostGIS, and it handles reprojection on the way in.
Geocoding
- US Census Geocoder is free, needs no API key, and handles US addresses only. It's the fastest way to test an address-to-point pipeline without a contract.
- Nominatim is free and global, but the public instance has a strict usage policy (one request per second, no bulk jobs). Run your own instance for anything serious.
- ArcGIS geocoding is commercial and credit-based, on the same platform the demo uses for routing.
Whichever one you pick, store the result as geography with SRID 4326 and longitude first, and keep the geocoder's confidence score. A rooftop match and an interpolated match are not the same promise.
Tools
- QGIS is a free desktop GIS, and the fastest way to look at spatial data before writing any code, or to sanity check what's actually in your table.
- GDAL handles format conversion and reprojection, and it's available as a container if you don't want it installed.
- The spatial results tab in SQL Server Management Studio is built in and surprisingly useful for "did my insert do what I think?" pgAdmin has a geometry viewer that does the same for PostGIS.
- geojson.io lets you paste GeoJSON and see it on a map, which is great for debugging API output.
- epsg.io looks up any SRID, with its units and area of use.
Testing Spatial Code
This wasn't in the talk, but it's worth writing down.
- Anything that's pure NetTopologySuite is unit testable without a database: geometry construction,
Contains,Intersects,Distance,Buffer, and validity checks. Build geometries from Well-Known Text in your fixtures.new WKTReader().Read("POLYGON((...))")is far more readable in a test than coordinate arrays. - Anything that depends on the database's spatial engine is not. SQL Server's
geographydistance and NTS'sDistance()don't compute the same number, because one is ellipsoidal and the other is planar, so an assertion that passes in memory can fail against the database. - So integration test the queries, against a containerized SQL Server or PostGIS from Testcontainers for .NET, seeded with a small known fixture. Test that the query translates and returns the right rows, because that's the part that actually breaks.
- Assert with a tolerance. Compare distances within a range, and choose
EqualsTopologicallyorEqualsExactdeliberately. - If a query calls an NTS method with no SQL translation, EF Core throws at runtime, not compile time. An integration test is the only thing that catches that before a user does.
- Fixture geometries worth having: a simple square, two overlapping squares, a polygon with a hole, a self-intersecting invalid polygon, and a point exactly on a boundary edge. The last two find the most bugs.
Front-End Map Libraries
- GeoBlazor wraps the ArcGIS Maps SDK for JavaScript in Blazor components. Again, mine, so weigh that accordingly.
- Leaflet is small and stable, with an enormous plugin ecosystem, and the easiest JavaScript interop story from Blazor.
- MapLibre GL JS renders vector tiles with WebGL, and it's the best-looking option for large datasets.
- OpenLayers is the heaviest and most capable, with strong projection support if you're not in 4326.
- ArcGIS Maps SDK for JavaScript is what GeoBlazor wraps, if you'd rather use it directly.
All of them consume GeoJSON, so the serialization work from the talk isn't tied to any one library.
Exercises
These extend something from the talk, easiest first.
- Break the happy path. Seed a customer outside every territory, one inside two territories, and one exactly on a shared border. Compare
Contains,Intersects,Covers, andCoveredByfor all three, on bothgeographyandgeometry. The border case is where they disagree, and the two storage types can disagree with each other too. - Port the demo to PostGIS. Swap
UseSqlServerforUseNpgsql, opt the columns intogeography, and re-run the containment and ranking queries. Check the generated SQL and the distance units before trusting it. - Run the index investigation at your scale. Use
capture-execution-plan.ps1after editing its row counts to match your data. Note when the seek appears and how tight the distance bound has to be to keep it. - Publish and consume. Push the demo territories to a hosted feature layer, then point a GeoBlazor layer (or plain
fetchplus GeoJSON) at it. Note what changes about authentication. - Sketch a territory. Add a GeoBlazor Pro
Sketchwidget that draws a boundary and posts the ring back to your API as Well-Known Text. Check the vertex order before storing it, because SQL Server reads a reversed ring as the whole globe minus your shape. - Geocode an address end to end. Use the Census Geocoder for a US address, store the point, and run the dispatch query against it. Log the match confidence.
- Find the gaps and overlaps.
Unionthe territory polygons, thenDifferencethat against a county or state boundary to find uncovered ground, andIntersectionpairs of territories to find double-covered ground. Decide which results are data errors and which are policy. - Rank by drive time, not distance. Request routes for the three closest eligible technicians and order by travel time instead of
STDistance. The nearest technician isn't always the fastest, and each route is a per-request cost the distance query doesn't have. - Reproject before GeoJSON. Store or compute a projected geometry (Web Mercator, SRID 3857, for example), then reproject to 4326 before emitting RFC 7946 output. Confirm the map still lines up, and compare the distances in each form.
- Use spatial types with Dapper. Run one containment query through Dapper instead of EF Core. The reader still needs the NetTopologySuite plugin registered on the connection to turn a
geographycolumn into aPolygon. - Diagnose an untranslatable expression. Write a query that calls an NTS method EF Core can't translate, watch it throw at runtime, and rewrite it into a shape the provider does translate.
Worth an Hour of Reading
- Coordinate reference systems. Why 4326 isn't a projection, why 3857 distorts area at high latitudes, and why your distances came out in degrees.
- Spatial indexing. R-trees (PostGIS GiST) and SQL Server's grid tessellation are different mechanisms with the same goal: cheaply rule out candidates before doing exact math.
- Topological validity. Self-intersections and unclosed rings produce predicate results that look like bugs in your code.
IsValidandBuffer(0)are the usual first aid. - Geometry simplification. Douglas-Peucker and its topology-preserving variants are necessary for any web map with real boundary data.
- Payload size. The real cloud cost surprise with spatial data is egress on unsimplified geometry, not compute.
Real-Time Data Visualization Resources
- The FleetDashboard sample has every pipeline stage from the talk, selectable by URL.
- Use ASP.NET Core SignalR with Blazor is the tutorial to start from for pushing data to a Blazor client.
- The SignalR .NET client covers connections, automatic reconnect, and streaming from the client side.
PeriodicTimeris the frame clock on the server side of the sample, from the "Send the latest when you're ready" slide.- Blazor render modes explains the WebAssembly and Interactive Server choice from the hosting slide and the appendix.
- ArcGIS Living Atlas is where to look for streams someone else hosts, like weather and traffic feeds.
- GeoBlazor documentation and the live GeoBlazor samples for everything else on the map side.
Get in Touch
If you try either sample on your own data, I'd love to hear how it goes. Ping me on Mastodon at @TimPurdum@dotnet.social, or email me at tim.purdum@dymaptic.com if you get stuck!
Interactive ArcGIS maps for your Blazor applications, with an open-source core.
Tim Purdum