AspIdentiy ApplicationUserManager - это Static, как расширить, чтобы он участвовал в моей инфраструктуре IoC?

В новом приложении ASPNET MVC теперь вы получаете бесплатные льготы AspIdentity.

В вашем почтовом сервисе есть незащищенная небольшая строка.

Итак, я сделал:

public class EmailService : IIdentityMessageService
{
    private static My.Services.IEmailService _emailservice;

    public EmailService(Insolvency.Services.IEmailService emailservice)
    {
        _emailservice = emailservice;
    }

    public Task SendAsync(IdentityMessage message)
    {
        _emailservice.SendEmail(message);
       return Task.FromResult(0);
    }
}

и теперь радость:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    private My.Services.IEmailService _emailservice;

    public ApplicationUserManager(IUserStore<ApplicationUser> store, My.Services.IEmailService emailservice): base(store)        
    {
        _emailservice = emailservice;
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()), _emailservice);
       ...

когда Owin наносит удар, он вызывает Create on ApplicationUserManager в Startup.Auth.cs:

public partial class Startup 
   {
    public void ConfigureAuth(IAppBuilder app) 
     {
        ...
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

и поскольку я использую AutoFac в качестве моего контейнера IoC, в global.asax.cs

builder.RegisterType<My.Services.EmailService>().As<IEmailService>();

если метод Create является статическим, поэтому я получаю:
_emailService имеет значение null

Я посмотрел здесь: http://forums.asp.net/post/5293670.aspx и Как создать экземпляр UserManager и Использование Autofac для предоставления типов, экспортируемых статическим factory. но не повезло.

Если я изменил:

private My.Services.IEmailService _emailservice;

чтобы быть публичным, не статическим, я чувствую, что боги IoC трясутся головами, и я не могу построить ссылку на объект.

Ответ 1

Сегодня я боролся с тем же вопросом (все еще работаю над этим, так как я новичок в Asp.Identity). Я сделал это следующим образом:

  • Startup.cs(используйте собственный контейнер)

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var authConfigurator = new AuthConfigurator();
            authConfigurator.ConfigureAuth(app);
            var unityContainer = UnityConfig<MvcUnityDependencyContainer>.UseContainer();
            //Asp identity registration
            IDataProtectionProvider dataProtectionProvider = app.GetDataProtectionProvider();
            unityContainer.RegisterInstance(dataProtectionProvider);
            unityContainer.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
            unityContainer.RegisterType<UserManager<ApplicationUser, int>>(new HierarchicalLifetimeManager());
            unityContainer.RegisterType IIdentityMessageService, EmailService>();
            unityContainer.RegisterType<IUserStore<ApplicationUser, int>,
                UserStore<ApplicationUser, CustomRole, int, CustomUserLogin, CustomUserRole, CustomUserClaim>>(
                new InjectionConstructor(new ApplicationDbContext()));
            unityContainer.RegisterType<IIdentityMessageService, EmailService>();
        }
    }
    
  • ApplicationUserManager (я удалил статический метод Create):

    public class ApplicationUserManagerService : UserManager<ApplicationUser, int>
    {
        public ApplicationUserManagerService(IUserStore<ApplicationUser, int> store, 
                                             IIdentityMessageService emailService,
                                             IDataProtectionProvider dataProtectionProvider)
                                             : base(store)
        {
            UserTokenProvider = new EmailTokenProvider<ApplicationUser, int>();
            EmailService = emailService;
            Configure(dataProtectionProvider);
        }
        private void Configure(IDataProtectionProvider dataProtectionProvider)
        {
            // Configure validation logic for usernames
            UserValidator = new UserValidator<ApplicationUser, int>(this)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };
            // Configure validation logic for passwords
            PasswordValidator = new PasswordValidator
            {
                RequiredLength = 1,
                RequireNonLetterOrDigit = false,
                RequireDigit = false,
                RequireLowercase = false,
                RequireUppercase = false,
            };
            // 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 in here.
            RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser, int>
            {
                MessageFormat = "Your security code is: {0}"
            });
            RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser, int>
            {
                Subject = "Security Code",
                BodyFormat = "Your security code is: {0}"
            });
            if (dataProtectionProvider != null)
            {
                UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
            }
        }
    }
    
  • контроллер

    public class AccountController : Controller
    {
        private ApplicationUserManagerService _userManagerService;
        public AccountController(ApplicationUserManagerService userManagerService)
        {
            Contract.Requires(userManagerService != null);
            _userManagerService = userManagerService;
        }
        /*....*/
    }
    
  • ApplicationUser

    public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
        {
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            return userIdentity;
        }
    }
    
    public class CustomRole : IdentityRole<int, CustomUserRole>
    {
        public CustomRole() { }
        public CustomRole(string name) { Name = name; }
    }
    
    public class CustomUserClaim : IdentityUserClaim<int> { }
    public class CustomUserLogin : IdentityUserLogin<int> { }
    public class CustomUserRole : IdentityUserRole<int> { }
    

Это работает для меня, но, пожалуйста, не стесняйтесь предлагать лучшее решение.

Ответ 2

Я долгое время боролся с этим, и, в конце концов, самым простым было это.

Внутри

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)

найдите эти строки кода.

manager.EmailService = new EmailService();
manager.SmsService = new SmsService();

И измените его на это.

manager.EmailService = new EmailService(DependencyResolver.Current.GetService<Insolvency.Services.IEmailService>());

Мне не нравится шаблон Service Locator, но для него используется весь шаблонный шаблон MVC, и лучше не бороться с каркасом.

Ответ 3

Используя Unity, я добавил следующее в RegisterTypes(IUnityContainer container) в UnityConfig.cs:

container.RegisterType<ApplicationUserManager>(New InjectionFactory(x => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()));

Это занимает ApplicationUserManager, который уже был создан для OwinContext в Startup.ConfigureAuth(IAppBuilder app), и делает его доступным для инъекций. Вы можете сохранить все остальное в настройках по умолчанию, включая статический метод Application_serManager Create.