2011-04-27 41 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