#unity-container #aop #unity-interception
#unity-контейнер #aop #unity-перехват
Вопрос:
Я нахожусь в процессе значительных усилий по внедрению NHibernate в нашу кодовую базу. Я подумал, что мне придется использовать какой-то контейнер DI, чтобы я мог внедрять зависимости в объекты, которые я загружаю из базы данных. Я выбрал Unity в качестве этого контейнера.
Я рассматриваю возможность использования механизма перехвата Unity для добавления аспекта транзакции в мой код, чтобы я мог сделать, например, следующее:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
}
}
и [Transaction]
обработчик позаботится о создании сеанса и транзакции, фиксации транзакции (или откате исключения) и т.д.
Я обеспокоен тем, что использование такого рода перехвата привяжет меня к использованию Unity практически везде в коде. Если я введу аспекты таким образом, то я никогда не должен вызывать new SomeService()
, или я получу службу, у которой нет транзакций. Хотя это приемлемо в производственном коде, в тестах это кажется слишком большими накладными расходами. Например, мне пришлось бы преобразовать это:
void TestMethod()
{
MockDependency dependency = new MockDependency();
dependency.SetupForTest();
var service = SomeService(dependency);
service.DoSomething();
}
в это:
void TestMethod()
{
unityContainer.RegisterType<MockDependency>();
unityContainer.RegisterType<IDependency, MockDependency>();
MockDependency dependency = unityContainer.Resolve<MockDependency>();
dependency.SetupForTest();
var service = unityContainer.Resolve<SomeService>();
service.DoSomething();
}
Это добавляет 2 строки для каждого используемого мной макетного объекта, что приводит к довольно большому объему кода (в наших тестах используется много макетов с отслеживанием состояния, поэтому нередко в тестовом классе бывает 5-8 макетных объектов, а иногда и больше.)
Я не думаю, что автономное внедрение помогло бы здесь: я должен настроить внедрение для каждого класса, который я использую в тестах, потому что аспекты могут быть добавлены в класс после написания теста.
Теперь, если я откажусь от использования перехвата, я получу:
class SomeService
{
public void DoSomething(CustomerId id)
{
Transaction.Run(
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
что, по общему признанию, не так приятно, но и не кажется таким уж плохим.
Я даже могу настроить перехват моего собственного бедняка:
class SomeService
{
[Transaction]
public void DoSomething(CustomerId id)
{
Interceptor.Intercept(
MethodInfo.GetCurrentMethod(),
() => {
Customer c = CustomerRepository.LoadCustomer(id);
c.DoSomething();
});
}
}
и тогда мой перехватчик может обрабатывать атрибуты для класса, но я все еще могу создать экземпляр класса с помощью new
и не беспокоиться о потере функциональности.
Есть ли лучший способ использования Unity interception, который не заставляет меня всегда использовать его для создания экземпляров моих объектов?
Комментарии:
1. @Mat, я бы с этим не согласился. Я вижу некоторое сходство между этим и некоторыми примерами «о чем не спрашивать», это все еще хорошо написанный и обоснованный вопрос. Он не спрашивает «Какой наш любимый инструмент AOP», а говорит «Я рассматриваю возможность использования Unity, но у меня есть некоторые опасения, какой опыт у людей от его использования может помочь мне решить, стоит ли это». Возможно, это погранично, но ИМО это достаточно хорошо, чтобы иметь достоинства и не быть закрытым.
2. @Mat Вопрос касается конкретной проблемы, которую я испытываю при использовании Unity, а не общего вопроса о том, стоит ли AOP. Я отредактировал последнюю строку вопроса, чтобы отразить это.
Ответ №1:
Если вы хотите использовать AOP, но беспокоитесь о Unity, я бы порекомендовал вам проверить PostSharp. Это реализует AOP как проверку после компиляции, но не вносит изменений в то, как вы используете код во время выполнения.
У них есть бесплатная версия для сообщества с хорошим набором функций, а также профессиональные и корпоративные версии со значительно расширенными наборами функций.