简体   繁体   English

UserManager.CreateAsync(用户,密码)陷入无限循环

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

I'm trying to make a very simple implementation of an IUserStore that would essentially: 我正在尝试对IUserStore进行非常简单的实现,该实现基本上是:

  • use NHibernate 使用NHibernate
  • save users in a single table (no claims/logins) 将用户保存在一个表中(无声明/登录)
  • store role names in the same table, in an nvarchar column (pipe ( '|' ) separated if multiple items). 将角色名称存储在同一表的nvarchar列中(如果有多个项目,则将管道( '|' )分开)。

When I run the following method: 当我运行以下方法时:

[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...
    }
}

the last line would never finish executing. 最后一行永远不会完成执行。

The weird thing is that the UserManager never calls any of the functions in my SimpleUserStore ; 奇怪的是UserManager从不调用我的SimpleUserStore任何函数; it gets stuck before that. 在此之前被卡住了。

Here are the components I defined: 这是我定义的组件:

The user class: 用户类:

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(); }
    }
}

The User Store: 用户商店:

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);
    }
}

How I manage roles 我如何管理角色

Probably not so important, but here it is anyway: 可能不是那么重要,但是无论如何这里是:

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);
    }
}

I have been inspecting the UserManager<TUser> class with DotPeek, but found no obvious causes for this weird behavior. 我一直在用DotPeek检查UserManager<TUser>类,但是没有发现明显的原因导致这种奇怪的行为。

What could be causing this? 是什么原因造成的?

Your approach to async is fundamentally broken at the moment, because you're returning the same task for all operations... and never starting it. 您的异步方法目前已基本中断,因为您要为所有操作返回相同的任务……而永远不会启动它。 I don't see any "infinite loop" here - I just see you blocking on a task which can never complete. 我在这里看不到任何“无限循环”-我只是看到您阻塞了一个永远无法完成的任务。

It's not clear what you hope to accomplish with your EmptyTask task, but it's definitely not helping you at the moment. 目前尚不清楚您希望用EmptyTask任务完成什么,但目前绝对不能帮助您。

Furthermore, it's not clear that your code is really asynchronous in any aspect, unless _session.Save (etc) are really asynchronous. 此外,除非_session.Save (等)确实是异步的,否则不清楚您的代码在任何方面是否都是真正的异步的。

You could improve things somewhat by just running extra tasks, eg 您可以通过运行额外的任务来对事情进行一些改进,例如

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

... although the fact that you're then immediately blocking on the task in the calling code makes it pointless, too. ...尽管您随后立即阻止了调用代码中的任务,这也变得毫无意义。 (It's not even clear how this compiles at the moment, as Task doesn't have a Result property... only Task<T> does.) (目前还不清楚如何编译,因为Task没有Result属性,只有Task<T>有。)

As noted in comments, this will create a new task which will effectively run synchronously in a new thread - using more threads than you'd otherwise need, with the potential benefit of parallelism. 如评论中所述,这将创建一个新任务,该任务将在新线程中有效地同步运行-使用比您原本需要的线程更多的线程,并具有并行性的潜在好处。 It doesn't achieve the same goals as a properly asynchronous database call (where there wouldn't be any threads tied up for the save call - just a task which would complete when the relevant network response was returned). 它没有达到与适当的异步数据库调用相同的目标(在该调用中不会有任何线程被束缚-只有在返回相关的网络响应时才能完成的任务)。

If you don't really care about it being asynchronous, you can use: 如果您真的不关心它是异步的,则可以使用:

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

This will synchronously save (just like your current code does) but then return a completed task (rather than the task which will never complete, as per your current code). 这将同步保存(就像您当前的代码一样),但随后返回已完成的任务(而不是根据您的当前代码永远不会完成的任务)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM