简体   繁体   English

使用ninject的Asp.net成员资格提供程序-调用Initialize方法

[英]Asp.net membership provider using ninject - call Initialize method

I am trying to implement a custom membership provider in an asp.net mvc 4 web application using ninject for dependency injection. 我正在尝试使用ninject进行依赖项注入在asp.net mvc 4 Web应用程序中实现自定义成员资格提供程序。 Here is the code I have until now. 这是我到目前为止的代码。

public interface IAccountRepository
{
    void Initialize(string name, NameValueCollection config);
    string ApplicationName { get; set; }
    bool ChangePassword(string username, string oldPassword, string newPassword);
    bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
        string newPasswordAnswer);
    MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
        string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
    bool DeleteUser(string username, bool deleteAllRelatedData);
    bool EnablePasswordReset { get; }
    bool EnablePasswordRetrieval { get; }
    MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
        out int totalRecords);
    /* I have deleted here all other methods and properties of membership for brevity */
}

.

public class AccountRepository : IAccountRepository
{
    private string applicationName;
    private bool enablePasswordReset;
    private bool enablePasswordRetrieval;
    private int maxInvalidPasswordAttempts;
    private int minRequiredNonAlphanumericCharacters;
    private int passwordAttemptWindow;
    private MembershipPasswordFormat passwordFormat;
    private string passwordStrengthRegularExpression;
    private bool requiresQuestionAndAnswer;
    private bool requiresUniqueEmail;
    private int minRequiredPasswordLength;

    public void Initialize(string name, NameValueCollection config)
    {
        applicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
        maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
        passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
        minRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
        minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "6"));
        enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
        passwordStrengthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
    }

    public string ApplicationName
    {
        get { return applicationName; }
        set { applicationName = value; }
    }

    public bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        throw new NotImplementedException();
    }

    public bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
        string newPasswordAnswer)
    {
        throw new NotImplementedException();
    }

    public MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
        string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
    {
        throw new NotImplementedException();
    }

    public bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        using (var database = new KinematDbContext())
        {
            // Query to get the user with the specified username
            User user = database.Users.SingleOrDefault(u => u.Username == username);

            if (user != null)
            {
                if (deleteAllRelatedData)
                {
                    database.Users.Remove(user);
                }
                else
                {
                    user.IsDeleted = true;
                }

                database.SaveChanges();
                return true;
            }

            return false;
        }
    }

    public bool EnablePasswordReset
    {
        get { return enablePasswordReset; }
    }

    public bool EnablePasswordRetrieval
    {
        get { return enablePasswordRetrieval; }
    }

    public MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
        out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
        out int totalRecords)
    {
        throw new NotImplementedException();
    }

    /* I have deleted here all other methods and properties of membership for brevity */
}

.

public class AccountMembershipProvider : MembershipProvider
{
    [Inject]
    public IAccountRepository AccountRepository { get; set; }

    public override void Initialize(string name, NameValueCollection config)
    {
        base.Initialize(name, config);
        AccountRepository.Initialize(name, config); 
        /* Here comes the error: Object reference not set to an instance of an object. */
    }

    public override string ApplicationName
    {
        get { return AccountRepository.ApplicationName; }
        set { AccountRepository.ApplicationName = value; }
    }

    public override bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        return AccountRepository.ChangePassword(username, oldPassword, newPassword);
    }
}

and this is my ninject controller factory(I also have set the controller factory in Application_Start()) 这是我的ninject控制器工厂(我也在Application_Start()中设置了控制器工厂)

public class NinjectControllerFactory : DefaultControllerFactory
{
    private IKernel ninjectKernel;

    public NinjectControllerFactory()
    {
        ninjectKernel = new StandardKernel();
        AddBindings();
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
    }

    private void AddBindings()
    {
        ninjectKernel.Bind<IAccountRepository>().To<AccountRepository>();
        ninjectKernel.Bind<IRoleRepository>().To<RoleRepository>();
        ninjectKernel.Inject(Membership.Provider);
        ninjectKernel.Inject(Roles.Provider);
    }
}

as I mention in a comment in the AccountMembershipProvider class when the AccountRepository.Initialize(name, config); 正如我在AccountRemberory.Initialize(name,config);时在AccountMembershipProvider类的注释中提到的那样; is called I receive the following error: Object reference not set to an instance of an object. 被称为我收到以下错误: 对象引用未设置为对象的实例。 After debugging the application and read articles about how ninject works I cannot figure out what the problem is about. 在调试了应用程序并阅读了有关ninject的工作方式的文章后,我无法弄清问题所在。 Please, can you give any explanation? 拜托,你能解释一下吗? Thank you. 谢谢。

Try to do the initialization for registering instances in Global.asax. 尝试进行初始化以在Global.asax中注册实例。

public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); 公共类MvcApplication:System.Web.HttpApplication {protected void Application_Start(){AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        // TODO register your binding here
        ...
    }
}

I've run into a similar problem using a Custom Membership Provider. 使用自定义成员资格提供程序时,我遇到了类似的问题。 If you want to call the initialize method in the AccountRepository you could do the following: 如果要在AccountRepository中调用initialize方法,则可以执行以下操作:

Configure your DI with ninject in App_Start using the following (available via nuget): 使用以下命令(通过nuget提供)在App_Start中使用ninject配置DI:

