Skip to content

Blazor Identity with Global RenderMode #51476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
IamRewt opened this issue Oct 18, 2023 · 5 comments
Closed
1 task done

Blazor Identity with Global RenderMode #51476

IamRewt opened this issue Oct 18, 2023 · 5 comments
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved

Comments

@IamRewt
Copy link

IamRewt commented Oct 18, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Making a new Blazor WebApp in RC2, if you select individual accounts and Global Interactive server mode:

  1. The template does not automatically add @rendermode="RenderMode.InteractiveServer" to the App.razor Routes and Head Outlet components. This only occurs when using the new identity pages, when they are excluded, the rendermode is automatically added.

  2. When you manually add the global rendermode in, the identity pages begin giving Null Reference Exceptions in several locations. For example: visiting the Register Page throws a null reference exception in StatusMessage.razor @ line 28: private string? MessageFromCookie => HttpContext.Request.Cookies[IdentityRedirectManager.StatusCookieName];

Removing the global rendermode from the Routes component stops the exceptions, but then eliminates the needed functionality.

Expected Behavior

The expected behavior was to be able to use the Interactive Server Render Mode globally with the new razor identity pages.

Steps To Reproduce

  1. Create a new blazor web app in RC2.
  2. Select 'Individual Accounts' for Authentication Type.
  3. Select 'Server' for Interactivity Type.
  4. Select 'Global' for Interactivity Location.
  5. Add @rendermode="RenderMode.InteractiveServer" to the HeadOutlet and Routes components in /Components/App.razor.
  6. Run the application.
  7. Navigate to Register or Login pages.

Exceptions (if any)

System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=BlazorApp1
StackTrace:
at BlazorApp1.Components.Identity.StatusMessage.get_MessageFromCookie() in F:\BlazorApp1\BlazorApp1\Components\Identity\StatusMessage.razor:line 28

.NET Version

.NET8 RC2

Anything else?

No response

@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Oct 18, 2023
@Kumima
Copy link

Kumima commented Oct 19, 2023

This will be fixed in next GA version. If you enable the Global RenderMode as Server, the project template for now will make all the pages rendered as server, which means there will be no HttpContext. You can check issue #51134 to preview the change. The Account pages will be rendered static even if you enable the global rendermode. Account pages rely on SignInManager which needs the HttpContext, so they have to be rendered as Static.

@javiercn
Copy link
Member

@Kumima answer is correct here.

/cc @halter73

@javiercn javiercn added question ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. labels Oct 19, 2023
@ghost ghost added the Status: Resolved label Oct 19, 2023
@cactusoft
Copy link

Found the same issue, good to see it will be fixed in GA. I was having trouble figuring out a workaround.

@mabulla
Copy link

mabulla commented Dec 1, 2023

Found A workaround where you can leave everything on Interactive, but if you navigate to the /Account-Pages you switch to a Static or "null" Rendermode.

Just add or change those lines in your

App.razor

<HeadOutlet @rendermode="@RenderModeForPage" />

<Routes @rendermode="@RenderModeForPage" />

@code {

    private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account")
        ? null
        : InteractiveServer;
}

Sideeffect is that when you want to use your ThemeSwitcher or any other interactive component declared in your MainLayout.razor they wont work anymore, so its best to remove or comment out this Line from your

AccountLayout.razor

@layout OpenSmartInfo.Server.Components.Layout.MainLayout

so that only the content from your /Account-Pages gets rendered without the now noninteractive "interactive" components.

And to make it look a little prettier you can add some css in AccountLayout.razor in a style-tag like so:

<style>
    body {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 80%;
    margin: auto;
    height: 100vh;
    justify-content: center;}
</style>

to center everything.

In my /Account-Pages i then removed the "col"- and "row"-classes from the divs and added a cancel-button.
For reference my

Register.razor

<PageTitle>Register</PageTitle>

<h1>Register</h1>

<div>
    <div>
        <StatusMessage Message="@Message" />
        <EditForm Model="Input" asp-route-returnUrl="@ReturnUrl" method="post" OnValidSubmit="RegisterUser" FormName="register">
            <DataAnnotationsValidator />
            <h2>Create a new account.</h2>
            <hr />
            <ValidationSummary class="text-danger" role="alert" />
            <div class="form-floating mb-3">
                <InputText @bind-Value="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="[email protected]" />
                <label for="email">Email</label>
                <ValidationMessage For="() => Input.Email" class="text-danger" />
            </div>
            <div class="form-floating mb-3">
                <InputText type="password" @bind-Value="Input.Password" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
                <label for="password">Password</label>
                <ValidationMessage For="() => Input.Password" class="text-danger" />
            </div>
            <div class="form-floating mb-3">
                <InputText type="password" @bind-Value="Input.ConfirmPassword" class="form-control" autocomplete="new-password" aria-required="true" placeholder="password" />
                <label for="confirm-password">Confirm Password</label>
                <ValidationMessage For="() => Input.ConfirmPassword" class="text-danger" />
            </div>
            <button type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
            <button class="w-100 btn btn-lg btn-primary" onclick="window.history.go(-1); return false;">Cancel</button>
        </EditForm>
    </div>
    <div >
        <section>
            <br />
            <h3 style="text-align:center;">Use another service to register.</h3>
            <hr />
            <ExternalLoginPicker />
        </section>
    </div>
</div>

@Stonne
Copy link

Stonne commented Dec 16, 2023

thanks Mabulla you saved my day thumbs up!!.
However In App.razor I had to add : @Inject IHttpContextAccessor HttpContextAccessor
and in the code block : private HttpContext HttpContext => HttpContextAccessor.HttpContext;
before
private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/Account")
? null
: InteractiveServer;

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved
Projects
None yet
Development

No branches or pull requests

6 participants