From 2acf54e1a908c40f573c44476d26f00d54fb808a Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Wed, 13 May 2026 20:20:06 -0400 Subject: [PATCH] Fix kiosk SignalR: skip WebSocket transport, add hubs/Kiosk to subscription bypass 1. kiosk-welcome.js: force SSE|LongPolling transport on the kiosk hub. Azure App Service's ingress proxy cancels anonymous WebSocket handshakes before the SignalR protocol exchange completes. SSE and long polling work fine for the low-frequency StartIntake push this hub needs. 2. SubscriptionMiddleware: add /hubs/ and /Kiosk/ to SkipPaths so a subscription redirect can never fire on a hub or kiosk request and abort the connection mid-handshake. Co-Authored-By: Claude Sonnet 4.6 --- src/PowderCoating.Web/Middleware/SubscriptionMiddleware.cs | 2 ++ src/PowderCoating.Web/wwwroot/js/kiosk-welcome.js | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/PowderCoating.Web/Middleware/SubscriptionMiddleware.cs b/src/PowderCoating.Web/Middleware/SubscriptionMiddleware.cs index 86009f0..2dc1a19 100644 --- a/src/PowderCoating.Web/Middleware/SubscriptionMiddleware.cs +++ b/src/PowderCoating.Web/Middleware/SubscriptionMiddleware.cs @@ -47,6 +47,8 @@ public class SubscriptionMiddleware "/Billing", "/api/", "/stripe/", + "/hubs/", + "/Kiosk/", "/Profile/Photo", "/CompanyLogo", "/AccountDataExport" diff --git a/src/PowderCoating.Web/wwwroot/js/kiosk-welcome.js b/src/PowderCoating.Web/wwwroot/js/kiosk-welcome.js index e249e91..e2a2cee 100644 --- a/src/PowderCoating.Web/wwwroot/js/kiosk-welcome.js +++ b/src/PowderCoating.Web/wwwroot/js/kiosk-welcome.js @@ -21,8 +21,13 @@ setStatus("#94a3b8", "Connecting…"); + // Skip WebSocket — anonymous WebSocket upgrades are blocked by the Azure App Service + // ingress proxy before the SignalR handshake completes. Server-Sent Events and + // long polling work fine for the low-frequency "StartIntake" push this hub needs. const connection = new signalR.HubConnectionBuilder() - .withUrl(`/hubs/kiosk?companyId=${companyId}`) + .withUrl(`/hubs/kiosk?companyId=${companyId}`, { + transport: signalR.HttpTransportType.ServerSentEvents | signalR.HttpTransportType.LongPolling + }) .withAutomaticReconnect([2000, 5000, 10000, 30000]) .configureLogging(signalR.LogLevel.Information) .build();