如何注入UserManager和SignInManager

我试图弄清楚如何注入UserManager和SignInManager。 我在我的应用程序中安装了Ninject,并且我以下列方式使用它:

请将此视为一个全新的项目。 在Startup.cs里面我有以下内容:

public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); app.UseNinjectMiddleware(CreateKernel); } private static IKernel CreateKernel() { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); return kernel; } } 

现在,如果我要创建一些Dummy类并尝试基于其工作的接口注入它。 我测试过了。 我想弄清楚的是我现在将如何从Startup.Auth.cs中删除以下内容并将其注入。 没有我可以依赖的接口,我不知道如何做到这一点:

 app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(ApplicationUserManager.Create); app.CreatePerOwinContext(ApplicationSignInManager.Create); 

为了澄清一次,我的问题是:如何实例化ApplicationUserManager和ApplicationSignInManager并将其注入我的控制器参数中。 这是我试图将其注入的控制器:

 public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { UserManager = userManager; SignInManager = signInManager; } 

编辑:

这是我尝试过的:

 private static IKernel CreateKernel() { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); kernel.Bind<IUserStore>().To<UserStore>(); kernel.Bind<UserManager>().ToSelf(); return kernel; } 

但有了这个我得到空引用错误

先决条件

使用MVC模板启动新的MVC5应用程序。 这将安装所有必需的依赖项,并部署包含Microsoft.AspNet.Identity的引导代码的Startup.Auth.cs文件(它还包括Microsoft.AspNet.Identity的所有引用)。

安装以下软件包,然后将其更新到最新版本。

 Install-Package Ninject Install-Package Ninject.MVC5 

组态

删除AccountController上的默认构造函数,以便只保留参数化构造函数。 它应该有follownig签名。

 public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager) 

这将确保如果注入失败,您将收到错误,这是我们想要的。

NInject配置

NInject NuGet包部署将创建一个名为NinjectWebCommon.cs的文件,其中进行锅炉板NInject注册。 这有一个带有以下签名的方法,您可以随注册一起扩展。

 private static void RegisterServices(IKernel kernel) 

现在我们将向此方法添加以下代码,以使NInject自动注入ApplicationSignInManagerApplicationUserManager实例。

 private static void RegisterServices(IKernel kernel) { kernel.Bind>().To>(); kernel.Bind>().ToSelf(); kernel.Bind().ToMethod(ctx => new HttpContextWrapper(HttpContext.Current)).InTransientScope(); kernel.Bind().ToMethod((context)=> { var cbase = new HttpContextWrapper(HttpContext.Current); return cbase.GetOwinContext().Get(); }); kernel.Bind().ToSelf(); } 

而已。 现在您应该能够导航到登录或注册链接并进行注入。

替代方法

我更喜欢一种代理方法,它为ApplicationSignInManagerApplicationUserManager实例公开了有限的function。 然后我将此代理注入必要的控制器。 它有助于从控制器中抽取一些身份信息,从而使将来更容易更改。 这不是一个新概念,无论你是否这样做取决于项目的大小和复杂性以及你想如何处理依赖项。 所以好处是(对任何代理来说都是常见的):

  • 您可以从代码中抽象出一些依赖项
  • 您可以简化api中的一些调用
  • 您只能公开要使用的function,包括可配置部分
  • 如果接口发生变化,变更管理应该更容易,现在您更改代理中的呼叫而不是控制器上的所有呼叫代码。

代码示例:

 public interface IAuthManager { Task PasswordSignInAsync(string userName, string password, bool rememberMe); } public class AuthManager : IAuthManager { private ApplicationUserManager _userManager; ApplicationSignInManager _signInManager; public AuthManager(ApplicationUserManager userManager, ApplicationSignInManager signInManager) { this._userManager = userManager; this._signInManager = signInManager; } public Task PasswordSignInAsync(string userName, string password, bool rememberMe) { return _signInManager.PasswordSignInAsync(userName, password, rememberMe, true); } } 

在NInject依赖项注册中添加以下行。

 kernel.Bind().To(); 

