У меня есть цепочка зависимостей, которая выглядит примерно так:
public class CarSalesBatchJob
{
public CarSalesBatchJob(IFileProvider fileProvider)
{ ... }
}
public class MotorcycleSalesBatchJob
{
public MotorcycleSalesBatchJob(IFileProvider fileProvider)
{ ... }
}
public class FtpFileProvider : IFileProvider
{
public FtpFileProvider(IFtpSettings settings)
{ ... }
}
public class CarSalesFtpSettings : IFtpSettings { ... }
public class MotorcycleSalesFtpSettings : IFtpSettings { ... }
До сих пор я использовал привязки, основанные на соглашениях, но это уже недостаточно хорошо, потому что у меня есть более одной реализации для IFtpSettings
. Поэтому я решил использовать некоторые контекстные привязки. Сначала blush kernel.Bind<>().To<>().WhenInjectedInto<>()
выглядел многообещающим, но это помогает только на первом уровне, а это значит, что если бы у меня были CarSalesFtpFileProvider
и MotorcycleSalesFtpProvider
, я мог бы это сделать:
kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
.WhenInjectedInto<CarSalesFtpFileProvider>();
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
.WhenInjectedInto<MotorcycleSalesFtpFileProvider>();
Но, кажется, довольно глупо создавать две конкретные реализации FtpFileProvider
, которые действительно отличаются только тем, какие настройки я хочу использовать. Я видел, что существует метод под названием WhenAnyAnchestorNamed(string name)
. Но этот маршрут требует, чтобы я добавлял атрибуты и магические строки в свои пакетные задания, о которых я не волнуюсь.
Я также заметил, что существует простой старый метод .When(Func<IRequest, bool>)
для операторов привязки, поэтому я придумал это как мои обязательные утверждения:
//at this point I've already ran the conventions based bindings code so I need to unbind
kernel.Unbind<IFtpSettings>();
kernel.Bind<IFtpSettings>().To<CarSalesFtpSettings>()
.When(r => HasAncestorOfType<CarSalesBatchJob>(r));
kernel.Bind<IFtpSettings>().To<MotorcycleSalesFtpSettings>()
.When(r => HasAncestorOfType<MotorcycleSalesBatchJob>(r));
// later on in the same class
private static bool HasAncestorOfType<T>(IRequest request)
{
if (request == null)
return false;
if (request.Service == typeof(T))
return true;
return HasAncestorOfType<T>(request.ParentRequest);
}
Итак, если конструктор запрашивает IFtpSettings, мы рекурсируем дерево запроса, чтобы узнать, соответствует ли какая-либо из запрошенных услуг/типов в цепочке предоставленный тип (CarSalesBatchJob или MotorcycleSalesBatchJob), и если так возвращает true. Если мы добираемся до вершины цепочки, мы возвращаем false.
Извините за подробное объяснение.
Вот мой вопрос: есть ли какая-то причина, почему я не должен обращаться к проблеме таким образом? Является ли это плохой формой? Есть ли лучший способ поиска типов запросов предков? Должен ли я перестроить свою цепочку классов/зависимостей на более "приятный" способ?