项目背景
我有一个开源项目,它是一个命令提示样式的网站(U413.com,U413.GoogleCode.com).该项目构建在ASP.NET MVC 3中,并使用实体框架4.本质上该站点允许您传递命令和参数,然后站点返回一些数据.这个概念很简单,但是我不想使用一个巨大的IF语句来处理命令.相反,我决定做一些有点独特的事情,并构建一个包含所有可能的命令作为对象上的方法的对象.
该站点使用反射来定位与发送的命令相对应的方法并执行它们.该对象是基于当前用户动态构建的,因为某些用户可以访问与其他用户不同的命令(例如,管理员拥有多个主持人,而且拥有超过用户等等).
我创建了一个自定义的CommandModuleFactory,它将在MVC控制器中创建,并将其称为BuildCommandModule方法来构建一个命令模块对象.我现在正在使用Ninject进行依赖注入,我想逐步删除此CommandModuleFactory,有利于将ICommandModule注入到控制器中,而无需控制器执行任何工作.
ICommandModule有一个方法定义,像这样:
public interface ICommandModule { object InvokeCommand(string command,List<string> args); }
InvokeCommand是执行自身反射以查找可能匹配传入命令的所有方法的方法.
然后我有五个不同的对象从ICommandModule继承(其中一些继承自其他模块,所以我们不重复命令):
AdministratorCommandModule继承自继承自BaseCommandModule的UserCommandModule的ModeratorCommandModule.
然后我还有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>(); } }
这里有几件事情发生.首先,Ninject模块取决于几件事情.它取决于一个布尔值,指示用户是否被认证(以确定它是否是其中一个登录命令模块或访问者命令模块).接下来它取决于字符串用户名和IUserRepository.这里是我的Mappings在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; }
在我加载Ninject模块以构建我的命令模块之前,我可以看到我将IUserRepository映射到其具体类型(尽量不要将Ninject绑定模块与我的命令模块混淆:S).然后我使用kernel.Get< IUserRepository>()来解决我的Ninject模块对它的依赖.
我的问题是HttpContext.Current.User为null.我不知道如何判断用户是否在Ninject绑定阶段登录.有任何想法吗?
当我进行Ninject绑定时,如何获得登录用户的引用?或者你能想到一个更好的方法来为我的ICommandModule做条件绑定吗?
任何帮助是赞赏!
解决方法
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>(); } }
然后绑定将被指定为
Kernel.Bind<ICommandModule>().ToProvider<CommandModuleProvider>();