你如何根据用户交替Ninject绑定?

Che*_*hev 12 c# asp.net-mvc dependency-injection ninject asp.net-mvc-3

这个问题在它有意义之前需要一些上下文,所以我将从项目的描述开始.

项目背景

我有一个开源项目,这是一个命令提示式网站(U413.com,U413.GoogleCode.com).该项目是在ASP.NET MVC 3中构建的,并使用Entity Framework 4.本质上,该站点允许您传入命令和参数,然后站点返回一些数据.这个概念相当简单,但我不想使用一个巨大的IF语句来处理命令.相反,我决定做一些有点独特的事情,并构建一个包含所有可能命令作为对象方法的对象.

该站点使用反射来定位与已发送命令对应的方法并执行它们.此对象是基于当前用户动态构建的,因为某些用户可以访问不同于其他用户的命令(例如,管理员拥有的不仅仅是主持人,而且mod还有多个用户等等).

我构建了一个CommandModuleFactory将在MVC控制器中创建的自定义,并将调用它的BuildCommandModule方法来构建命令模块对象.我现在正在使用Ninject进行依赖注入,我想逐步淘汰这个CommandModuleFactory,支持ICommandModule在没有控制器做任何工作的情况下注入控制器.

ICommandModule 有一个方法定义,如下所示:

public interface ICommandModule
{
    object InvokeCommand(string command, List<string> args);
}
Run Code Online (Sandbox Code Playgroud)

InvokeCommand 是对自身执行反射以查找可能与传入命令匹配的所有方法的方法.

然后我有五个不同的对象继承自ICommandModule(其中一些继承自其他模块,所以我们不重复命令):

AdministratorCommandModule继承自ModeratorCommandModule哪些继承自的UserCommandModule继承BaseCommandModule.

然后我也VisitorCommandModule继承了,BaseCommandModule因为访问者将无法访问其他三个命令模块中的任何命令.

希望你能开始看看它是如何工作的.到目前为止,我对这一切的工作方式感到非常自豪.

问题

我希望Ninject为我构建我的命令模块并将其绑定到ICommandModule我可以让我的MVC控制器依赖ICommandModule它,它将收到它的正确版本.这是我的Ninject模块在绑定发生的位置.

public class BuildCommandModule : NinjectModule
{
    private bool _isAuthenticated;
    private User _currentUser;

    public BuildCommandModule(
        bool isAuthenticated,
        string username,
        IUserRepository userRepository
        )
    {
        this._isAuthenticated = isAuthenticated;
        this._currentUser = userRepository.GetUserBy_Username(username);
    }

    public override void Load()
    {
        if (_isAuthenticated)
            if (_currentUser.Administrator)
                //load administrator command module
                this.Bind<ICommandModule>().To<AdministratorCommandModule>();
            else if (_currentUser.Moderator)
                //Load moderator command module
                this.Bind<ICommandModule>().To<ModeratorCommandModule>();
            else
                //Load user command module
                this.Bind<ICommandModule>().To<UserCommandModule>();
        else
            //Load visitor command module
            this.Bind<ICommandModule>().To<VisitorCommandModule>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了一些事情.首先,Ninject模块取决于一些事情.它取决于指示用户是否经过身份验证的布尔值(以确定它是否是登录命令模块之一,或访问者命令模块).接下来它取决于字符串用户名和IUserRepository.这是我在Global.asax中定义映射的地方.

    protected override IKernel CreateKernel()
    {
        var kernel = new StandardKernel();

        kernel.Bind<IBoardRepository>().To<BoardRepository>();
        kernel.Bind<IReplyRepository>().To<ReplyRepository>();
        kernel.Bind<ITopicRepository>().To<TopicRepository>();
        kernel.Bind<IUserRepository>().To<UserRepository>();

        kernel.Load(new BuildCommandModule(User.Identity.IsAuthenticated, User.Identity.Name, kernel.Get<IUserRepository>()));

        return kernel;
    }
Run Code Online (Sandbox Code Playgroud)

IUserRepository在加载Ninject模块以构建我的命令模块之前,您可以看到我映射到其具体类型(尽量不要将Ninject绑定模块与我的命令模块混淆:S).然后我用它kernel.Get<IUserRepository>()来解决我的Ninject模块对它的依赖.

我的问题HttpContext.Current.User是null.我不知道如何判断用户是否在Ninject绑定阶段登录.有任何想法吗?

当我在进行Ninject绑定时,如何获取对登录用户的引用?或者你能想到一个更好的方法让我为我做条件绑定ICommandModule吗?

任何帮助表示赞赏!

Vad*_*dim 12

您应该使用提供程序而不是将逻辑放在模块中.首先,您可以创建类似SecurityInformation类的东西,它可以告诉您用户是否经过身份验证及其角色.目前我的实现我认为只使用第一个用户的授权信息来启动应用程序.但是,每次请求此模块的实例时,您都要检查当前用户的权限.

public class CommandModuleProvider : IProvider
{
    public Type Type { get { return typeof(ICommandModule); } }
    public object Create(IContext context)
    {
        var securityInfo = context.Kernel.Get<SecurityInformation>();
        if (securityInfo.IsAuthenticated)
            if (securityInfo.IsCurrentUserAdministrator)
                //load administrator command module
                return context.Kernel.Get<AdministratorCommandModule>();
            else if (securityInfo.IsCurrentUserModerator)
                //Load moderator command module
                return context.Kernel.Get<ModeratorCommandModule>();
            else
                //Load user command module
                return context.Kernel.Get<UserCommandModule>();
        else
            //Load visitor command module
            return context.Kernel.Get<VisitorCommandModule>();
     }
}   
Run Code Online (Sandbox Code Playgroud)

然后将指定绑定

Kernel.Bind<ICommandModule>().ToProvider<CommandModuleProvider>();
Run Code Online (Sandbox Code Playgroud)