【问题标题】:why does UserManager.GetUserAsync not return?为什么 UserManager.GetUserAsync 不返回?
【发布时间】:2020-04-18 11:04:03
【问题描述】:

为什么 UserManager.GetUserAsync 不返回?

当我在“关于”页面上手动单击时,将在 Blazor UI 中访问属性 IsAdmin。我不明白为什么对 GetUSerAsync 的调用没有返回。有什么线索或错误吗?为简单起见,我删除了锁定代码。 (没有也不起作用)

关于.razor.cs

using System.Collections.Generic;
using System.Linq;
using Common.Server.Logic.Services;
using Common.Shared.Extensions;
using Microsoft.AspNetCore.Components;

namespace Common.Server.UI.Pages
{
    public partial class About : ComponentBase
    {
#nullable disable
        [Inject]
        private UserSessionInfo UserSession { get; set;  }

        private string IsAdminText { get; set; }
        private IEnumerable<string> UserRoleNames { get; set; } = Enumerable.Empty<string>();

#nullable restore

        protected override void OnInitialized()
        {
            IsAdminText = UserSession.IsAdmin.Format();
            UserRoleNames = UserSession.UserRoles;
        }
    }
}

UserSessionInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AspNetCore.ServiceRegistration.Dynamic.Interfaces;
using Common.Server.Logic.Bases;
using Common.Shared;
using Common.Shared.Extensions;
using Common.Shared.Models.Logging.Bases;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;

namespace Common.Server.Logic.Services
{
    public class UserSessionInfo : LockingBase, IHasUsername, IScopedService
    {
        public DateTime LoginAt { get; set; }

        private UserManager<IdentityUser> UserManager { get; }
        private AuthenticationStateProvider AuthenticationStateProvider { get; }

        public IEnumerable<string> UserRoles { get; private set; } = Enumerable.Empty<string>();

        private string? _username;
        public string? Username
        {
            get
            {
                CheckInitialized();

                return _username;
            }
        }

        private bool _isAdmin;
        public bool IsAdmin
        {
            get
            {
                CheckInitialized();

                return _isAdmin;
            }
        }

        public UserSessionInfo(IServiceProvider serviceProvider)
        {
            UserManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
            AuthenticationStateProvider = serviceProvider.GetRequiredService<AuthenticationStateProvider>();
        }

        private void CheckInitialized()
        {
            if (_username is null)
                // double lock
                SyncLock.Lock(async () => await InitializeAsync()).GetAwaiter().GetResult();
        }

        private async Task InitializeAsync()
        {
            var claimsPrincipal = (await AuthenticationStateProvider.GetAuthenticationStateAsync()).User;

            var user = await UserManager.GetUserAsync(claimsPrincipal); // Does not return
            _isAdmin = await UserManager.IsInRoleAsync(user, Const.Authorization.Roles.AdminRoleName);

            UserRoles = await UserManager.GetRolesAsync(user);

            var username = await UserManager.GetUserNameAsync(user);
            Interlocked.Exchange(ref _username, username);
        }
    }
}

还有(startup.cs):

services.AddDefaultIdentity<IdentityUser>()
                .AddRoles<IdentityRole>()
                .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<IdentityUser, IdentityRole>>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders()
                .AddDefaultUI();

services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();

services.AddScoped<UserSessionInfo>();

【问题讨论】:

  • services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;().AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();你可以先查一下。
  • 我正在使用。没有复制它。添加用户和登录工作正常。只是上面的代码没有。我用缺少的启动代码更新了我的问题代码。
  • @Henk Holtermann。这是正确的,但我总是使用一个 IServiceProvider ctor 参数来保持它的清洁。这减少了从基类继承时的样板签名代码。它还使测试类更容易一些,因为您只需为 IserviceProvider 传递一个模拟实例,而不是多个参数。无论如何,这并不能解决所描述的问题。

标签: c# asp.net-core entity-framework-core blazor-server-side


【解决方案1】:

当异步方法没有返回时,.GetAwaiter().GetResult() 是第一个嫌疑人。

您的调用代码(渲染器?)很可能让您的 Username 和 IsAdmin 属性重叠,然后您就会出现死锁。但是如果没有看到整个调用链,我们就无法确定。

根据经验,您不需要锁定或 GetResult(或 .Wait()、.Result)。当你认为你这样做时,可能是时候备份了。

【讨论】:

    【解决方案2】:

    我终于找到了解决方案。 (以及它不起作用的原因)

    问题是我在 OnInitialized 回调期间访问了 IsAdmin 而不是 OnInitializedAsync。

    将 IsAdmin 的访问权限放入 OnInitializedAsync 一切正常!

    【讨论】:

      猜你喜欢
      • 2019-01-27
      • 2018-12-09
      • 2017-10-08
      • 2014-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-30
      相关资源
      最近更新 更多