kaarq
kaarq

Reputation: 3

Problem with rendering Blazor in InteractiveServer mode

I've got a Blazor 8.0 app. I used the default Blazor template with identity logging. When I use <Routes @rendermode="InteractiveServer"/> logging page and few others located in specific directories start blinking and have infinite refresh loop, but some other pages work just fine.

This is my program.cs:

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using BlazorApp1.Components;
using BlazorApp1.Components.Account;
using BlazorApp1.Data;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();

builder.Services.AddAuthentication(options =>
    {
        options.DefaultScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    })
    .AddIdentityCookies();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ??
                       throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddSignInManager()
    .AddDefaultTokenProviders();

builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();

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

// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();

app.Run();

And App.razor:

<!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="bootstrap/bootstrap.min.css"/>
    <link rel="stylesheet" href="app.css"/>
    <link rel="stylesheet" href="BlazorApp1.styles.css"/>
    <link rel="icon" type="image/png" href="favicon.png"/>
    <HeadOutlet/>
</head>

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

</html>

I reduced the blinking page to @page "/Account/Login" and layout to

@inherits LayoutComponentBase

@Body

What is wrong?

Upvotes: 0

Views: 570

Answers (2)

Razvan Cristian
Razvan Cristian

Reputation: 1

Implement the needed identity pages(ui) like login, register, etc with radzen and use identity endpoints not the identity razor pages so like a spa. In this way, I think , you will have a fresh HttpContext (that identity framework can use) when you will make a http req from the radzen pages locally to your identity endpoints. In the end the main goal for auth is to get cookie/token to your client side

secure a Web API backend for SPA

Upvotes: 0

Qiang Fu
Qiang Fu

Reputation: 8811

When set to InterActiveServer, page will be render twice.
1st: prerender(SSR), HttpContext is available. So HttpContext.SignInAsync works.
2nd: pure InterActive, HttpContext is not available.

Apparently, identity pages needs HttpContext to signin, signout etc. So you have to set the rendermode to null (null represent only prerender).The template should have below code wthich meant to null(SSR) mode to identity pages which route path start with "/Account".

<Routes @rendermode="RenderModeForPage" />
...
private IComponentRenderMode? RenderModeForPage => 
        HttpContext.Request.Path.StartsWithSegments("/Account")
            ? null
            : InterActiveServer;

Upvotes: 0

Related Questions