总而言之,我目前正在编写的应用程序应该模拟当前登录的用户。
这是一个管理信息查询的应用程序。
由于NHibernate.ISessionFactory
在连接字符串级别上不允许更多的灵活性,我需要使用当前用户凭据动态构建连接。 (顺便说一句,我不是在反对NH,我在每个项目上使用都很棒。)
所以,我需要在启动时强制进行身份验证。许多依赖项可能在启动时绑定,但不能绑定数据访问模块,这些依赖项需要在用户通过连接字符串进行身份验证后加载。
AuthenticationPresenter
告诉MembershipService
使用提供的凭据对用户进行身份验证; AuthetnicationUser
类的实例保留在MembershipService
内,而SessionFactoryProvider
又绑定在单一范围内; MembershipService.CurrentUser
依赖于我的CurrentUser
属性来检索用于构建连接字符串的凭据,因此Program
属性在此模块的加载时不能为空,因此我不能在应用程序启动时加载此模块而不会破坏某些内容。它是一个Windows窗体应用程序,因此我使用IKernel
类来实例化Ninject ISession
并加载应用程序启动所需的模块。
该应用程序稍后需要解析新的依赖项,例如数据访问,查询管理和依赖于CurrentUser
的存储库。
解决方案应该是能够加载需要在应用程序生命周期中稍后知道public class DataModule : NinjectModule {
public override void Load() {
Bind<ISessionFactory>().ToProvider<SessionFactoryProvider>().InSingletonScope();
Bind<ISession>().ToProvider<SessionProvider>();
Bind<IStatelessSession>().ToProvider<StatelessSessionProvider>();
}
}
的模块,或者使用上下文或条件依赖注入绑定。
DataModule的
public class ServiceModule : NinjectModule {
public override void Load() {
Bind<IMembershipService>().To<MembershipService>().InSingletonScope();
}
}
ServiceModule
public class AuthenticationModule : NinjectModule {
public override void Load() {
Bind<AuthenticationPresenter>().ToSelf().InSingletonScope();
Bind<IAuthenticationPresenterFactory>().ToFactory();
Bind<IAuthenticationView>().To<AuthenticationForm>();
}
}
AuthenticationModule
public class InquiriesManagementModule : NinjectModule {
public override void Load() {
Bind<IInquiriesManagementPresenterFactory>().ToFactory();
Bind<InquiriesManagementPresenter>().ToSelf().InSingletonScope();
Bind<IInquiriesManagementView>().To<InquiriesMgmtForm>();
Bind<ICancelInquiryPresenterFactory>().ToFactory();
Bind<CancelInquiryPresenter>().ToSelf();
Bind<ICancelInquiryView>().To<CancelInquiryForm>();
Bind<IEditInquiryPresenterFactory>().ToFactory();
Bind<EditInquiryPresenter>().ToSelf();
Bind<IEditInquiryView>().To<EditInquiryForm>();
Bind<INewInquiryPresenterFactory>().ToFactory();
Bind<NewInquiryPresenter>().ToSelf();
Bind<INewInquiryView>().To<NewInquiryForm>();
Bind<IInquiriesRepository>().To<InquiriesRepository>();
}
}
InquiriesManagementModule
ApplicationContext
如果您需要更多详细信息,请查看此问题:
Conditional dependency injection binding only when property not null
我还想过编写一个WithConstructorArgument
类,它可以包含当前用户的基本信息,以便将它传递给需要它的应用程序的演示者和提供者,但问题仍然存在。
所以我想知道这是一个设计缺陷还是缺乏依赖注入工具的知识,或者两者兼而有之。
修改
关注@Simon Whitehead的评论,
您是否考虑过使用
WithConstructorArgument
方法传入用户凭据?
由于以下几个原因,我没有想过使用[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
IKernel dependencies = new StandardKernel(
new ApplicationModule(),
new AuthenticationModule(),
new ServiceModule(),
new InquiriesManagementModule(),
new DataModule());
ApplicationPresenter applicationPresenter =
dependencies.Get<ApplicationPresenter>();
Application.Run((Form)applicationPresenter.View);
}
:
程序 (我决定去静态依赖注入工厂之前的情况)
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
DependencyInjectionFactory.Register(
new ApplicationModule(),
new AuthenticationModule(),
new ServiceModule());
ApplicationPresenter applicationPresenter =
DependencyInjectionFactory.Resolve<ApplicationPresenter>();
Application.Run((Form)applicationPresenter.View);
}
程序 (我现在如何使用静态依赖注入工厂)
{{1}}
除此之外,我觉得拥有一个静态依赖注入器是一个肮脏的解决方案,因为它可以通过魔术从任何地方调用......
我是否将它推得太远以至于我使事情复杂化而不是简化它们?
答案 0 :(得分:1)
您根本不需要条件或上下文绑定。 转而采用最简单的方法: 编写nhibernate配置,会话,......好像你没有运行时&#34;计时&#34;依赖。这意味着:将经过身份验证的用户注入NHibernate配置构建器。
然后,您只需要确保在对用户进行身份验证之前,不依赖于任何NHibernate的对象树部分进行实例化。这应该很容易。
使用任何类型的引导机制,首先创建绑定,然后显示登录窗口,登录,成功登录后,加载(显示)应用程序的其余部分。
结合:
IBindingRoot.Bind<Configuration>().ToProvider<ConfigurationProvider>();
IBIndingRoot.Bind<ISessionFactory>()
.ToMethod(ctx => ctx.Kernel.Get<Configuration>().BuildSessionFactory())
.InSingletonScope();
public class ConfigurationProvider : IProvider<Configuration>
{
private readonly IUserService userService;
public ConfigurationProvider(IUserService userService)
{
this.userService = userService;
}
public object Create(IContext context)
{
if(this.userService.AuthenticatedUser == null)
throw new InvalidOperationException("never ever try to use NHibernate before user is authenticated! this includes injection an ISessionFactory in any class! Postpone creationg of object tree until after authentication of user. This exception means you've produced buggy code!");
return Fluently.Configure()
.DataBase(MsSqlConfiguration.MsSql2008)
.ConnectionString(connectionBuilder => connectionBuilder.Is(... create the string...)
....
.BuildConfiguration();
}
}