На SO есть несколько вопросов, которые похожи, но не совсем то, что я ищу. Я хотел бы выполнить привязку Ninject на основе условия выполнения, которое заранее неизвестно при запуске. Другие вопросы о SO для динамической привязки вращаются вокруг привязки на основе файла конфигурации или чего-то подобного - мне нужно, чтобы это происходило условно на основе значения базы данных при обработке данных для определенного объекта. Например.,
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
В другом месте у меня есть 2 dll, которые реализуют IExport.
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
Затем для партнера Б;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
Текущая привязка Ninject:
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, как со статически привязанными объектами?
ОБНОВЛЕНИЕ: я обновил свой код с помощью решения 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>();
Создание экземпляров реализации экспорта в двух тестовых модулях работает и отлично создает экземпляр контекста PADBEntites
. Однако все другие привязки на моем уровне служб теперь больше не работают для остальной части системы. Точно так же я не могу привязать слой экспорта, если я изменю аргумент PADBEntities
variable/ctor на компонент ISomeEntityService. Кажется, я пропустил последний шаг в настройке привязок, чтобы получить эту работу. Есть предположения?
Ошибка: «Ошибка активации ISomeEntityService. Нет доступных привязок, и тип не является самопривязываемым»
Обновление 2: в конце концов, путем проб и ошибок, используя решение BatteryBackupUnit
, я получил это, хотя я не слишком доволен обручами, чтобы прыгать с мысли. Любое другое более лаконичное решение приветствуется.
Я изменил исходную привязку соглашения;
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
дважды. Для первого соглашения вы должны были исключить всеIExport
. Я предлагаю вам создать новый вопрос о том, как сформировать вопрос. Возможно, другая платформа SE, такая как codereview или программисты, была бы лучше. Предложение. Почему бы не ввести соглашение для всех типов, оканчивающихся наService
, и специально связать все остальные? Кроме того, если есть более конкретные привязки, их можно поместить вNinjectModule
в конкретных сборках. - person BatteryBackupUnit   schedule 07.09.2015IExport
и того, как разработать обычные привязки, следует разделить. как спроектировать обычные привязки, не подходит для SO. Конкретный вопрос => как исключить тип хорошо подходит для SO. Ответ: вы можете использовать методWhere
filter для исключения всех типов, реализующихIExport
. Дополнительную информацию о соглашениях см. также здесь - person BatteryBackupUnit   schedule 07.09.2015