Мы используем метод CreateClassProxy
для создания прокси для службы, как это было предложено в ответе на вопрос Castle Dynamic Proxy not intercepting method calls when invoked from within the class. Затем мы регистрируем полученный прокси как реализацию для интерфейса. Таким образом, наш метод пользовательских RegisterComponent
выглядит следующим образом
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var proxyType = new ProxyGenerator().CreateClassProxy<TImplementation>().GetType();
Container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
Полная регистрация компонент
Container = new WindsorContainer();
Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel));
// Interceptor
Container.Register(Component.For<IInterceptor>().ImplementedBy<SomeInterceptor>().LifestyleTransient());
// Component registrations
RegisterComponent<ISomeService, SomeService>();
И, конечно же, все методы, которые вы должны перехватывать должны быть virtual
, поскольку используется наследование на основе прокси.
Однако недостатком этого решения является то, что вы не могли использовать инъекцию конструктора при создании прокси-объекта. Обратите внимание, что вы создаете «пронумерованный» прокси-объект с оператором new
только для получения типа прокси-сервера. Поэтому вы не можете использовать инъекцию конструктора только при создании фиктивного прокси, но когда вы разрешаете свою службу через контейнер, инъекция будет работать нормально. Таким образом, этот недостаток имеет решающее значение только для компонентов с конструктивной логикой, которые сложнее, чем просто привязка зависимостей.Если вам нужно только assigments зависимостей вы можете попытаться решить все зависимости от контейнера вручную до создания манекена проксирования без проксирования
private object[] ResolveConstructorParameters<TType>()
{
return typeof(TType).GetConstructors()
.Single(c => c.IsPublic)
.GetParameters()
.Select(p => _container.Resolve(p.ParameterType))
.ToArray();
}
, а затем RegisterComponent
станет
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var constructorParameters = ResolveConstructorParameters<TImplementation>();
var proxyType = new ProxyGenerator().CreateClassProxy(typeof(TImplementation), constructorParameters).GetType();
_container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
Вы также можете просто заполнить аргументы null
.
Есть ли способ зарегистрировать сервис как интерфейс, но использовать перехват на основе наследства без этого взлома? Почему он отключен по умолчанию? – xumix
К сожалению, я не знаю ни о каком коммутаторе, который позволил бы вам поменять механизм перехвата по умолчанию, но я никогда не нуждался в этом, поэтому никогда не выглядел тяжело. Обычно я использую перехват служб уровня приложения, чтобы делать такие вещи, как управление транзакциями. Поэтому в моем случае это не имеет особого значения для такого поведения (например, если перехватчик уже открыл транзакцию во время вызова внешнего метода, я не хочу, чтобы это повторилось для вызова внутреннего метода). –
@ krzysztof-kozmic Итак, нет простого способа использовать перехват на основе Inheritance? – xumix