blazoronclickblazor-server-side.net-9.0blazor-rendermode

Interactivity not working in Blazor Server .NET 9


I need some help. This is the first time I'm building a Blazor app and I've been trying to get an @onclick working on a button in my .NET 9 Blazor Server app and I just can't get it to work.

I've found countless of answers saying I need to set the render mode, which I hadn't but sadly that didn't help at all. I tried both setting it for the entire app in App.razor (<Routes @rendermode="InteractiveServer" />) and setting it in my page (@rendermode InteractiveServer).

I checked the program.cs and it does have the .AddInteractiveServerComponents() on both the AddRazorComponents() and the MapRazorComponents<App>() as it should be:

using BoatPlannerAI.Web.Components;
using Microsoft.Azure.Cosmos;
using System.Globalization;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var cosmosConfig = builder.Configuration.GetSection("CosmosDb");
var account = cosmosConfig["Account"];
var key = cosmosConfig["Key"];

var databaseName = cosmosConfig["DatabaseName"];

if (string.IsNullOrWhiteSpace(databaseName))
    throw new InvalidOperationException("CosmosDb:DatabaseName configuration is missing or empty.");

builder.Services.AddSingleton(s => new CosmosClient(account, key));
builder.Services.AddSingleton(_ => databaseName);

// Add localization services
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

var supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("nl") };
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("nl");
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseAntiforgery();
app.MapStaticAssets();

// Redirect root '/' to '/nl' on the server side
app.Use(async (context, next) =>
{
    if (context.Request.Path == "/")
    {
        context.Response.Redirect("/nl", permanent: false);
        return;
    }
    await next();
});

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode();

// Configure localization middleware
var locOptions = app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);

// Set culture based on first URL segment
app.Use(async (context, next) =>
{
    var path = context.Request.Path.Value;

    if (!string.IsNullOrEmpty(path))
    {
        var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);

        if (segments.Length > 0)
        {
            var lang = segments[0];
            var supported = new[] { "en", "nl" };

            if (supported.Contains(lang))
            {
                var culture = new CultureInfo(lang);
                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }
        }
    }

    await next();
});

app.Run();

I also checked my _Imports.razor, it is in the correct location and has all the using I'd expect:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using BoatPlannerAI.Web
@using BoatPlannerAI.Web.Components

As I said, I tried setting the render mode for the entire app using:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="@Assets["lib/bootstrap/dist/css/bootstrap.min.css"]" />
    <link rel="stylesheet" href="@Assets["app.css"]" />
    <ImportMap />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <Routes @rendermode="InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

And I also tried setting it in the page:

@page "/{lang}/buttontest"
@rendermode InteractiveServer

@using Microsoft.Extensions.Localization
@inject IStringLocalizer<ButtonTest> L

@code {
    [Parameter] public string? lang { get; set; }

    private int buttonClickedCount = 0;

    private void ButtonClicked()
    {
        Console.WriteLine("Button clicked");
        buttonClickedCount++;
    }
}

Test the button <button @onclick="ButtonClicked" >Click me</button>
<p>Button clicked: @buttonClickedCount</p>

But nothing works. This the onclick is never even triggered if you ask me.

What am I missing here? Any help would be greatly appreciated!

Thanks,
elloco


Solution

  • So I figured it out. Thank you @HenkHolterman for your suggestion in the comments, that led to me finding the issue.

    In my program.cs I had this line:

    `builder.Services.AddSingleton(_ => databaseName);`

    Turns out Blazor doesn't like it when you register strings as Singletons... I removed that line and it works fine now.

    Cursor thought it would be useful to register the DB name as a singleton so it could easily be used throughout the application. And I failed to catch that.