结构图和Aspnet.Identity UserManager静态类问题

时间:2014-06-02 09:30:02

标签: c# static asp.net-mvc-5 inversion-of-control structuremap

我在帐户控制器中获取正确的UserManager实例时出现问题。目前,我无法重置密码以作为我的提供商工作,其他设置被忽略。

在Startup中 - void ConfigureAuth(IAppBuilder app)我有以下内容:

app.CreatePerOwinContext<ViewingBookerDatabaseContext>(ViewingBookerDatabaseContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

然后在AccountManager类中,上面引用的方法Create包含以下内容:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    // Configure the application user manager
    public ApplicationUserManager(ApplicationUserStore store)
        : base(store)
    {
    }

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new ApplicationUserStore(new ViewingBookerDatabaseContext()));

        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = false,
            RequireLowercase = false,
            RequireUppercase = false,
        };
        // Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;

        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }

现在,在安装IoC之前,这种方法很有用 - 在本例中是StrcutureMap。控制器的IoC以下列模式注册:

Scan(scan =>
        {
            scan.TheCallingAssembly();
            scan.With(new ControllerConvention());
        });

public class ControllerConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (type.CanBeCastTo(typeof(Controller)) && !type.IsAbstract)
        {
            registry.For(type).LifecycleIs(new UniquePerRequestLifecycle());
        }
    }
}

然后在我的AccountController中引用UserManager,如下所示:

private ApplicationUserManager _userManager;
    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

    private IAuthenticationManager _authenticationManager
    {
        get
        {
            return HttpContext.GetOwinContext().Authentication;
        }
    }

    public AccountController() 
    {
    }

    public AccountController(ApplicationUserManager userManager, ViewingBookerDatabaseContext context, CurrentUser currentUser, Logger logger, EmailService emailService)
    {
        UserManager = userManager;
        _context = context;
        _currentUser = currentUser;
        _logger = logger;
        _emailService = emailService;
    }

现在,UserManager用于我的密码重置,帐户创建等。安装IoC后,我收到“没有ITokenProvider已注册”密码重置,带有@的帐户名在创建用户时返回无效等。看起来像AccountController的ApplicationUserManager实例不是通过ApplicationUserManager类的Create()方法创建的。

任何人都可以指向我对结构图的正确实现,因此它调用Create来获取AccountUserManager的实例,而不是返回不包含ITokenProvider规范的该类的通用实例。等?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

好的伙计们。由于没有人回复这么久,不得不做一些进一步的研究,并提出以下,可能不是最优雅,这是一个有效的解决方案:

<强> 1。 Startup.cs - 删除以下行

app.CreatePerOwinContext<ViewingBookerDatabaseContext>   (ViewingBookerDatabaseContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

<强> 2。在Startup.cs中引入新变量

public static IDataProtectionProvider DataProtectionProvider {get;私人集; }

然后,将它在public void ConfigureAuth(IAppBuilder应用程序)中设置为以下:

DataProtectionProvider = app.GetDataProtectionProvider();

第3。 ApplicationUserManager或您调用的任何内容,删除静态Create方法并将其构造函数更改为以下内容:

         public ApplicationUserManager(ApplicationUserStore store)
        : base(store)
    {
        // Configure validation logic for usernames
        UserValidator = new UserValidator<ApplicationUser>(this)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };

        // Configure validation logic for passwords
        PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = false,
            RequireLowercase = false,
            RequireUppercase = false,
        };

        // Configure user lockout defaults
        UserLockoutEnabledByDefault = true;
        DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        MaxFailedAccessAttemptsBeforeLockout = 5;
    }

对于密码重置ITokenProvider,只需引用Startup的DataProtectionProvider变量,如下所示:

    if (Startup.DataProtectionProvider != null)
            UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(Startup.DataProtectionProvider.Create("ASP.NET Identity"));

最后......

在AccountController.cs中

- 删除对ApplicationUserManager的getter的任何引用,并重用StructureMap在控制器构造函数中提供的实例。

 public AccountController(ApplicationUserManager userManager)
    {
        _userManager = userManager;

所以你要调用_userManager对象方法

   REMOVE IF YOU HAVE IT IN YOUR CONTROLLER:
   public ApplicationUserManager UserManager
{
    get
    {
        return _userManager ??    HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    private set
    {
        _userManager = value;
    }
}

答案 1 :(得分:1)

您可以注册创建回调以在静态创建之外设置这些属性。以下是我如何完成同样的事情:

$collection = $this->getMock('MongoCollection', ['find', 'findOne'], [], '', false);
        $collection->method('find')->will($this->returnValue([
                [['_id' => 'aaa'], ['content'], 'ccc']
            ]));
        $collection->method('findOne')->will($this->returnValue([
            [['_id' => 'aaa'], ['content'], 'ccc']
        ]));