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

14
demandé sur Bojan 2016-03-26 22:16:41

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é

21
répondu Igor 2017-02-23 12:08:28

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

14
répondu Bojan 2016-12-07 17:22:15