У меня есть цепочка зависимостей, которая выглядит примерно так:
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
. Поэтому я решил использовать некоторые контекстные привязки. На первый взгляд 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
для операторов привязки, поэтому я придумал это как свои операторы привязки:
//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.
Извините за длинное пояснение.
Вот мой вопрос: Есть ли причина, почему я не должен подходить к проблеме таким образом?Считается ли это дурным тоном? Есть ли лучший способ найти типы запросов предков? Должен ли я реструктурировать свою цепочку классов/зависимостей в более «приемлемом» стиле?