簡體   English   中英

UserManager.CreateAsync(用戶,密碼)陷入無限循環

[英]UserManager.CreateAsync(user, password) stuck in infinite loop

我正在嘗試對IUserStore進行非常簡單的實現,該實現基本上是:

  • 使用NHibernate
  • 將用戶保存在一個表中(無聲明/登錄)
  • 將角色名稱存儲在同一表的nvarchar列中(如果有多個項目,則將管道( '|' )分開)。

當我運行以下方法時:

[Fact]
public void Create_A_User()
{
    // _session is a valid NHibernate ISession object
    using (var userStore = new SimpleUserStore<SimpleIdentityUser>(_session))
    using (var userManager = new UserManager<SimpleIdentityUser>(userStore))
    {
        var user = new SimpleIdentityUser
        {
            UserName = "kenny_mccormick",
            RolesStr = "admin",
        };

        var createTask = userManager.CreateAsync(user, "the_password");

        var result = createTask.Result; // this never finishes...
    }
}

最后一行永遠不會完成執行。

奇怪的是UserManager從不調用我的SimpleUserStore任何函數; 在此之前被卡住了。

這是我定義的組件:

用戶類:

public class SimpleIdentityUser : IUser
{
    public virtual Guid UserId { get; set; }
    public virtual string PasswordHash { get; set; }
    public virtual string SecurityStamp { get; set; }
    public virtual string RolesStr { get; set; }
    public virtual string UserName { get; set; }

    public virtual string Id
    {
        get { return UserId.ToString(); }
    }
}

用戶商店:

public class SimpleUserStore<TUser> :
    IUserPasswordStore<TUser>,
    IUserRoleStore<TUser>,
    IUserSecurityStampStore<TUser>
    where TUser : SimpleIdentityUser
{
    // ReSharper disable once StaticFieldInGenericType
    private static readonly Task EmptyTask = new Task(() => { });

    private readonly ISession _session;

    public SimpleUserStore(ISession session)
    {
        _session = session;
    }

    public Task<TUser> FindAsync(UserLoginInfo login)
    {
        return Task.FromResult((TUser) null);
    }

    public Task CreateAsync(TUser user)
    {
        _session.Save(user);
        return EmptyTask;
    }

    public Task UpdateAsync(TUser user)
    {
        // updates will (hopefully) be saved automatically when the current session is committed
        return EmptyTask;
    }

    public Task DeleteAsync(TUser user)
    {
        _session.Delete(user);
        return EmptyTask;
    }

    public Task<TUser> FindByIdAsync(string userId)
    {
        TUser user = null;
        Guid guidId;

        if (Guid.TryParse(userId, out guidId))
            user = _session.Get<TUser>(guidId);

        return Task.FromResult(user);
    }

    public Task<TUser> FindByNameAsync(string userName)
    {
        TUser user = _session.Query<TUser>().SingleOrDefault(u => u.UserName == userName);
        return Task.FromResult(user);
    }

    public Task SetPasswordHashAsync(TUser user, string passwordHash)
    {
        user.PasswordHash = passwordHash;
        return EmptyTask;
    }

    public Task<string> GetPasswordHashAsync(TUser user)
    {
        return Task.FromResult(user.PasswordHash);
    }

    public Task<bool> HasPasswordAsync(TUser user)
    {
        return Task.FromResult(user.PasswordHash != null);
    }

    public void Dispose()
    {
    }

    public Task AddToRoleAsync(TUser user, string role)
    {
        new SimpleRoleManager<TUser>(user).AddRole(role);

        return EmptyTask;
    }

    public Task RemoveFromRoleAsync(TUser user, string role)
    {
        new SimpleRoleManager<TUser>(user).DeleteRole(role);

        return EmptyTask;
    }

    public Task<IList<string>> GetRolesAsync(TUser user)
    {
        List<string> roles = new SimpleRoleManager<TUser>(user).GetRoles().ToList();

        return Task.FromResult((IList<string>) roles);
    }

    public Task<bool> IsInRoleAsync(TUser user, string role)
    {
        return Task.FromResult(new SimpleRoleManager<TUser>(user).IsInRole(role));
    }

    public Task SetSecurityStampAsync(TUser user, string stamp)
    {
        user.SecurityStamp = stamp;
        return EmptyTask;
    }

    public Task<string> GetSecurityStampAsync(TUser user)
    {
        return Task.FromResult(user.SecurityStamp);
    }
}

我如何管理角色

可能不是那么重要,但是無論如何這里是:

public class SimpleRoleManager<TUser> where TUser : SimpleIdentityUser
{
    private const string Separator = "|";

    private readonly TUser _user;

    public SimpleRoleManager(TUser user)
    {
        _user = user;
    }

    public string[] GetRoles()
    {
        return (_user.RolesStr ?? String.Empty)
            .Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
    }

    public bool IsInRole(string roleName)
    {
        return GetRoles().Contains(roleName);
    }

    public bool AddRole(string roleName)
    {
        var roles = GetRoles().ToList();

        if (roles.Contains(roleName))
            return false;

        roles.Add(roleName);
        SetRoles(roles);
        return true;
    }

    public bool DeleteRole(string roleName)
    {
        List<string> roles = GetRoles().ToList();

        if (!roles.Contains(roleName))
            return false;

        roles.Remove(roleName);
        SetRoles(roles);
        return true;
    }

    private void SetRoles(IEnumerable<string> roles)
    {
        _user.RolesStr = String.Join(Separator, roles);
    }
}

我一直在用DotPeek檢查UserManager<TUser>類,但是沒有發現明顯的原因導致這種奇怪的行為。

是什么原因造成的?

您的異步方法目前已基本中斷,因為您要為所有操作返回相同的任務……而永遠不會啟動它。 我在這里看不到任何“無限循環”-我只是看到您阻塞了一個永遠無法完成的任務。

目前尚不清楚您希望用EmptyTask任務完成什么,但目前絕對不能幫助您。

此外,除非_session.Save (等)確實是異步的,否則不清楚您的代碼在任何方面是否都是真正的異步的。

您可以通過運行額外的任務來對事情進行一些改進,例如

public Task CreateAsync(TUser user)
{
    Action action = () => _session.Save(user);
    return Task.Run(action);
}

...盡管您隨后立即阻止了調用代碼中的任務,這也變得毫無意義。 (目前還不清楚如何編譯,因為Task沒有Result屬性,只有Task<T>有。)

如評論中所述,這將創建一個新任務,該任務將在新線程中有效地同步運行-使用比您原本需要的線程更多的線程,並具有並行性的潛在好處。 它沒有達到與適當的異步數據庫調用相同的目標(在該調用中不會有任何線程被束縛-只有在返回相關的網絡響應時才能完成的任務)。

如果您真的不關心它是異步的,則可以使用:

public Task CreateAsync(TUser user)
{
    _session.Save(user);
    return Task.FromResult<object>(null);
}

這將同步保存(就像您當前的代碼一樣),但隨后返回已完成的任務(而不是根據您的當前代碼永遠不會完成的任務)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM