Comment injecter UserManager & SignInManager
j'essaie de trouver comment injecter UserManager et SignInManager. J'ai installé Ninject dans mon application et je l'utilise de la manière suivante:
veuillez considérer que c'est un tout nouveau projet. À L'Intérieur De Démarrage.cs, j'ai le code suivant:
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;
}
}
maintenant, si je devais créer une classe fictive et essayer de l'injecter en se basant sur son interface qui fonctionne. Je l'ai testé. Ce que j'essaie de savoir comment aurais-je maintenant bande de la suite de Démarrage.Auth.cs et de l'injecter. N'ayant pas d'interfaces sur lesquelles je puisse compter, Je ne suis pas sûr de savoir comment faire:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
juste pour clarifier une fois de plus, ma question Est: Comment puis-je instancier ApplicationUserManager et ApplicationSignInManager et l'injecter dans Mes paramètres de contrôleur. Voici la manette dans laquelle j'essaie de l'injecter:
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
EDIT:
Voici ce que j'ai essayé:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
kernel.Bind<UserManager<ApplicationUser>>().ToSelf();
return kernel;
}
mais avec ceci j'obtiens la référence nulle erreur
2 réponses
pré-requis
lancer une nouvelle application MVC5 en utilisant le modèle MVC. Cela installera toutes les dépendances nécessaires ainsi que déployer le Startup.Auth.cs
fichier qui contient le code bootstrap pour Microsoft.AspNet.Identity
(sla comprend toutes les références pour Microsoft.AspNet.Identité.)
installez les paquets suivants et mettez-les à jour au plus tard par la suite.
Install-Package Ninject
Install-Package Ninject.MVC5
Configuration
Supprimer le constructeur par défaut sur le AccountController
il ne reste donc que le constructeur paramétré. Il doit avoir la signature suivante.
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)
cela garantit que vous obtiendrez une erreur si l'injection échoue, ce que nous voulons.
NInject Configuration
le déploiement du paquet NInject NuGet aura créé un fichier nommé NinjectWebCommon.cs
où a lieu L'enregistrement de la plaque chauffante. Ceci a une méthode avec la signature suivante que vous pouvez étendre avec votre enregistrement.
private static void RegisterServices(IKernel kernel)
Maintenant, nous allons ajouter le code suivant à cette méthode pour obtenir NInject injecter automatiquement l' ApplicationSignInManager
et ApplicationUserManager
instances.
private static void RegisterServices(IKernel kernel) {
kernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
kernel.Bind<UserManager<ApplicationUser>>().ToSelf();
kernel.Bind<HttpContextBase>().ToMethod(ctx => new HttpContextWrapper(HttpContext.Current)).InTransientScope();
kernel.Bind<ApplicationSignInManager>().ToMethod((context)=>
{
var cbase = new HttpContextWrapper(HttpContext.Current);
return cbase.GetOwinContext().Get<ApplicationSignInManager>();
});
kernel.Bind<ApplicationUserManager>().ToSelf();
}
c'est tout. Maintenant, vous devriez être en mesure de naviguer vers les liens de connexion ou D'enregistrement et l'injection se produira.
Approche Alternative
je préfère un Proxy approche qui expose des fonctionnalités limitées pour l' ApplicationSignInManager
et ApplicationUserManager
instances. J'injecte alors cette procuration dans le contrôleurs nécessaires. Il aide à faire abstraction de certaines informations sur l'identité des contrôleurs, ce qui le rend plus facile à changer à l'avenir. Ce n'est en aucun cas un nouveau concept et que vous le fassiez ou non dépend de la taille et de la complexité de votre projet ainsi que de la façon dont vous voulez gérer les dépendances. Donc les avantages sont (communs en fait pour n'importe quel proxy):
- vous pouvez abstraire certaines des dépendances de votre code
- Vous pouvez rationaliser certains appels dans l'api
- vous ne pouvez exposer que les fonctionnalités que vous voulez utiliser, y compris les pièces configurables
- la gestion du changement devrait être plus facile si jamais les interfaces changent, maintenant vous changez les appels dans votre proxy au lieu de tout le code d'appel dans vos controllers.
exemple de Code:
public interface IAuthManager
{
Task<SignInStatus> 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<SignInStatus> PasswordSignInAsync(string userName, string password, bool rememberMe)
{
return _signInManager.PasswordSignInAsync(userName, password, rememberMe, true);
}
}
ajouter la ligne suivante dans votre enregistrement de dépendances NInject.
kernel.Bind<IAuthManager>().To<AuthManager>();
Modifier votre AccountController
constructeur à prendre dans une instance de IAuthManager
. Finalement, changez vos méthodes pour vous référer à ce proxy au lieu de ASP.NET les classes D'identité directement.
Avertissement - je n'ai pas de fil d'un complexe d'appel, il suffit d'une très simple pour illustrer mon point. Cela est également entièrement facultatif et si vous le faites ou non devrait vraiment dépendre de la portée et la taille de votre projet et la façon dont vous prévoyez d'utiliser ASP.NET cadre D'identité
pour donner une réponse exacte à ma question, voici le code et les instructions:
Étape 1: Créer des Utilisateurs de Stocker
public class ApplicationUserStore : UserStore<ApplicationUser>
{
public ApplicationUserStore(ApplicationDbContext context)
: base(context)
{
}
}
Étape 2: Mettre à jour ApplicationUserManager et déplacer le code de la méthode Create dans le constructeur
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
: base(store)
{
this.UserValidator = new UserValidator<ApplicationUser>(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<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
this.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
{
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<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
}
Étape 3: Modifier le démarrage.Classe Auth et commentez le code suivant
//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
//app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
Étape 4: Mettre à jour le contrôleur de Compte (ou tout autre contrôleur en question) et ajouter ce qui suit: constructeur
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager)
{
_userManager = userManager;
_signInManager = signInManager;
_authManager = authManager;
}
Étape 5: Mettre à jour le contrôleur de Compte et ne rendre les propriétés récupérables que comme suit:
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager;
}
}
private IAuthenticationManager AuthenticationManager
{
get
{
return _authManager;
}
}
Étape 6: Mise À Jour De Démarrage.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<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind<IUserStore<ApplicationUser>>().To<ApplicationUserStore>();
kernel.Bind<ApplicationUserManager>().ToSelf();
kernel.Bind<ApplicationSignInManager>().ToSelf();
kernel.Bind<IAuthenticationManager>().ToMethod(x => HttpContext.Current.GetOwinContext().Authentication);
kernel.Bind<IDataProtectionProvider>().ToMethod(x => _app.GetDataProtectionProvider());
return kernel;
}
}
Pour étendre la réponse à cette question, sur la base des commentaires que j'ai reçu:
ces gestionnaires ne devraient pas être injectés en tant que classes car alors vous n'êtes pas accomplissant DI. Ce qui devrait être fait à la place est de créer des interfaces multiples qui séparent davantage et groupent les méthodes de UserManager selon vos besoins. Voici un exemple:
public interface IUserManagerSegment
{
Task<IdentityResult> CreateAsync(ApplicationUser user, string password);
Task<IdentityResult> CreateAsync(ApplicationUser user);
Task<IdentityResult> ConfirmEmailAsync(string userId, string token);
Task<ApplicationUser> FindByNameAsync(string userName);
Task<bool> IsEmailConfirmedAsync(string userId);
Task<IdentityResult> ResetPasswordAsync(string userId, string token, string newPassword);
Task<IList<string>> GetValidTwoFactorProvidersAsync(string userId);
Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login);
void Dispose(bool disposing);
void Dispose();
}
la méthode ci-dessus a une liste de quelques méthodes aléatoires que j'ai choisi juste pour illustrer le point. Ceci dit, nous n'aurions pas injecter la méthode basée sur l'interface comme ceci:
kernel.Bind<IUserManagerSegment>().To<ApplicationUserManager>();
et maintenant notre constructeur AccountController ressemblerait à ceci:
public AccountController(IUserManagerSegment userManager, ApplicationSignInManager signInManager, IAuthenticationManager authManager)
{
_userManager = userManager;
_signInManager = signInManager;
_authManager = authManager;
}
il faut faire la même chose pour SignInManager et AuthenticationManager.
Le code ci-dessus a été testé et de travail. Assurez-vous simplement d'avoir référencé les DLLs suivantes:
Ninject.dll
Ninject.Web.Commune
Ninject.Web.Commun.OwinHost
Ninject.Web.Mvc