Может ли Ninject разрешать абстрактные зависимости после инициализации объекта? - PullRequest
1 голос
/ 27 апреля 2011

Кто-нибудь знает, возможно ли использовать Ninject для разрешения любых неразрешенных абстрактных зависимостей вне процесса создания экземпляра? Я только что посмотрел на внедрение конструктора против внедрения свойства / метода / поля, но мне кажется, что Ninject все еще ожидает быть создателем типа с использованием метода IKernel.Get <> ().

По сути, мы используем MVC3 для создания нашего продукта, и мы столкнулись с ситуацией, когда мы хотим, чтобы ModelBinder по умолчанию отображал значения формы на экземпляр объекта, а затем мог вызывать метод для представленная модель представления, которая зависит от абстрактного интерфейса, например

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 <> ().

Может быть, решение - это ModelBinder на основе Ninject, или это действительно плохая идея?

РЕДАКТИРОВАТЬ В ДОБАВИТЬ: После комментариев ниже я понимаю, что мой поспешно смоделированный пример кода на самом деле не отражает то, с чем мы столкнулись. Я обновил пример кода, чтобы отразить, что логика для InviteFriend.Execute () является более сложной, чем просто вызов метода в одном репозитории. Потенциально это логика, представляющая дискретную задачу, которая могла бы координировать взаимодействия между несколькими различными объектами домена и несколькими хранилищами. Репозитории определены абстрактно, и в идеале это должно быть разрешено Ninject.

Ответы [ 2 ]

4 голосов
/ 28 апреля 2011

Я думаю, что вы ищете несколько следующий сценарий:

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 голосов
/ 03 мая 2011

Спасибо за все ваши комментарии, но впоследствии я нашел информацию, которую искал.

Ответ заключается в том, что с помощью 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, на данный момент это достаточно хорошо, и мы всегда можем позже провести рефакторинг с некоторыми из хороших предложенийв ответе Даниэля.Однако, это был вопрос о возможностях Ninject, а не вопрос архитектурного обзора, и это то, что я считаю ответом на свой вопрос:)

...