.net 对于剃刀页面,AuthenticationState级联值始终为空

ddrv8njm  于 2023-05-19  发布在  .NET
关注(0)|答案(1)|浏览(118)

有一个Razor组件(UserProfile.razor)试图使用AuthenticationState CascadingParameter获取登录用户的信息。当在任何Blazor页面中使用此(UserProfile.razor)时(即它返回用户的信息。但是当同一个组件(UserProfile.razor)被用在任何一个Razor页面(即index.cshtml),则_authState始终为null。
有什么办法能修好吗?

Index.cshtml

@page
@using static MyApp.Components.UserProfile;
@model IndexModel

@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<div class="row">
    <div class="col-6 d-flex flex-column justify-content-between">
        <div>
            <h2 class="mb-3">Hello, @Model.FriendlyUserName!</h2>
            <div class="my-3">
                <label class="form-label">Your username is</label>
                <input asp-for="Username" class="form-control" placeholder="Please choose your username." disabled />
            </div>
            <p>
                You cannot change that. However, you can update your
                other personal information on the right.
            </p>
        </div>
        <div>
            <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Page("/", new { area = "" })" method="post">
                <button type="submit" class="btn btn-lg btn-danger">Logout</button>
            </form>
        </div>
    </div>
    <div class="col-6">
        <component type="typeof(Components.UserProfile)"
                   render-mode="ServerPrerendered" />
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Index.cshtml.cs

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace MyApp.Areas.Identity.Pages.Account.Manage
{
  public class IndexModel : PageModel
  {
    private readonly UserManager<User> _userManager;
    private readonly SignInManager<User> _signInManager;

    public IndexModel(
        UserManager<User> userManager,
        SignInManager<User> signInManager)
    {
      _userManager = userManager;
      _signInManager = signInManager;
    }

    public User _user { get; set; } = null!;

    public string FriendlyUserName
    {
      get
      {
        if (!String.IsNullOrWhiteSpace(_user.FirstName))
        {
          if (!String.IsNullOrWhiteSpace(_user.LastName))
          {
            return $"{_user.FirstName} {_user.LastName}";
          }
          else
          {
            return _user.FirstName;
          }
        }
        else
        {
          return _user.UserName;
        }
      }
    }

    /// <summary>
    ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
    ///     directly from your code. This API may change or be removed in future releases.
    /// </summary>
    public string Username { get; set; }
    //public string FirstName { get; set; }
    //public string LastName { get; set; }

    /// <summary>
    ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
    ///     directly from your code. This API may change or be removed in future releases.
    /// </summary>
    [TempData]
    public string StatusMessage { get; set; }

    /// <summary>
    ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
    ///     directly from your code. This API may change or be removed in future releases.
    /// </summary>
    [BindProperty]
    public InputModel Input { get; set; }

    /// <summary>
    ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
    ///     directly from your code. This API may change or be removed in future releases.
    /// </summary>
    public class InputModel
    {
      /// <summary>
      ///     This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
      ///     directly from your code. This API may change or be removed in future releases.
      /// </summary>

      [Required]
      [DataType(DataType.Text)]
      [Display(Name = "FirstName")]
      public string FirstName { get; set; }

      [Required]
      [DataType(DataType.Text)]
      [Display(Name = "LastName")]
      public string LastName { get; set; }
    }

    private async Task LoadAsync(User user)
    {
      var userName = await _userManager.GetUserNameAsync(user);
      Username = userName;
      Input = new InputModel
      {
        FirstName = user.FirstName,
        LastName = user.LastName
      };
    }

    public async Task<IActionResult> OnGetAsync()
    {
      _user = await _userManager.GetUserAsync(User);
      if (_user == null)
      {
        return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
      }

      await LoadAsync(_user);
      return Page();
    }
  }
}

UserProfile.razor

@using Microsoft.AspNetCore.Identity;
@using System.ComponentModel.DataAnnotations;
@using Microsoft.EntityFrameworkCore;
@using MyApp.Pages;

<EditForm Model="@Input" OnValidSubmit="OnSubmit">
    <h2>User Details</h2>
</EditForm>

@code {
    [CascadingParameter]
    public Task<AuthenticationState>? _authState { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        if (_authState is not null) //_authState is always null when this component is used in razor page i.e. Index.cshtml
        {
            var authenticationState = await _authState;
        }
    }
}
m2xkgtsf

m2xkgtsf1#

Microsoft documentation所述:
级联值和参数提供了一种方便的方法,使数据沿组件层次结构从祖先组件向下流动到任意数量的后代组件。
这意味着来自示例化组件的Blazor页面的数据被转发到组件。
剃刀页面不是Blazor因此,没有数据从Razor页面转发到Blazor页面。这是一种不同的(旧的)技术。Razor页面/视图有their own conventions for authentication
将Blazor组件放在Razor页面中并不是一个好主意,因为您将失去Blazor功能。主Index.cshtml是例外,因为它启动了Blazor应用程序。但是,此时不转发数据。通过大量的努力,你可能会让它工作,但然后你重新设计Blazor。很有黑客的味道。
如果没有基础Blazor组件,即如果你想直接访问AuthenticationState,你需要在blazor组件中注入AuthenticationStateProvider,而不是使用这个Cascading参数。请参阅here的详细信息。

@inject AuthenticationStateProvider AuthenticationStateProvider

...

var authState = await AuthenticationStateProvider
    .GetAuthenticationStateAsync();

像这样的东西其实不需要转发:所以使用DI。

相关问题