C# 如何根据用户选择Ninject绑定?
这个问题需要一点背景知识才能理解,所以我将从项目的描述开始 项目背景 我有一个开源项目,它是一个命令提示符风格的网站(,)。该项目是在ASP.NET MVC 3中构建的,并使用实体框架4。基本上,站点允许您传入命令和参数,然后站点返回一些数据。这个概念相当简单,但我不想使用一个巨大的IF语句来处理命令。相反,我决定做一些独特的事情,构建一个对象,其中包含所有可能的命令作为对象上的方法 站点使用反射来定位与发送的命令相对应的方法并执行它们。此对象是基于当前用户动态构建的,因为某些用户可以访问与其他用户不同的命令(例如,管理员拥有多个版主,而MOD拥有多个用户,等等) 我构建了一个自定义的C# 如何根据用户选择Ninject绑定?,c#,asp.net-mvc,asp.net-mvc-3,dependency-injection,ninject,C#,Asp.net Mvc,Asp.net Mvc 3,Dependency Injection,Ninject,这个问题需要一点背景知识才能理解,所以我将从项目的描述开始 项目背景 我有一个开源项目,它是一个命令提示符风格的网站(,)。该项目是在ASP.NET MVC 3中构建的,并使用实体框架4。基本上,站点允许您传入命令和参数,然后站点返回一些数据。这个概念相当简单,但我不想使用一个巨大的IF语句来处理命令。相反,我决定做一些独特的事情,构建一个对象,其中包含所有可能的命令作为对象上的方法 站点使用反射来定位与发送的命令相对应的方法并执行它们。此对象是基于当前用户动态构建的,因为某些用户可以访问与其他
CommandModuleFactory
,它将在MVC控制器中创建,并将调用它的BuildCommandModule
方法来构建一个命令模块对象。我现在使用Ninject进行依赖项注入,我想逐步淘汰这个CommandModuleFactory
,支持在控制器不做任何工作的情况下将ICommandModule
注入控制器
ICommandModule
定义了一个方法,如下所示:
public interface ICommandModule
{
object InvokeCommand(string command, List<string> args);
}
这里发生了几件事。首先,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;
}
protectedoverride IKernel CreateKernel()
{
var kernel=新的标准内核();
kernel.Bind().To();
kernel.Bind().To();
kernel.Bind().To();
kernel.Bind().To();
Load(新的BuildCommandModule(User.Identity.IsAuthenticated,User.Identity.Name,kernel.Get());
返回内核;
}
您可以看到,在加载Ninject模块以构建命令模块之前,我将IUserRepository
映射到它的具体类型(尽量不要将Ninject绑定模块与命令模块混淆:S)。然后我使用kernel.Get()
来解决Ninject模块对它的依赖关系
我这里的问题是HttpContext.Current.User
为空。我不知道如何判断用户是否在Ninject绑定阶段登录。有什么想法吗
在进行Ninject绑定时,如何获取登录用户的引用?或者,您能为我的
ICommandModule
想出一个更好的方法来进行条件绑定吗?您应该使用提供程序,而不是将逻辑放入模块中。首先,您可以创建一个类似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>();
}
}
公共类CommandModuleProvider:IPProvider
{
公共类型类型{get{return typeof(ICommandModule);}
创建公共对象(IContext上下文)
{
var securityInfo=context.Kernel.Get();
如果(securityInfo.IsAuthenticated)
if(securityInfo.IsCurrentUserAdministrator)
//加载管理员命令模块
返回context.Kernel.Get();
else if(securityInfo.IsCurrentUserModerator)
//加载调节器命令模块
返回context.Kernel.Get();
其他的
//加载用户命令模块
返回context.Kernel.Get();
其他的
//加载访问者命令模块
返回context.Kernel.Get();
}
}
然后指定绑定,如下所示
Kernel.Bind<ICommandModule>().ToProvider<CommandModuleProvider>();
Kernel.Bind().ToProvider();
应用程序中运行的内核数量应该(非常)有限:大多数情况下最好只有一个。与其尝试为每个用户创建新内核,不如让绑定为每个用户生成不同的实现。正如瓦迪姆指出的那样,这可以使用i提供程序s来完成。以下是同一想法的变体:
public override void Load()
{
Bind<ICommandModule>().ToMethod(
c =>
{
var sessionManager = c.Kernel<ISessionManager>();
if (!sessionManager.IsAuthenticated)
return c.Kernel.Get<VisitorCommandModule>();
var currentUser = sessionManager.CurrentUser;
if (currentUser.IsAdministrator)
return c.Kernel.Get<AdministratorCommandModule>();
if (currentUser.IsModerator)
return c.Kernel.Get<ModeratorCommandModule>();
return c.Kernel.Get<UserCommandModule>();
}).InRequestScope();
}
public override void Load()
{
Bind().ToMethod(
c=>
{
var sessionManager=c.Kernel();
如果(!sessionManager.IsAuthenticated)
返回c.Kernel.Get();
var currentUser=sessionManager.currentUser;
if(currentUser.IsAdministrator)
返回c.Kernel.Get();
if(currentUser.IsModerator)
返回c.Kernel.Get();
返回c.Kernel.Get();
}).InRequestScope();
}
在这个实现中,我希望用一个类来实现ISessionManager
,该类检查当前的HttpContext
,以确定谁登录,并提供有关此人的基本信息
InRequestScope()
现在驻留在Ninject.Web.Common
库中,这将有助于避免每个请求重复执行所有这些逻辑一次以上。我看到您正在从此提供程序重新调用ICommandModule。我以前没用过。您能给我举个例子说明绑定发生在哪里,以及我将在哪里使用/创建这个IProvider吗?另外,这个SecurityInformation类如何知道用户已登录?为什么这个类是必需的?@Chevex,我已经更新了答案,让你看看绑定。Ninject只会在需要ICommandModule时使用提供程序。Secu
public override void Load()
{
Bind<ICommandModule>().ToMethod(
c =>
{
var sessionManager = c.Kernel<ISessionManager>();
if (!sessionManager.IsAuthenticated)
return c.Kernel.Get<VisitorCommandModule>();
var currentUser = sessionManager.CurrentUser;
if (currentUser.IsAdministrator)
return c.Kernel.Get<AdministratorCommandModule>();
if (currentUser.IsModerator)
return c.Kernel.Get<ModeratorCommandModule>();
return c.Kernel.Get<UserCommandModule>();
}).InRequestScope();
}