HttpContext возвращает значение null на странице входа в Blazor

На прошлой неделе я работал над проектом .net 8 своего веб-приложения blazor, и все работало нормально. Теперь я вернулся и больше не могу войти. Моя страница входа выдает ошибку.

Логин.razor:

@page "/Account/Login"
@layout EmptyLayout
@attribute [AllowAnonymous]

@using System.ComponentModel.DataAnnotations
@using AVAZicht.Components.Layout
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@using AVAZicht.Data

@inject SignInManager<ApplicationUser> SignInManager
@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager
@inject IdentityRedirectManager RedirectManager

<PageTitle>Log in</PageTitle>

<div class = "container">
    <div class = "row justify-content-md-center align-items-center vh-100">
        <div class = "col-lg-4" align = "center">

            <img src = "images/ava_logo_transp.png" class = "w-75 mb-3" />

            <section class = "p-0">
                <StatusMessage Message = "@errorMessage" />
                <EditForm Model = "Input" method = "post" OnValidSubmit = "LoginUser" FormName = "login">
                    <DataAnnotationsValidator />
                    <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" class = "form-label">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 = "current-password" aria-required = "true" placeholder = "password" />
                        <label for = "password" class = "form-label">Password</label>
                        <ValidationMessage For = "() => Input.Password" class = "text-danger" />
                    </div>
                    <div class = "checkbox mb-3">
                        <label class = "form-label">
                            <InputCheckbox @bind-Value = "Input.RememberMe" class = "darker-border-checkbox form-check-input" />
                            Ingelogd blijven
                        </label>
                    </div>
                    <div>
                        <button type = "submit" class = "w-100 btn btn-lg btn-primary">Inloggen</button>
                    </div>
                </EditForm>
            </section>
        </div>
    </div>
</div>

@code {
    private string? errorMessage;

    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    [SupplyParameterFromForm]
    private InputModel Input { get; set; } = new();

    [SupplyParameterFromQuery]
    private string? ReturnUrl { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (HttpMethods.IsGet(HttpContext.Request.Method))
        {
            // Clear the existing external cookie to ensure a clean login process
            await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
        }

    }

    public async Task LoginUser()
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true
        var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            Logger.LogInformation("User logged in.");
            RedirectManager.RedirectTo(ReturnUrl);
        }
        else if (result.RequiresTwoFactor)
        {
            RedirectManager.RedirectTo(
                "Account/LoginWith2fa",
                new() { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe });
        }
        else if (result.IsLockedOut)
        {
            Logger.LogWarning("User account locked out.");
            RedirectManager.RedirectTo("Account/Lockout");
        }
        else
        {
            errorMessage = "Error: Invalid login attempt.";
        }
    }

    private sealed class InputModel
    {
        [Required]
        [EmailAddress]
        public string Email { get; set; } = "";

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; } = "";

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
    }
}

Ошибка, которую я получаю:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

AVAZicht.Components.Account.Pages.Login.HttpContext.get returned null.

Я создал чистый проект Blazor Web App .net 8 с отдельными учетными записями в качестве типа аутентификации, и он работает отлично. Я просмотрел каждую страницу, которую он использует, перейдя на страницу входа в систему.

У кого-нибудь есть советы?

Я удалил @rendermode = "new InteractiveServerRenderMode(prerender: false)" из <Routes /> и <HeadOutlet /> в файле app.razor, и теперь страница входа снова работает. Как это работает? Не могу ли я установить режим рендеринга по умолчанию?

Jeremy 30.05.2024 19:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
266
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

HttpContext доступен только в режиме SSR (статический рендеринг сервера). https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-8.0#ihttpcontextaccessorhttpcontext-in-razor-comComponents-blazor.
App.razor устанавливает глобальный режим рендеринга:

  1. <Routes /> означает «нет интерактивности», для которого будет установлено значение SSR.
  2. <Routes @rendermode = "new InteractiveServerRenderMode"/> будет установлено значение «SSR (prerender) + интерактивный сервер»
  3. <Routes @rendermode = "new InteractiveServerRenderMode(prerender: false)"/> будет установлен чистый «интерактивный сервер» без SSR.

Таким образом, HttpContext доступен только при использовании первого (SSR).

Если вы создадите шаблон с «индивидуальной аутентификацией» и отметите App.razor, вы найдете

...
    <Routes @rendermode = "RenderModeForPage" />
...
@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

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

Он использует «динамический» глобальный режим. Если маршрут страницы — «/account/...», для этого режима рендеринга страницы будет установлено значение null, что соответствует SSR. https://learn.microsoft.com/en-us/aspnet/core/blazor/comComponents/render-modes?view=aspnetcore-8.0#area-folder-of-static-ssr-comComponents

Спасибо, это отлично работает! Какова наилучшая практика в отношении предварительного рендеринга true/false? Когда использовать не использовать предварительный рендер?

Jeremy 31.05.2024 08:01

@ Джереми. SSR (пререндер) использует «Httpcontext». InteractiveServer использует «websocket». На мой взгляд, WASM загружается медленно, поэтому я рассмотрю возможность использования пререндера для быстрой загрузки некоторых статических страниц. Я предпочитаю отключать предварительный рендеринг при использовании «InteractiveServer», потому что он уже загружается быстро. Но если вашему механизму нужен httpcontext, вы можете рассмотреть возможность использования страницы SSR или, проще говоря, просто создать контроллер API для обработки кодов, связанных с httpcontext.

Qiang Fu 31.05.2024 08:13

Официальные документы немного вводят в заблуждение. Они говорят: «... использует HttpContext, чтобы определить, отображается ли компонент на сервере». Однако, как вы отметили, HttpContext определяет только то, является ли компонент интерактивным или SSR! ничего о местонахождении интерактивности нельзя определить из HttpContext.

Shahryar Saljoughi 31.05.2024 15:24

Другие вопросы по теме