public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(() => CreateKernel());
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);
        DependencyResolver.SetResolver(new NinjectServiceLocator(kernel));
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        //add your bindings here
        kernel.Bind<IAccountRepository>().To<AccountRepository>();

        kernel.Bind<MembershipProvider>().To<AccountMembershipProvider>().InRequestScope();
        kernel.Bind<RoleProvider>().To<AccountRoleProvider>().InRequestScope(); //In case you have a custom Role Provider. 

    }

}

Then in your custom provider: 然后在您的自定义提供程序中:

public class AccountMembershipProvider : MembershipProvider
{
    private readonly IAccountRepository _repository;

    public AccountMembershipProvider()
    {
        _repository = ServiceLocator.Current.GetInstance<IAccountRepository>();
        _repository.Initialize();
    }

    public override bool ValidateUser(string username, string password)
    {
        return _repository.IsValidLogin(username, password);
    }

    ...//Other methods
}

Hope this helps, 希望这可以帮助,

Not the answer you're looking for, but I tried to do this myself a while ago and while I did manage to find a way to make it work, I found the solution to be too complex and brittle for production use. 不是您要寻找的答案,而是我自己尝试过一段时间,虽然确实设法找到一种解决办法,但我发现该解决方案过于复杂和脆弱,无法用于生产。

I simply gave up on the idea of using Injection with my custom provider, because of the way Membership creates the provider. 由于Membership创建提供程序的方式,我只是放弃了将Injection与我的自定义提供程序一起使用的想法。 It's just not worth the headaches in my opinion. 在我看来,这不值得头疼。

I also think using Injection breaks the whole concept of the Membership provider, since the idea is that providers are supposed to be pluggable, and you can replace one with another without making any changes to your code. 我还认为使用Injection打破了Membership提供程序的整个概念,因为该想法是提供程序应该是可插入的,并且您可以在不更改代码的情况下将另一个替换。 That's simply not possible to do if you have to have configuration code in your app to configure the database context.. 如果您必须在应用程序中具有配置代码来配置数据库上下文,那简直是不可能的。

Ok, you might argue that you won't be changing the provider.. in which case, Why bother with the provider at all then? 好的,您可能会争辩说您将不会更改提供程序。在这种情况下,为什么还要烦扰提供程序呢? Why not just implement a custom IIdentity and IPrincipal implementations. 为什么不仅仅实现自定义的IIdentity和IPrincipal实现。

How about adding the following line into your AddBindings() method 如何将以下行添加到您的AddBindings()方法中

kernel.Bind<AccountMembershipProvider>().ToMethod(ctx => Membership.Provider);

I used ninject and custom membership provider with mvc3 Not sure if it helps you but you can compare yours with mine. 我在mvc3中使用了ninject和自定义成员资格提供程序。不确定它是否对您有帮助,但是您可以将其与我的进行比较。

[assembly: WebActivator.PreApplicationStartMethod(typeof(VBooks.Web.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(VBooks.Web.App_Start.NinjectWebCommon), "Stop")]

namespace VBooks.Web.App_Start
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;

    public class ProviderInitializationHttpModule : IHttpModule
    {
        public ProviderInitializationHttpModule(MembershipProvider membershipProvider) { }
        public void Init(HttpApplication context) { }


        void IHttpModule.Dispose()
        {

        }
    } 

    public static class NinjectWebCommon 
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start() 
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            //
            RegisterServices(kernel);

            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IRegisterService>().To<RegisterService>();
            kernel.Bind<IEmailService>().To<EmailService>();
            kernel.Bind<IAccountService>().To<AccountService>();
            kernel.Bind<ICoverService>().To<CoverService>();
            kernel.Bind<IAdminLogService>().To<AdminLogService>();
            kernel.Bind<MembershipProvider>().ToMethod(ctx => Membership.Provider);
            kernel.Bind<IHttpModule>().To<ProviderInitializationHttpModule>();

            // Add data and infrastructure modules     
            var modules = new List<INinjectModule>
            {
                new RepositoryModule()
            };

            kernel.Load(modules);

        }  

    }
}

Instead of implementing DefaultControllerFactory you can implement IDependencyResolver : 除了实现DefaultControllerFactory还可以实现IDependencyResolver

public class NinjectDependencyResolver : IDependencyResolver
{
    readonly IKernel _kernel;

    public NinjectDependencyResolver()
    {
        _kernel = new StandardKernel();
        AddBindings();
    }

    public object GetService(Type serviceType)
    {
        return _kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _kernel.GetAll(serviceType);
    }

    void AddBindings()
    {
        // Remember to add bindings here.
        _kernel.Bind<IAccountRepository>().To<EFAccountRepository>();
    }
}

Then in global.asax.cs instead of setting ControllerFactory you can set DependencyResolver : 然后在global.asax.cs中,而不是设置ControllerFactory ,可以设置DependencyResolver

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);

        DependencyResolver.SetResolver(new NinjectDependencyResolver()); // Here.
    }
}

Then in your implementation of MembershipProvider ask current DependencyResolver(Ninject) to create you an instance of, in this case, IAccountRepository : 然后,在实现MembershipProvider要求当前的DependencyResolver(Ninject)创建一个IAccountRepository的实例:

public class CustomMembershipProvider : MembershipProvider
{
    private readonly IAccountRepository _repository;

    public OpenTibiaMembershipProvider()
    {
        _repository = (IAccountRepository)DependencyResolver.Current.GetService(typeof(IAccountRepository));
    }

    // Rest of implementation.
}

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM