2011-04-27 39 views
1

有谁知道是否有可能使用Ninject解决实例化过程之外的任何未解决的抽象依赖关系?我刚刚查看了构造函数注入vs属性/方法/字段注入,但它看起来好像Ninject仍然期望使用IKernel.Get <>()方法创建该类型。对象初始化后Ninject是否可以解析抽象依赖关系?

基本上,我们使用MVC3来构建我们的产品,我们想到了默认的ModelBinder将表单值映射到对象实例然后能够调用方法的情况在提交的ViewModel上依赖于抽象接口,例如

public class InviteFriend { 
    [Required] 
    public string EmailAddress { get; set; } 

    public void Execute() { 
     var user = IUserRepository.GetUser(this.EmailAddress); 

     if (user == null) { 
       IUserRepository.SaveInvite(this.EmailAddress); 
     } 

     MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties 
     SmtpClient.Send(toSend); 
    } 
} 

其中控制器操作将接收InviteFriend作为方法参数。我们希望Ninject能够解决IUserRepository依赖,但我不能完全解决如何,因为对象本身是由MVC模型绑定器,而不是Ninject IKernel.Get <>()实例化。

也许该解决方案是基于Ninject-ModelBinder的,或者这是否显得非常糟糕的主意?

编辑添加:经过下面的评论,我意识到我的匆忙模拟代码示例并不真正反映我们面临的。我更新了代码示例以反映InviteFriend.Execute()的逻辑比调用一个存储库上的方法更复杂。潜在地,这是表示可以协调多个不同域对象和多个存储库之间的交互的离散任务的逻辑。存储库被抽象地定义,理想情况下将由Ninject解决。

+0

我觉得这是好主意,在模型这样的方法 - 任何数据操作应由控制器完成。模型只应代表数据和数据。 – 2011-04-27 14:55:15

+0

我同意Lukas所说的控制器应该有IUserRepository和InviteFriend类应该只做它应该做的事:表示用户输入数据。 – 2011-04-27 21:09:10

+0

这会不会导致胖控制器呢?我的想法是,在ViewModel中使用这种逻辑,或者更好地称为命令式对象,可以将业务逻辑保留在域对象中,然后更容易重用,而不是将业务逻辑有效地放入Controller操作方法中留下复制粘贴样式代码重用的范围。通过这种方式,Silverlight/WP7应用程序可以重复使用相同的命令式对象,而不需要为相同的逻辑复制代码... – jonsidnell 2011-04-27 21:55:10

回答

0

感谢您对您的所有意见,但我后来发现我一直在寻找的信息。

答案是有可能注入依赖与Ninject,实例化后。该解决方案如下:

public class InviteFriend { 
    [Inject] 
    public IUserRepository UserRepo { get; set; } 

    [Required] 
    public string EmailAddress { get; set; } 

    public void Execute() { 
     var user = UserRepo.GetUser(this.EmailAddress); 

     if (user == null) { 
       UserRepo.SaveInvite(this.EmailAddress); 
     } 

     MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties 
     SmtpClient.Send(toSend); 
    } 
} 

与当时的客户端代码中使用Ninject内核如下:

IKernel container = new StandardKernel(new ModuleWithMyBindings()); 
container.Inject(instanceOfInviteFriend); 

代码本身比即我不是实例化一个新的iKernel更复杂一点每次我需要它。

我意识到这在结构上不如纯粹评论中提出的一些建议,但是本着YAGNI的精神,现在已经足够好了,以后我们可以随时重构Daniel的一些好建议回答。然而,这是一个关于Ninject的功能,而不是一个建筑评价问题的问题,这是我认为的答案我自己的问题:)

+0

很公平。采取的措施:D – 2011-05-04 18:18:23

4

我想你在找什么是有些以下情形:

public class InviteFriend { 
    [Required] 
    public string EmailAddress { get; set; } 

    // More information 
} 

public interface ICommand { 
    void Execute(); 
} 

public class InviteFriendCommand : ICommand 
{ 
    public InviteFriend(InviteFriend info, IUserRepository userRepo, IMailSender mailSender) { 
     this.inviteFriend = info; 
     this.userRepo = userRepo; 
     this.mailSender = mailSender; 
    } 

    public void Execute() { 
     var user = this.userRepo.GetUser(this.inviteFriend.EmailAddress); 

     if (user == null) { 
       this.userRepo.SaveInvite(this.inviteFriend.EmailAddress); 
     } 

     MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties 
     this.mailSender.Send(toSend); 
    } 
} 

public interface ICommandFactory { 
    ICommand CreateInviteFriendCommand(InviteFriend info); 
} 

public class CommandFactory { 

    public CommandFactory(IResolutionRoot resolutionRoot) { 
     this.resolutionRoot = resolutionRoot; 
    } 

    ICommand CreateInviteFriendCommand(InviteFriend info) { 
     this.resolutionRoot.Get<InviteFriendCommand>(new ConstructorArgument("info", info)); 
    } 
} 

public class YourController { 

    // Somewhere 

    var command = this.commandFactory.CreateInviteFriendCommand(info); 
    command.Execute(); 

} 

public class YourModule : NinjectModule { 

    override Load() { 
     Bind<IUserRepository>().To<UserRepo>().InRequestScope(); 
     Bind<ICommandFactory>().To<CommandFactory>().InRequestScope(); 
     Bind<InviteFriendCommand>().ToSelf().InRequestScope(); 
    } 
} 

原谅我,当你需要调整它一下。我用我的大脑进行编译的一起黑客攻击它;)

+0

+1,但想指出注入resolutinroot是一个坏消息 - 让容器泄漏太多。考虑绑定'Func '或使用Func模块@Remo Gloor给出了另一个答案(即将在2.3-4我相信) – 2011-04-28 19:40:29

+0

Hy Ruben,你说得对。我总是尝试使用Func <>方法。但有时这会变得复杂。这就是为什么我们在我的团队中决定工厂可以使用IResolutionRoot。 – 2011-04-30 10:41:10

+0

感谢您的评论 - 这绝对是一种更实用的方式来实现我所概述的InviteFriend命令,所以我将其视为一个很好的,经过深思熟虑的答案。然而,我没有接受它作为答案,因为我的问题是关于Ninject的能力,而不是解决方案的最佳体系结构。 感谢您抽出宝贵时间回答:) – jonsidnell 2011-05-03 14:13:35