Как вставить UserManager & SignInManager

Я пытаюсь выяснить, как вводить UserManager и SignInManager. Я установил Ninject в своем приложении, и я использую его следующим образом:

Пожалуйста, рассмотрите это как совершенно новый проект. Inside 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>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

Чтобы уточнить еще раз, мой вопрос: как мне создать ApplicationUserManager и ApplicationSignInManager и ввести его в параметры моего контроллера. Вот контроллер, который я пытаюсь ввести в это:

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

EDIT:

Вот что я пробовал:

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

Но с этим я получаю нулевую ошибку ссылки

Ответ 1

Чтобы дать точный ответ на мой вопрос, вот код и инструкции:

Шаг 1: Создать пользовательский магазин

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

Шаг 2: Обновите ApplicationUserManager и переместите код из метода Create в конструктор

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

Шаг 3: Измените класс Startup.Auth и закомментируйте следующий код

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

Шаг 4: Update Account Controller (или любой другой контроллер) и добавьте следующий конструктор

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

Чтобы дополнительно расширить ответ на этот вопрос, на основе полученных мной комментариев:

Эти менеджеры не должны вводиться как классы, так как тогда вы не выполняете DI. Вместо этого следует создать несколько интерфейсов, которые дополнительно разделяют и группируют методы UserManager в соответствии с вашими потребностями. Вот пример:

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

В приведенном выше методе есть список из нескольких случайных методов, которые я выбрал, чтобы проиллюстрировать эту точку. При этом мы не будем вводить метод на основе интерфейса, такого как:

kernel.Bind<IUserManagerSegment>().To<ApplicationUserManager>();

Теперь наш конструктор 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

Ответ 2

Необходимые условия

Запустите новое приложение MVC5, используя шаблон MVC. Это установит все необходимые зависимости, а также разворачивает файл Startup.Auth.cs, который содержит код начальной загрузки для Microsoft.AspNet.Identity (он также включает все ссылки для Microsoft.AspNet.Identity).

Установите следующие пакеты и обновите их до последней версии.

Install-Package Ninject
Install-Package Ninject.MVC5

Конфигурация

Удалить конструктор по умолчанию на AccountController, так что останется только конструктор с параметрами. Он должен иметь подпись follownig.

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager)

Это гарантирует, что вы получите сообщение об ошибке, если инъекция завершится неудачно, что мы хотим.

Конфигурация NInject

В развертывании пакета NInject NuGet будет создан файл с именем NinjectWebCommon.cs, где происходит регистрация Nike-блока котла. У этого есть метод со следующей подписью, которую вы можете продлить с регистрацией.

private static void RegisterServices(IKernel kernel)

Теперь мы добавим следующий код в этот метод, чтобы NInject автоматически вводил экземпляры ApplicationSignInManager и ApplicationUserManager.

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

Вот оно. Теперь вы сможете перейти к ссылкам "Вход в систему" ​​или "Регистрация", и произойдет инъекция.

Альтернативный подход

Я предпочитаю прокси-подход, который предоставляет ограниченную функциональность для экземпляров ApplicationSignInManager и ApplicationUserManager. Затем я вставляю этот прокси в необходимые контроллеры. Это помогает отвлечь часть информации Identity от контроллеров, что облегчает ее изменение в будущем. Это не новая концепция, и независимо от того, выполняете ли вы это или нет, зависит от размера и сложности вашего проекта, а также от того, как вы хотите обрабатывать зависимости. Таким образом, преимущества (общие для любого прокси-сервера):

  • Вы можете абстрагировать некоторые зависимости от вашего кода.
  • Вы можете упорядочить некоторые вызовы в api
  • Вы можете указать только те функции, которые вы хотите использовать, включая настраиваемые части
  • Управление изменениями должно быть проще, если интерфейсы когда-либо изменятся, теперь вы изменяете вызовы в своем прокси вместо всего кода вызова на своих контроллерах.

Пример кода:

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

Добавьте в свою регистрацию зависимостей NInject следующую строку.

kernel.Bind<IAuthManager>().To<AuthManager>();

Измените конструктор AccountController, чтобы взять экземпляр IAuthManager. Наконец, измените свои методы, чтобы напрямую ссылаться на этот прокси вместо классов ASP.NET Identity.

Отказ от ответственности - я не связывал сложный вызов, просто очень простой, чтобы проиллюстрировать мою мысль. Это также совершенно необязательно, и независимо от того, выполняете ли вы это или нет, это должно зависеть от объема и размера вашего проекта и от того, как вы планируете использовать структуру удостоверения ASP.NET