在 ASP.NET Web 应用程序之外获取 UserManager 实例?

Get the UserManager instance outside of ASP.NET web application?

我有一个 ASP.NET MVC 5 网络应用程序,具有 ASP.NET 身份(个人帐户)。但我需要能够从控制台应用程序注册新用户。

所以我将一些 ASP.NET 身份 classes 从网络应用程序移动到 class 库中,以便在网络应用程序和 CLI 之间共享。

我已经成功移动了以下内容:

public class PortalDbContext : IdentityDbContext<PortalUser>
{
    public PortalDbContext(string connectionString)
        : base(connectionString, throwIfV1Schema: false)
    {
    }

    public static PortalDbContext Create(string connectionString)
    {
        return new PortalDbContext(connectionString);
    }
}

public class PortalUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<PortalUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        // Add custom user claims here
        return userIdentity;
    }
}

public class PortalUserManager : UserManager<PortalUser>
{
    public PortalUserManager(IUserStore<PortalUser> store) : base(store)
    {
    }

    public async Task<IdentityResult> RegisterUser(string email, string password)
    {
        PortalUser user = new PortalUser { UserName = email, Email = email };

        return await this.CreateAsync(user, password);
    }
}

但我不知道从哪里得到 IUserStore<PortalUser> PortalUserManager 需要的东西。

在网络应用程序中,此管理器是从 HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>() 中检索到的,我显然不能在 class 库中使用它。

看看 OwinRequestScopeContext nuget 包。它允许您在不依赖 System.Web 的情况下使用上下文。为了没有 link-only 答案,我将添加当前自述文件中的示例:

# Usage 

// using Owin; you can use UseRequestScopeContext extension method.

// enabled timing is according to Pipeline.
// so I recommend enable as far in advance as possible.
app.UseRequestScopeContext();

app.UseErrorPage();
app.Run(async _ =>
{
    // get global context like HttpContext.Current.
    var context = OwinRequestScopeContext.Current;

    // Environment is raw Owin Environment as IDictionary<string, object>.
    var __ = context.Environment;

    // optional:If you want to change Microsoft.Owin.OwinContext, you can wrap.
    new Microsoft.Owin.OwinContext(context.Environment);

    // Timestamp is request started(correctly called RequestScopeContextMiddleware timing).
    var ___ = context.Timestamp;

    // Items is IDictionary<string, object> like HttpContext.Items.
    // Items is threadsafe(as ConcurrentDictionary) by default.
    var ____ = context.Items;

    // DisposeOnPipelineCompleted can register dispose when request completed(correctly RequestScopeContextMiddleware underling Middlewares finished)
    // return value is cancelToken. If call token.Dispose() then canceled register.
    var cancelToken = context.DisposeOnPipelineCompleted(new TraceDisposable());

    // OwinRequestScopeContext over async/await also ConfigureAwait(false)
    context.Items["test"] = "foo";
    await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
    var _____ = OwinRequestScopeContext.Current.Items["test"]; // foo

    await Task.Run(() =>
    {
        // OwinRequestScopeContext over new thread/threadpool.
        var ______ = OwinRequestScopeContext.Current.Items["test"]; // foo
    });

    _.Response.ContentType = "text/plain";
    await _.Response.WriteAsync("Hello OwinRequestScopeContext! => ");
    await _.Response.WriteAsync(OwinRequestScopeContext.Current.Items["test"] as string); // render foo
});

我最终添加了一个静态方法 Create(string connectionString)PortalUserManager,它将创建 UserStoreDbContext 以及 return 的新实例经理。

public class PortalDbContext : IdentityDbContext<PortalUser>
{
    public PortalDbContext(string connectionString)
        : base(connectionString, throwIfV1Schema: false)
    {
    }

    public static PortalDbContext Create(string connectionString)
    {
        return new PortalDbContext(connectionString);
    }
}

public class PortalUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<PortalUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        // Add custom user claims here
        return userIdentity;
    }
}

public class PortalUserManager : UserManager<PortalUser>
{
    public PortalUserManager(IUserStore<PortalUser> store) : base(store)
    {
    }

    public static PortalUserManager Create(string connectionString)
    {
        UserStore<PortalUser> userStore = new UserStore<PortalUser>(PortalDbContext.Create(connectionString));

        PortalUserManager manager = new PortalUserManager(userStore);

        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<PortalUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = true,
            RequireUniqueEmail = true                
        };

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        return manager;
    }

    public async Task<IdentityResult> RegisterUser(string email, string password)
    {
        PortalUser user = new PortalUser { UserName = email, Email = email };

        return await this.CreateAsync(user, password);
    }
}