2

依存性注入に ninject を使用して、asp.net mvc 4 Web アプリケーションにカスタム メンバーシップ プロバイダーを実装しようとしています。ここに私が今まで持っているコードがあります。

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

これは私の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);
    }
}

AccountMembershipProvider クラスのコメントで述べたように、AccountRepository.Initialize(name, config); 次のエラーが表示されます:オブジェクト参照がオブジェクトのインスタンスに設定されていません。 アプリケーションをデバッグし、ninject の動作に関する記事を読んだ後、問題の原因がわかりません。説明をお願いします。ありがとうございました。

4

5 に答える 5

2

カスタム メンバーシップ プロバイダーを使用して同様の問題が発生しました。AccountRepository で initialize メソッドを呼び出したい場合は、次のようにします。

以下を使用して、App_Start で ninject を使用して DI を構成します (nuget から入手可能)。

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. 

    }

}

次に、カスタム プロバイダーで次のようにします。

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
}

お役に立てれば、

于 2013-05-17T22:44:34.943 に答える
1

あなたが探している答えではありませんが、私は少し前にこれを自分でやろうとしましたが、それを機能させる方法を見つけることができましたが、ソリューションが複雑すぎて本番環境で使用するには脆弱であることがわかりました.

メンバーシップがプロバイダーを作成する方法が原因で、カスタム プロバイダーでインジェクションを使用するというアイデアを単にあきらめました。私の意見では、頭痛の種に値するものではありません。

また、インジェクションを使用すると、メンバーシップ プロバイダーの概念全体が壊れると思います。これは、プロバイダーはプラグイン可能であり、コードを変更せずにプロバイダーを別のプロバイダーに置き換えることができるという考えからです。データベースコンテキストを構成するためにアプリに構成コードが必要な場合、それは不可能です..

わかりました、プロバイダーを変更しないと主張するかもしれません..その場合、なぜプロバイダーを気にする必要があるのでしょうか? カスタムの IIdentity と IPrincipal の実装を実装しない理由はありません。

于 2013-05-12T20:29:36.000 に答える
0

実装する代わりに、次を実装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>();
    }
}

次に、設定する代わりにglobal.asax.csControllerFactoryで設定できます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.
    }
}

次に、ask current DependencyResolver(Ninject) の実装でMembershipProvider、この場合は次のインスタンスを作成しますIAccountRepository

public class CustomMembershipProvider : MembershipProvider
{
    private readonly IAccountRepository _repository;

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

    // Rest of implementation.
}

お役に立てれば。

于 2014-07-02T19:44:55.240 に答える