I have a simple dashboard application that I wrote in .NET 8.0 Blazor. There are various backend classes using timers to update parts of the page, it works as expected run through Visual Studio as a container, and standalone.
When deployed to an Azure Kubernetes cluster the page loads and shows the expected data, but the timers are not updating the page.
I can see from kubernetes logs that the timers are running, and I am not seeing exceptions.
When run locally I can see the expected SignalR negotiation, and messages exchanging in the browser network tab. I also see console messages in the browser:
[2024-08-11T22:46:43.501Z] Information: Normalizing '_blazor' to 'https://localhost:32782/_blazor'.blazor.web.js:1 [2024-08-11T22:46:43.543Z] Information: WebSocket connected to wss://localhost:32782/_blazor?id=uu8i0EXFbvgzUFqKBzgjug.When deployed to kubernetes I cannot see any network tab activity related to SignalR, nor do I see any console messages.
The application is based heavily on the Blazor Web App VS template, using InteractiveServer mode, aside from the template code to hook up Blazor there is an MS EntraID based auth.
I'm looking for any insight into why the client JS script is not attempting to connect to the _blazor SignalR hub.
.csproj:
<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>net8.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><LangVersion>latest</LangVersion><DockerDefaultTargetOS>Linux</DockerDefaultTargetOS></PropertyGroup><ItemGroup><PackageReference Include="Dapper" Version="2.1.35" /><PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.7" /><PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.7" NoWarn="NU1605" /><PackageReference Include="Microsoft.Identity.Web" Version="3.0.1" /><PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="3.0.1" /><PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" /><PackageReference Include="Npgsql" Version="8.0.3" /><PackageReference Include="Seq.Api" Version="2024.3.0" /></ItemGroup></Project>Abridged program.cs looks like this:
builder.Services .AddRazorComponents() .AddInteractiveServerComponents() .AddHubOptions(ho => { ho.EnableDetailedErrors = true; });builder.Services.Configure<ForwardedHeadersOptions>(options =>{ options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;});builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { builder.Configuration.Bind("AzureAd", options); options.Events = new OpenIdConnectEvents { OnRedirectToIdentityProvider = context => { context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http://", "https://"); return Task.CompletedTask; } }; }); ...var app = builder.Build();// Configure the HTTP request pipeline.if (!app.Environment.IsDevelopment()){ app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseHsts(); app.UseDeveloperExceptionPage();}app.UseForwardedHeaders();app.UseAuthentication();app.UseAuthorization();app.UseStaticFiles();app.UseAntiforgery();app.MapRazorComponents<App>() .AddInteractiveServerRenderMode();app.Run();Dockerfile looks like:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS baseUSER appWORKDIR /appEXPOSE 8080EXPOSE 8081FROM mcr.microsoft.com/dotnet/sdk:8.0 AS buildARG BUILD_CONFIGURATION=ReleaseWORKDIR /srcCOPY ["Dashboard/Dashboard.csproj", "Dashboard/"]RUN dotnet restore "./Dashboard/Dashboard.csproj"COPY . .WORKDIR "/src/Dashboard"RUN dotnet build "./Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/buildFROM build AS publishARG BUILD_CONFIGURATION=ReleaseRUN dotnet publish "./Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=falseFROM base AS finalWORKDIR /appCOPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "Dashboard.dll"]Ingress currently looks like this:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: systems-dashboard-ingress annotations: nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "affinity" nginx.ingress.kubernetes.io/session-cookie-expires: "14400" nginx.ingress.kubernetes.io/session-cookie-max-age: "14400" nginx.ingress.kubernetes.io/proxy-http-version: "1.1" labels: app.kubernetes.io/managed-by: Helmspec: ingressClassName: nginx tls: - hosts: - {mysite} rules: - host: {mysite} http: paths: - path: / pathType: Prefix backend: service: name: systems-dashboard port: number: 8080I have added ingress annotations per this MS article:https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/server?view=aspnetcore-8.0#kubernetes
and this SO article:How to correctly deploy a Blazor Server app on Kubernetes
I have put a breakpoint in the blazor.web.js source in the browser, and attempted to step through the issue. Function names are obfuscated so its rather hard to see what's going on.
I sent post request to https://{mysite}/_blazor/negotiate?negotiateVersion=1 and got back
{"negotiateVersion": 1,"connectionId": "DdFgDoSqHeNzcYb_byCMkA","connectionToken": "TL4xt2O-Z4xIFOIQvNG6YA","availableTransports": [ {"transport": "WebSockets","transferFormats": ["Text","Binary" ] }, {"transport": "ServerSentEvents","transferFormats": ["Text" ] }, {"transport": "LongPolling","transferFormats": ["Text","Binary" ] } ]}