#c# #ninject
#c# #ninject
Вопрос:
Сегодня я обновил нашу зависимость Ninject с 3.3.4 до 4.0.0-beta-0134, но теперь она выдает исключение циклической зависимости в шаблоне декоратора:
`Необработанное исключение: Ninject.Исключение ActivationException: ошибка при активации Program IService с использованием условной привязки Program IService к Program Service Между конструкторами двух сервисов была обнаружена циклическая зависимость.
Путь активации: 2) Внедрение программы зависимостей IService в службу параметров конструктора типа Program ServiceDecorator
- Запрос для Program IService
Предложения:
- Убедитесь, что вы не объявили зависимость для Program IService ни от одной реализации сервиса.
- Рассмотрите возможность объединения сервисов в один, чтобы удалить цикл.
- Используйте внедрение свойств вместо внедрения конструктора и реализуйте IInitializable, если вам нужно, чтобы логика инициализации выполнялась после ввода значений свойств. `
Вот пример кода:
public static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new IocConfig());
kernel.Get<IService>().Serve();
}
internal interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { }
}
public class ServiceDecorator : IService
{
private readonly IService _service;
public ServiceDecorator(IService service) => _service = service;
public void Serve() => _service.Serve();
}
public class IocConfig : NinjectModule
{
public override void Load()
{
Bind<IService>().To<Service>().WhenInjectedInto<ServiceDecorator>().InSingletonScope();
Bind<IService>().To<ServiceDecorator>().InSingletonScope();
}
}
Похоже, что ему не нравится использование WhenInjectedInto
в NinjectModule. Я нашел другие подобные вопросы, но ни WhenInjectedInto
один из них не работал.
Один из способов исправить это — изменить тип параметра сервиса с IService
на Service
на, но это устраняет большую часть причин использования декоратора.
Кто-нибудь из вас знает о другом решении / обходном пути?
Ответ №1:
После выполнения еще одного прохода может показаться, что проблема на самом деле вызвана использованием .WhenInjectedInto<ServiceDecorator>
, поскольку между привязками нет различий.
Альтернативой является простое использование Bind<IService>().To<Service>().InSingletonScope();
, а затем добавление a BindingConfiguration.Condition
в ваш декоратор для обработки Get<ServiceDecorator>()
варианта использования:
public static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(new IocConfig());
kernel.Get<IService>().Serve();
kernel.Get<ServiceDecorator>().Serve();
}
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { Console.WriteLine("service"); }
}
public class ServiceDecorator : IService
{
private readonly IService _service;
public ServiceDecorator(IService service) => _service = service;
public void Serve() { Console.WriteLine("decorator"); _service.Serve(); }
}
public class IocConfig : NinjectModule
{
public override void Load()
{
Bind<IService>().To<Service>().InSingletonScope();
Bind<IService>().To<ServiceDecorator>().InSingletonScope().BindingConfiguration.Condition =
(Ninject.Activation.IRequest request) =>
request.Service == typeof(ServiceDecorator);
}
}
Комментарии:
1. Спасибо, Дэвид! Это именно то, что я ищу! Работает для меня.
Ответ №2:
Неясно, как вы собираетесь использовать декоратор из этого примера, но одной из возможностей было бы применить новый интерфейс к декоратору, который, в свою очередь, наследуется от IService
.
public interface IServiceDecorator : IService { }
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve() { }
}
public class ServiceDecorator : IServiceDecorator
{
private readonly IService _service;
public ServiceDecorator(IService service) => _service = service;
public void Serve() => _service.Serve();
}
public class IocConfig : NinjectModule
{
public override void Load()
{
Bind<IService>().To<Service>().InSingletonScope();
Bind<IService>().To<Service>().WhenInjectedInto<ServiceDecorator>().InSingletonScope();
Bind<IServiceDecorator>().To<ServiceDecorator>().InSingletonScope();
}
}
Комментарии:
1. Интересно, что это создало бы множество стандартных интерфейсов, которых было бы очень приятно избежать… Спасибо за ваш вклад!