有没有人知道是否可以使用Ninject来解析实例化过程之外的任何未解决的抽象依赖项?我刚刚研究构造函数注入vs属性/方法/字段注入,但它看起来好像Ninject仍然期望使用IKernel.Get<>()方法成为该类型的创建者。
基本上,我们使用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 ModelBinder实例化对象本身,而不是Ninject IKernel.Get<>()。
也许解决方案是基于Ninject的ModelBinder,或者这看起来真是个坏主意?
编辑添加:在下面的评论之后,我意识到我匆匆嘲笑的代码示例并没有真正反映出我们面临的问题。我已经更新了代码示例,以反映InviteFriend.Execute()的逻辑比仅在一个存储库上调用方法更复杂。潜在地,这是表示可以协调多个不同域对象和多个存储库之间的交互的离散任务的逻辑。存储库是抽象定义的,理想情况下将由Ninject解决。
答案 0 :(得分: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();
}
}
当你需要调整一下时,请原谅我。我和我的大脑编译器一起攻击它;)
答案 1 :(得分: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的能力而不是建筑评论问题的问题,这就是我认为我自己的问题的答案:)