| name | shiny-blazor-hosting |
| description | Generate and configure Shiny Blazor Hosting for .NET - IAppSupport for Blazor WebAssembly providing app version, browser user-agent, screen/viewport dimensions, and live culture/time-zone change events via synchronous JS interop |
| auto_invoke | true |
| triggers | ["Shiny.Extensions.BlazorHosting","IAppSupport","AddAppSupport","UserAgent","UserAgentVersion","BrowserWidth","BrowserHeight","ScreenWidth","ScreenHeight","CultureChanged","TimeZoneChanged","shiny-appsupport.js"] |
Shiny Blazor Hosting Skill
You are an expert in Shiny Extensions Blazor Hosting, a .NET library that provides an IAppSupport service for Blazor WebAssembly apps: app version, browser user-agent, screen/viewport dimensions, and live culture / time-zone change events.
It is the browser-side sibling of Shiny.Extensions.MauiHosting's IAppSupport. The two interfaces share a name and namespace (Shiny) but expose different members — pick the one matching the host. This skill is for the Blazor WebAssembly variant.
When to Use This Skill
Invoke this skill when the user wants to:
- Read app/browser/device info in a Blazor WebAssembly app (
AppVersion, UserAgent, screen/viewport sizes)
- React to culture or time-zone changes in the browser via
IAppSupport
- Wire up
Shiny.Extensions.BlazorHosting
Library Overview
Documentation: https://shinylib.net/blazorhost/
Repository: https://github.com/shinyorg/extensions
Package: Shiny.Extensions.BlazorHosting
Namespace: Shiny
Host: Blazor WebAssembly only (uses IJSInProcessRuntime for synchronous browser reads)
IAppSupport Interface
public interface IAppSupport
{
Version AppVersion { get; }
string? UserAgent { get; }
Version? UserAgentVersion { get; }
int ScreenWidth { get; }
int ScreenHeight { get; }
int BrowserWidth { get; }
int BrowserHeight { get; }
CultureInfo CurrentCulture { get; }
event EventHandler<CultureInfo>? CultureChanged;
TimeZoneInfo CurrentTimeZone { get; }
event EventHandler<TimeZoneInfo>? TimeZoneChanged;
}
| Member | Source | Notes |
|---|
AppVersion | Registration argument | Pass a compile-time constant (ThisAssembly.AssemblyVersion) — never reflected off the entry assembly |
UserAgent | navigator.userAgent | Read once and cached (fixed for the page's lifetime) |
UserAgentVersion | Parsed from UserAgent | Best-effort browser version, tokens tried Edge → Opera → Firefox → Chrome → Safari; null if none parse |
ScreenWidth / ScreenHeight | window.screen.* | Physical screen size |
BrowserWidth / BrowserHeight | window.innerWidth/innerHeight | Viewport size — read live on each access, so reflects resizes |
CurrentCulture + CultureChanged | CultureInfo.CurrentCulture | 30-second poller raises the event on change |
CurrentTimeZone + TimeZoneChanged | TimeZoneInfo.Local | 30-second poller raises the event on change |
The change-detection events use lazy subscription: the poll timer starts when the first handler attaches and stops when the last detaches.
Setup
-
Install the NuGet package Shiny.Extensions.BlazorHosting.
-
Reference the bundled JS in wwwroot/index.html, before blazor.webassembly.js. It attaches window.shinyAppSupport so reads can run synchronously through IJSInProcessRuntime:
<script src="_content/Shiny.Extensions.BlazorHosting/shiny-appsupport.js"></script>
-
Register in Program.cs, passing the head app's version constant (no reflection):
using Shiny;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddAppSupport(ThisAssembly.AssemblyVersion);
AddAppSupport is idempotent (TryAddSingleton), so it's safe to call from libraries.
Usage
@inject IAppSupport App
@code {
protected override void OnInitialized()
{
var version = App.AppVersion;
var browser = App.UserAgentVersion;
var (w, h) = (App.BrowserWidth, App.BrowserHeight);
App.CultureChanged += (s, c) => InvokeAsync(StateHasChanged);
App.TimeZoneChanged += (s, tz) => InvokeAsync(StateHasChanged);
}
}
API Summary
public static class BlazorHostingExtensions
{
public static IServiceCollection AddAppSupport(this IServiceCollection services, Version appVersion);
public static IServiceCollection AddAppSupport(this IServiceCollection services, string appVersion);
}
Code Generation Instructions
- Always emit the
<script src="_content/Shiny.Extensions.BlazorHosting/shiny-appsupport.js"> tag in index.html before blazor.webassembly.js; the service throws on first JS call if it's missing.
- Pass
ThisAssembly.AssemblyVersion (or another compile-time constant) to AddAppSupport — do not reflect the entry assembly version.
- This is WebAssembly-only. For Blazor Server (no
IJSInProcessRuntime), the synchronous property reads won't work — don't suggest it there.
- For MAUI apps, use
Shiny.Extensions.MauiHosting's IAppSupport instead (different members: orientation, device manufacturer/model, browser/map launch).
- Detach
CultureChanged / TimeZoneChanged handlers on Dispose so the poll timer stops.
Best Practices
- Read viewport dimensions on demand —
BrowserWidth/BrowserHeight reflect the live window, so read them when needed rather than caching.
- Marshal event handlers to the UI —
CultureChanged / TimeZoneChanged may fire off the render context; wrap UI updates in InvokeAsync(StateHasChanged).
- Treat
UserAgentVersion as best-effort — UA strings are unreliable; handle null and don't gate critical logic on an exact browser version.