Alle berichten

Realtime webapps in .NET met SignalR

Stuur updates van je ASP.NET Core-server meteen naar elke verbonden browser. We bouwen stap voor stap een kleine realtime chatapp met SignalR.

Bijgewerkt op 1 november 20264 min lezen

Er zijn een paar manieren om een webpagina zichzelf te laten bijwerken. Je kunt een vernieuwknop toevoegen, of de server elke paar seconden pollen met setInterval en fetch. Pollen werkt, maar het verspilt requests en is nooit echt realtime: er zit altijd vertraging tot de volgende controle.

De betere optie is een WebSocket: een verbinding tussen browser en server die open blijft, zodat de server data naar de browser kan sturen op het moment dat er iets gebeurt, zonder dat de browser erom vraagt.

In .NET doe je dat het makkelijkst met SignalR. SignalR is onderdeel van ASP.NET Core en geeft je een eenvoudige API om vanuit je servercode methodes aan te roepen op verbonden clients (en omgekeerd). Het gebruikt WebSockets wanneer die beschikbaar zijn en valt automatisch terug op Server-Sent Events of long polling wanneer dat niet zo is.

Een realtime chat bouwen met SignalR

We bouwen een kleine chatapp waarin elk bericht meteen verschijnt bij iedereen die de pagina open heeft.

Maak in Visual Studio een nieuwe ASP.NET Core Web App (Model-View-Controller) met de naam ChatApp, of gebruik de CLI:

Shell
dotnet new mvc -n ChatApp

De SignalR-server zit al in ASP.NET Core, dus je hoeft geen NuGet-package te installeren.

Serverkant

Een hub is de klasse waarmee clients verbinden. Maak een map Hubs met een klasse ChatHub die overerft van Hub:

C#
using Microsoft.AspNetCore.SignalR;

namespace ChatApp.Hubs;

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        // Stuur een "ReceiveMessage"-event naar elke verbonden client
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Clients kunnen SendMessage aanroepen, en de hub stuurt het bericht door naar alle verbonden clients via het event ReceiveMessage.

Registreer daarna SignalR en de hub in Program.cs:

C#
using ChatApp.Hubs;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddSignalR(); // Voeg de SignalR-services toe

var app = builder.Build();

// ... de standaard middleware en routes uit de template ...

app.MapHub<ChatHub>("/chat"); // Clients verbinden met de hub op /chat

app.Run();

Clientkant

De browser heeft de SignalR-JavaScriptclient nodig. Klik in Visual Studio met de rechtermuisknop op het project en kies Add > Client-Side Library.... Kies de provider unpkg, zoek naar @microsoft/signalr, kies Choose specific files, selecteer dist/browser/signalr.js en signalr.min.js, en zet de doellocatie op wwwroot/js/signalr/.

Geen Visual Studio? De LibMan-CLI doet hetzelfde:

Shell
libman install @microsoft/signalr@latest -p unpkg -d wwwroot/js/signalr --files dist/browser/signalr.js --files dist/browser/signalr.min.js

Maak nu wwwroot/js/chat.js. Het verbindt met de hub, toont binnenkomende berichten en verstuurt nieuwe:

JavaScript
"use strict";

// Verbind met de hub op het pad /chat dat we in Program.cs gemapt hebben
const connection = new signalR.HubConnectionBuilder()
  .withUrl("/chat")
  .withAutomaticReconnect()
  .build();

const sendButton = document.getElementById("sendButton");
sendButton.disabled = true; // Wordt actief zodra we verbonden zijn

// Wordt uitgevoerd telkens de hub een "ReceiveMessage"-event stuurt
connection.on("ReceiveMessage", (user, message) => {
  const li = document.createElement("li");
  li.textContent = `${user} says: ${message}`; // textContent, zodat berichten geen HTML kunnen injecteren
  document.getElementById("messagesList").appendChild(li);
});

sendButton.addEventListener("click", async (event) => {
  event.preventDefault();
  const user = document.getElementById("userInput").value;
  const message = document.getElementById("messageInput").value;

  try {
    await connection.invoke("SendMessage", user, message);
  } catch (err) {
    console.error(err);
  }
});

async function start() {
  try {
    await connection.start();
    sendButton.disabled = false;
  } catch (err) {
    console.error(err);
    setTimeout(start, 5000); // Probeer opnieuw na 5 seconden
  }
}

start();

Enkele dingen om op te letten:

  • withAutomaticReconnect() verbindt vanzelf opnieuw wanneer de verbinding wegvalt, bijvoorbeeld wanneer de server herstart.
  • De verstuurknop blijft uitgeschakeld tot de verbinding open is, zodat je geen berichten in het niets verstuurt.
  • We gebruiken textContent in plaats van innerHTML, zodat niemand HTML of scripts kan injecteren via een chatbericht.

Vervang tot slot de inhoud van Views/Home/Index.cshtml door de chat-UI. Die gebruikt de Bootstrap 5-klassen die bij de template horen, en laadt de scripts alleen op deze pagina:

HTML
<div class="card">
  <div class="card-header">
    <h3>Chat</h3>
  </div>
  <div class="card-body">
    <!-- Binnenkomende berichten komen hier -->
    <ul id="messagesList"></ul>
  </div>
  <div class="card-footer">
    <div class="input-group">
      <input type="text" id="userInput" class="form-control" placeholder="Username" />
      <input type="text" id="messageInput" class="form-control" placeholder="Message" />
      <button id="sendButton" class="btn btn-primary">Send</button>
    </div>
  </div>
</div>

@section Scripts {
  <script src="~/js/signalr/dist/browser/signalr.min.js"></script>
  <script src="~/js/chat.js"></script>
}

Testen

Dat was het! Start de app met dotnet run (of F5) en open hem in twee browsertabbladen. Typ een bericht in het ene tabblad en het verschijnt meteen in allebei:

Hoe verder?

Clients.All is nog maar het begin. Een hub kan ook naar één verbinding sturen (Clients.Client(id)), naar iedereen behalve de verzender (Clients.Others), of naar benoemde groepen (Groups.AddToGroupAsync). Dat is ideaal voor chatrooms of meldingen per gebruiker. Zet [Authorize] op een hub om alleen aangemelde gebruikers toe te laten.

Conclusie

Je weet nu hoe SignalR werkt en hoe je updates realtime van je server naar de browser stuurt. Hetzelfde patroon werkt voor live dashboards, meldingen, multiplayergames en samen bewerken. Lees meer in de officiële SignalR-documentatie van Microsoft.

Veelgestelde vragen

Moet ik een NuGet-package installeren voor SignalR in ASP.NET Core?

Nee. De SignalR-server is onderdeel van het gedeelde ASP.NET Core-framework. Je voegt alleen de JavaScriptclient @microsoft/signalr toe aan de browserkant.

Wat gebeurt er als WebSockets niet beschikbaar zijn?

SignalR valt automatisch terug op Server-Sent Events of long polling, zodat dezelfde code blijft werken.

  • .NET
  • SignalR
  • JavaScript
  • ASP.NET Core

Knijp, scroll of tik twee keer om te zoomen. Sleep om te verplaatsen.