Страницы

Поиск по вопросам

пятница, 13 марта 2020 г.

Внедрение зависимостей в Owin

#aspnet_mvc #dependency_injection #aspnet_identity_2 #owin


В базовом шаблоне при создании asp.net mvc проекта в качестве системы авторизации
(по умолчанию) используется asp.net identity.

public class ApplicationUser : IdentityUser
{
    public async Task GenerateUserIdentityAsync(
        UserManager manager)
    {}
}

public class ApplicationUserManager : UserManager
{
    public ApplicationUserManager(IUserStore store)
        : base(store)
    {}

    public static ApplicationUserManager Create(
        IdentityFactoryOptions options,
        IOwinContext context)
    {}
}

public class ApplicationSignInManager : SignInManager
{
    public ApplicationSignInManager(
        ApplicationUserManager userManager,
        IAuthenticationManager authenticationManager) : 
        base(userManager, authenticationManager) { }

    public override Task CreateUserIdentityAsync(ApplicationUser user)
    {}

    public static ApplicationSignInManager Create(
        IdentityFactoryOptions options,
        IOwinContext context)
    {}
}

public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {}

    static ApplicationDbContext()
    {}

    public static ApplicationDbContext Create()
    {}
}


Указанные выше классы используются при настройки авторизации в приложении

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and role manager to use
        // a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext(ApplicationUserManager.Create);
        app.CreatePerOwinContext(ApplicationRoleManager.Create);
        app.CreatePerOwinContext(ApplicationSignInManager.Create);

    }
}


Как в приведенном коде избавиться от сильной зависимости - app.CreatePerOwinContext()?
    


Ответы

Ответ 1



Воспользуемся IoC контейнером Autofac для внедрения зависимостей. При помощи менеджера пакетов Nuget установим необходимые пакеты: Autofac Autofac ASP.NET MVC 5 Integration Autofac OWIN Integration Внесем следующие изменения в класс Startup: private void ConfigureContainer(IAppBuilder app) { var builder = new ContainerBuilder(); // STANDARD MVC SETUP: // Register your MVC controllers. builder.RegisterControllers(typeof(MvcApplication).Assembly); // Run other optional steps, like registering model binders, // web abstractions, etc., then set the dependency resolver // to be Autofac. builder.RegisterType().As().InstancePerRequest(); builder.RegisterType() .As>().InstancePerRequest(); builder.RegisterType>() .As>().InstancePerRequest(); builder.Register((c, p) => c.Resolve() .Authentication).InstancePerRequest(); var dataProtectionProvider = app.GetDataProtectionProvider(); builder.Register>((c, p) => BuildUserManager(c, p, dataProtectionProvider)); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); // OWIN MVC SETUP: // Register the Autofac middleware FIRST, then the Autofac MVC middleware. app.UseAutofacMiddleware(container); app.UseAutofacMvc(); } private UserManager BuildUserManager( IComponentContext context, IEnumerable parameters, IDataProtectionProvider dataProtectionProvider) { var manager = new ApplicationUserManager(context.Resolve>()); // Configure validation logic for usernames manager.UserValidator = new UserValidator(manager) { AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true }; // Configure validation logic for passwords manager.PasswordValidator = new PasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = true, RequireDigit = true, RequireLowercase = true, RequireUppercase = true, }; // Configure user lockout defaults manager.UserLockoutEnabledByDefault = true; manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5); manager.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. manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider { MessageFormat = "Your security code is {0}" }); manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider { Subject = "Security Code", BodyFormat = "Your security code is {0}" }); //manager.EmailService = new EmailService(); //manager.SmsService = new SmsService(); if (dataProtectionProvider != null) { manager.UserTokenProvider = new DataProtectorTokenProvider( dataProtectionProvider.Create("ASP.NET Identity")); } return manager; } } Добавим вызов метода ConfigureContainer(IAppBuilder app) в метод Configuration(IAppBuilder app) public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); ConfigureContainer(app); } } После выше приведенных действий можно удалить методы app.CreatePerOwinContext() из метода ConfigureAuth() так же необходимо модифицировать AccountControlle, ManageController: Убрать конструктор без параметров. Удалить следующие свойства: UserManager, SignInManager, AuthenticationManager Вот так может выглядеть AccountController после внесения необходимых изменений: public class AccountController : Controller { private readonly IAuthenticationManager _authenticationManager; private readonly SignInManager _signInManager; private readonly UserManager _userManager; public AccountController( UserManager userManager, SignInManager signInManager, IAuthenticationManager authenticationManager) { _authenticationManager = authenticationManager; _userManager = userManager; _signInManager = signInManager; } //Прочие необходимые методы } Использованные источники информации: Autofac’s documentation Habrahabr

Ответ 2



Строка app.CreatePerOwinContext(ApplicationUserManager.Create); нужна фреймворку для того чтобы можно было получть объект ApplicationUserManager в SecurityStampValidator. Не обязательно оставлять код для ApplicationUserManager.Create но нужно научить фреймворк как получать инстанс ApplicationUserManager. Если используется DI контейнер, то можно будет заменать на app.CreatePerOwinContext(() => DependencyResolver.Current.GetService());

Комментариев нет:

Отправить комментарий