Есть несколько вопросов о SO, которые похожи, но не совсем то, что я ищу. Я хотел бы сделать привязку Ninject на основе условия выполнения, которое не было известно при запуске. Другие вопросы о SO для динамического связывания вращаются вокруг привязки на основе файла конфигурации или некоторых таких - мне нужно, чтобы это произошло условно на основе значения базы данных при обработке данных для определенного объекта. НАПРИМЕР,Ninject динамически привязывается к реализации
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
В другом месте, у меня есть 2 DLLs, которые реализуют IExport
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
Тогда для партнера B;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
Нисходящее связывание;
public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}
Итак, как мне настроить привязки, которые я могу сделать;
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
Возможно ли это? Похоже, должно быть, но я не могу понять, как это сделать. Существующая конфигурация связывания выше отлично работает для статических привязок, но мне нужно что-то, что я могу решить во время выполнения. Возможно ли это выше, или мне просто придется обходить Ninject и загружать плагины, используя отражение старой школы? Если да, то как я могу использовать этот метод для разрешения любых аргументов конструктора через Ninject, как со статически связанными объектами?
UPDATE: Я обновил свой код с помощью решения BatteryBackupUnit
, чтобы у меня теперь было следующее:
Bind<PADBEntities>().ToSelf().InRequestScope();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
.Configure(c => c.InRequestScope())
);
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.Modules.*.dll")
.SelectAllClasses()
.InheritedFrom<IExportService>()
.BindSelection((type, baseTypes) => new[] { typeof(IExportService) })
);
Kernel.Bind<IExportServiceDictionary>().To<ExportServiceDictionary>().InSingletonScope();
ExportServiceDictionary dictionary = KernelInstance.Get<ExportServiceDictionary>();
Инстанцирование реализаций экспорта в пределах 2 тестовых модулей работ инстанцирует PADBEntites
контекст просто отлично. Тем не менее, все остальные привязки на моем уровне услуг теперь больше не работают для остальной части системы. Аналогично, я не могу связать уровень экспорта, если я изменяю аргумент переменной/ctor PADBEntities
компоненту ISomeEntityService. Кажется, я пропустил последний шаг в настройке привязок, чтобы получить эту работу. Есть предположения?
Ошибка: «Ошибка активация ISomeEntityService Нет соответствующие привязки не доступны, и тип не является самим-Привязываемым.»
Update 2: В конце концов получила эту работу с небольшим количеством проб и ошибок с использованием BatteryBackupUnit
«s решения хотя я не слишком доволен обручами, чтобы передумать. Любое другое более сжатое решение приветствуется.
Я изменил первоначальную конвенцию;
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
к гораздо более подробному и явному;
Bind<IActionService>().To<ActionService>().InRequestScope();
Bind<IAuditedActionService>().To<AuditedActionService>().InRequestScope();
Bind<ICallService>().To<CallService>().InRequestScope();
Bind<ICompanyService>().To<CompanyService>().InRequestScope();
//...and so on for 30+ lines
Не мое любимое решение, но оно работает с явным и основанным на соглашениях привязкой, но не с двумя соглашениями. Может ли кто-нибудь увидеть, где я ошибаюсь в привязке?
Обновление 3: Не обращайте внимания на проблему с привязками в обновлении 2. По-видимому, я обнаружил ошибку в Ninject, связанную с наличием нескольких связующих модулей в справочной библиотеке.Изменение модуля A, даже если оно не попало через точку останова, будет явно разбивать проект с использованием другого модуля B. Перейдите к рисунку.
ИМО, ответы ниже все реализации той или иной форме фабрика, что является правильным ответом. Внесите завод, позвольте фабрике вернуть правильный IExport. Несмотря на некоторые (проницательные) комментарии в ответах ниже, наличие этого на заводе помогает изолировать вас от конкретных функций. –
@Atoms, ninject здесь несколько требуется, так как реализациям экспорта требуются другие сервисы в их ctors, которые уже связаны через ядро ninject.Имеет смысл повторно использовать их, а не реализовывать конкретную фабрику. – DiskJunky
Использование соглашения из двух частей, в котором отсутствует привязка? Также обратите внимание, что с помощью соглашения из двух частей вы бы связали каждый «IExport» дважды. Для первого соглашения вы должны были исключить все 'IExport'. Я предлагаю вам задать новый вопрос в отношении того, как формировать вопрос. Может быть, другая платформа SE, такая как codereview или программисты, будет лучше. ** Предложение **: Почему бы не иметь соглашение для всех типов, заканчивающихся в «Сервис», и, в частности, связать все остальное? Более того, если есть более конкретные привязки, они могут быть помещены в 'NinjectModule' в конкретных сборках. – BatteryBackupUnit