改变你的AccountController构造函数以获取IAuthManager的实例。 最后更改您的方法以直接引用此代理而不是ASP.NET Identity类。

免责声明 – 我没有连接一个复杂的电话,只是一个非常简单的电话来说明我的观点。 这也是完全可选的,无论你是否真的这样做,都应该取决于你的项目的范围和大小以及你如何计划使用ASP.NET Identity框架

为了准确回答我的问题,这里是代码和说明:

第1步:创建自定义用户存储

 public class ApplicationUserStore : UserStore { public ApplicationUserStore(ApplicationDbContext context) : base(context) { } } 

第2步:更新ApplicationUserManager并将代码从Create方法移动到构造函数中

 public class ApplicationUserManager : UserManager { public ApplicationUserManager(IUserStore store, IdentityFactoryOptions options) : base(store) { this.UserValidator = new UserValidator(this) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords this.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Configure user lockout defaults this.UserLockoutEnabledByDefault = true; this.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); this.MaxFailedAccessAttemptsBeforeLockout = 5; // Register two-factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user // You can write your own provider and plug it in here. this.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider { MessageFormat = "Your security code is {0}" }); this.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider { Subject = "Security Code", BodyFormat = "Your security code is {0}" }); this.EmailService = new EmailService(); this.SmsService = new SmsService(); var dataProtectionProvider = options.DataProtectionProvider; if (dataProtectionProvider != null) { this.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); } } } 

步骤3:修改Startup.Auth类并注​​释掉以下代码

 //app.CreatePerOwinContext(ApplicationDbContext.Create); //app.CreatePerOwinContext(ApplicationUserManager.Create); //app.CreatePerOwinContext(ApplicationSignInManager.Create); 

步骤4:更新帐户控制器(或任何其他有问题的控制器)并添加以下构造函数

 public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager) { _userManager = userManager; _signInManager = signInManager; _authManager = authManager; } 

步骤5:更新帐户控制器并使属性只能如下:

 public ApplicationSignInManager SignInManager { get { return _signInManager; } } public ApplicationUserManager UserManager { get { return _userManager; } } private IAuthenticationManager AuthenticationManager { get { return _authManager; } } 

第6步:更新Startup.cs

 public partial class Startup { private IAppBuilder _app; public void Configuration(IAppBuilder app) { ConfigureAuth(app); _app = app; app.UseNinjectMiddleware(CreateKernel); } private IKernel CreateKernel() { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); kernel.Bind().ToSelf().InRequestScope(); kernel.Bind>().To(); kernel.Bind().ToSelf(); kernel.Bind().ToSelf(); kernel.Bind().ToMethod(x => HttpContext.Current.GetOwinContext().Authentication); kernel.Bind().ToMethod(x => _app.GetDataProtectionProvider()); return kernel; } } 

根据我收到的评论,进一步扩大这个问题的答案:

这些经理不应该被注入课程,因为你没有完成DI。 应该做的是创建多个接口,根据您的需要进一步分离和分组UserManager的方法。 这是一个例子:

 public interface IUserManagerSegment { Task CreateAsync(ApplicationUser user, string password); Task CreateAsync(ApplicationUser user); Task ConfirmEmailAsync(string userId, string token); Task FindByNameAsync(string userName); Task IsEmailConfirmedAsync(string userId); Task ResetPasswordAsync(string userId, string token, string newPassword); Task> GetValidTwoFactorProvidersAsync(string userId); Task AddLoginAsync(string userId, UserLoginInfo login); void Dispose(bool disposing); void Dispose(); } 

上面的方法列出了我选择的几个随机方法来说明这一点。 有了这个说,我们不会注入基于这样的接口的方法:

 kernel.Bind().To(); 

现在我们的AccountController构造函数看起来像这样:

 public AccountController(IUserManagerSegment userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager) { _userManager = userManager; _signInManager = signInManager; _authManager = authManager; } 

应该对SignInManager和AuthenticationManager做同样的事情。

上面的代码已经过测试并且正在运行。 只需确保您引用了以下DLL:

Ninject.dll
Ninject.Web.Common
Ninject.Web.Common.OwinHost
Ninject.Web.Mvc