9.0 KiB
De SocketServer installeren als Windows-service
MijnBesluit.SocketServer.exe is twee dingen tegelijk, net als je in WinDev gewend bent:
- start Windows hem, dan draait de server;
- start jij hem, dan verschijnt een beheerschermpje.
Eén exe om uit te leveren dus, en geen los installatieprogramma.
Bouwen
D:\MijnBesluit VS\MijnBesluit\tools\SocketServer-publiceren.ps1
Dat levert D:\publish\mijnbesluit-socketserver.zip. Of met de hand:
dotnet publish src\MijnBesluit.SocketServer -c Release -r win-x64 --self-contained false -o D:\MijnBesluit VS\MijnBesluit\publish
Het project staat vast op x64; er komt dus geen 32-bits versie uit, ook niet op een machine
waar dat de standaard zou zijn. Wil je dat er op de doelmachine helemaal geen .NET geïnstalleerd
hoeft te zijn, gebruik dan --self-contained true; de map wordt dan een stuk groter maar draait
op zichzelf.
Op mijnbesluit.nl, naast de website
De SocketServer draait náást IIS op dezelfde machine en praat met dezelfde database. Drie dingen moeten daarbij kloppen, anders krijgt de app straks een lege of onleesbare kluis te zien.
1. Dezelfde geheimen. appsettings.json wijst met ExtraConfigFile naar
C:\MijnBesluitData\appsettings.secrets.json — precies het bestand dat de website al gebruikt.
Eén plek dus voor de databasegegevens en de SMTP-instellingen, en ze overleven een nieuwe
publicatie. Ontbreekt dat bestand, dan stopt de service meteen met een duidelijke melding in
plaats van een onbegrijpelijke "Access denied" van de database.
2. Hetzelfde sleutelbestand. Security:MasterKeyFile staat op
C:\MijnBesluitData\keys\masterkey.json, hetzelfde bestand als de website gebruikt. Met een
ánder sleutelbestand is geen enkel kluisitem te openen dat via de website is opgeslagen. Ook
Storage:Path moet dezelfde map zijn.
Het serviceaccount LocalSystem moet dat sleutelbestand kunnen lezen.
3. Een certificaat. Zonder certificaat luistert de server onversleuteld, en daar gaan wachtwoorden en pincodes overheen. Het certificaat van mijnbesluit.nl uit IIS is te hergebruiken:
De snelste weg is IIS vragen welk certificaat hij voor de site gebruikt:
Import-Module WebAdministration
Get-ChildItem IIS:\SslBindings | Select-Object IPAddress, Port, Host, Thumbprint, Store
Staat er geen regel met mijnbesluit.nl, dan gebruikt die site de regel met IP-adres
0.0.0.0 — dat is het certificaat voor alle sites zonder eigen regel.
Om te zien welke namen zo'n certificaat dekt:
Get-ChildItem Cert:\LocalMachine\WebHosting |
Select-Object Subject, @{n='Namen';e={$_.DnsNameList -join ', '}}, Thumbprint, NotAfter, HasPrivateKey
Zet de vingerafdruk in Socket:CertificateThumbprint. De server kijkt in de opslagen My én
WebHosting; die laatste is waar hostingpanelen en Let's Encrypt-tools hun certificaten
neerzetten. Spaties maken niet uit. Let op de
vervaldatum: wordt het certificaat vernieuwd, dan verandert de vingerafdruk en moet deze
instelling mee — een herstart van de service is dan nodig.
Poort 5200 open. In de firewall van de server:
New-NetFirewallRule -DisplayName "MijnBesluit SocketServer" -Direction Inbound `
-Protocol TCP -LocalPort 5200 -Action Allow
En bij je hoster, als daar nog een firewall voor staat. Controleer het daarna vanaf je eigen pc
met Test-NetConnection mijnbesluit.nl -Port 5200.
Installeren
- Klik met de rechtermuisknop op
MijnBesluit.SocketServer.exeen kies Als administrator uitvoeren. - Het schermpje verschijnt met de status Niet geïnstalleerd.
- Vul het poortnummer in (standaard 5200). Onder het veld zie je meteen of die poort vrij is.
- Klik op Install.
Wat er dan gebeurt:
- het poortnummer wordt in
appsettings.jsonnaast de exe gezet — dat bestand leest de service straks zelf; - de service wordt aangemaakt onder de naam
MijnBesluitSocket, met weergavenaam MijnBesluit SocketServer, opstarttype Automatisch en account LocalSystem; - Windows krijgt de opdracht de service zelf opnieuw te starten als hij onverwacht stopt: na 10 seconden, dan na 30, en daarna elke 2 minuten;
- de service wordt meteen gestart.
Verwijderen
Rechtermuisknop → Als administrator uitvoeren. Het schermpje laat nu Draait of Geïnstalleerd, gestopt zien, en de knop heet UnInstall. Er wordt eerst gevraagd of je het zeker weet; daarna wordt de service gestopt en verwijderd.
Zolang de service bestaat kun je de poort niet wijzigen — dat staat er ook bij. Wil je een andere poort: verwijderen, poort aanpassen, opnieuw installeren.
Zonder beheerdersrechten
Start je de exe gewoon met een dubbelklik, dan verschijnt hetzelfde schermpje, maar zijn de knoppen uitgeschakeld en staat er een knop Opnieuw starten als administrator. Die start dezelfde exe opnieuw met de UAC-vraag. Klik je die weg, dan gebeurt er niets.
Het programma vraagt dus niet uit zichzelf om rechten bij het starten: alleen als je iets wilt doen waarvoor ze nodig zijn.
Waar de service zijn spullen zoekt
Windows start een service met C:\Windows\System32 als werkmap. Alle relatieve paden in
appsettings.json worden daarom omgezet naar paden naast de exe:
| Instelling | Standaard | Wordt |
|---|---|---|
Security:MasterKeyFile |
keys/masterkey.json |
<publish-map>\keys\masterkey.json |
Storage:Path |
kluisbestanden |
<publish-map>\kluisbestanden |
Smtp:DropFolder |
mail-uitgaand |
<publish-map>\mail-uitgaand |
Zet je er een volledig pad neer (D:\MijnBesluit VS\MijnBesluit\keys\masterkey.json), dan wordt dat gebruikt
zoals het er staat. Voor het sleutelbestand is dat vaak handiger: dan overleeft het een nieuwe
publish.
Het serviceaccount LocalSystem moet het sleutelbestand kunnen lezen en in de map met kluisbestanden kunnen schrijven.
Hoe de server met verbindingen omgaat
-
Eén thread accepteert verbindingen en doet verder niets.
-
Elke verbinding krijgt zijn eigen thread, met een blokkerende leeslus. Die thread heet
MijnBesluit-verbinding-<nummer>, dus in een dump of in de debugger zie je meteen welke verbinding waar hangt. -
Elk binnengekomen verzoek krijgt een eigen thread. De leeslus gaat meteen door met lezen, dus een trage databaseactie houdt de volgende verzoeken van diezelfde app niet op. Per verbinding lopen er maximaal
Socket:MaxVerzoekenPerVerbindingtegelijk (standaard 8) en over de hele serverSocket:MaxVerzoekenTotaal(standaard 200); daarboven wordt er van die verbinding even niet gelezen, wat vanzelf tegendruk geeft.Bewust een echte thread en niet de threadpool: de afhandeling blokkeert op de database en op bestanden, en dat zou de pool uithongeren — die groeit maar langzaam, waardoor verzoeken alsnog achter elkaar zouden gaan lopen in plaats van naast elkaar. Een verzoekthread krijgt 512 kB stapelruimte (
Sockethoeft daar niets voor te weten; zieRequestThreadStackBytes). -
Het wegschrijven van antwoorden is geserialiseerd: er kunnen nooit twee antwoorden door elkaar over de lijn gaan. Antwoorden kunnen wél in een andere volgorde terugkomen dan de verzoeken binnenkwamen — de app koppelt ze op
requestId. -
Bij afsluiten wacht de server tot de lopende verzoeken van een verbinding klaar zijn, zodat er niet naar een al opgeruimde verbinding wordt geschreven.
Omdat elk verzoek op zijn eigen thread loopt, krijgt het ook zijn eigen databasecontext: een EF Core-context is niet bedoeld om door meerdere threads tegelijk gebruikt te worden.
Instellingen
"Socket": {
"Address": "0.0.0.0",
"Port": 5200,
"MaxVerbindingen": 500,
"MaxVerzoekenPerVerbinding": 8,
"MaxVerzoekenTotaal": 200,
"CertificateFile": "D:\\MijnBesluit\\certificaat.pfx",
"CertificatePassword": "...",
"CertificateThumbprint": ""
}
CertificateThumbprint pakt een certificaat uit de machine-certificaatopslag van Windows —
handig als je er al een hebt dat automatisch vernieuwd wordt. Spaties in de vingerafdruk maken
niet uit; die worden eruit gehaald.
Als er iets misgaat
-
Je wilt meekijken terwijl hij draait. Stop de service en start dezelfde exe zelf met
--service:net stop MijnBesluitSocket cd C:\MijnBesluitSocket MijnBesluit.SocketServer.exe --serviceEr verschijnt dan een venster met het logboek erin; daar komt ook langs waarom een verzoek misging (
Fout bij '<actie>': …). Afsluiten met Ctrl+C, en daarnanet start MijnBesluitSocketniet vergeten. Liever een bestand? Zet er> log.txt 2>&1achter; dan blijft het venster weg en vult dat bestand zich terwijl hij draait. -
De service start niet. Kijk in Logboeken → Windows-logboeken → Toepassing. De meest voorkomende oorzaak is dat de poort al bezet is; dat staat er dan letterlijk.
-
"De service is verwijderd maar Windows is er nog niet mee klaar." Er staat nog een venster Services open met de service geselecteerd. Sluit dat en probeer het over een halve minuut opnieuw.
-
Het schermpje zegt dat de poort bezet is. Met
netstat -ano | findstr :5200zie je welk proces erop luistert.