#c# #.net #unity-container #enterprise-library #ioc-container
#c# #.net #unity-контейнер #корпоративная библиотека #ioc-контейнер
Вопрос:
У меня есть базовый класс и несколько производных классов. Базовый класс содержит свойство, которое необходимо ввести. Как мне настроить Unity для построения моих объектов?
public class BaseService<T> where T : class
{
public T Entity { get; private set; }
[Dependency]
public IUnitOfWork UnitOfWork { get; private set; }
public BaseService(T obj)
{
this.Entity = obj;
}
}
public class ContactService : BaseService<Contact>
{
public ContactService(Contact obj) : base(obj)
{
}
public bool IsValid()
{
bool result = false;
// ...
return resu<
}
public void AddContact()
{
if (!IsValid()) { throw new InvalidEntityException<Contact>(); }
try
{
this.UnitOfWork.BeginTransaction();
this.UnitOfWork.Add<Contact>(this.Entity);
this.UnitOfWork.CommitTransaction();
}
catch
{
this.UnitOfWork.RollbackTransaction();
}
}
}
Как мне зарегистрировать это в первую очередь, а затем как мне разрешить ContactService, поскольку у него есть конструктор с аргументами, которые нельзя ввести? Должен ли я вообще использовать Unity для этого?
Ответ №1:
Вы можете использовать UnitiContainer.Наращивание для внедрения зависимостей в существующий объект. Если у вас есть небольшой заранее определенный набор значений для вашего параметра конструктора, вы можете использовать класс InjectionConstructor, чтобы указать значение параметра во время регистрации. В противном случае зарегистрируйте фабричный класс в Unity и используйте его для создания своих сервисов.
public class ContactServiceFactory
{
IUnitOfWork UnitOfWork { get; private set; }
public ContractServiceFactory(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public ContactService Create(Contact obj)
{
return new ContractService(obj, unitOfWork);
}
}
Комментарии:
1. 1 Я думал о фабрике. Я собираюсь изучить создание и регистрацию фабрики, но я собираюсь использовать больше абстракции, так что, надеюсь, я смогу получить это, все еще используя эти методы.
2. На самом деле, подумав об этом, фабрика, вероятно, лучше контролировать абстракцию и действительно держать IoC домена в неведении.
Ответ №2:
Я пытаюсь избежать этой ситуации, структурируя подобные вещи следующим образом:
public class ContactService : IContactService
{
private readonly IContactRepository repository;
private readonly IValidator<Contact> validator;
private readonly IUnitOfWork unitOfWork;
public ContactService(
IContactRepository repository,
IValidator<Contact> validator,
IUnitOfWork unitOfWork)
{
this.repository = repository;
this.validator = validator;
this.unitOfWork = unitOfWork;
}
public void Add(Contact contact)
{
if (!validator.IsValid(contact)) throw new ArgumentException();
try
{
unitOfWork.Start();
repository.Save(contact);
unitOfWork.Commit();
}
catch
{
unitOfWork.Rollback();
throw;
}
}
}
Используя этот базовый шаблон, Unity может создать ваш сервис со всеми его зависимостями, и у вас не возникнет проблемы с внедрением контакта. Репозиторий можно использовать как абстракцию или просто напрямую использовать вашу любимую платформу доступа к данным, такую как EF, NHibernate или старый добрый Ado.Нет, если вы так действуете.
Поскольку материал try catch является повторяющимся, вы можете использовать метод расширения для сжатия вашего кода следующим образом:
public void Add(Contact contact)
{
if (!validator.IsValid(contact)) throw new ArgumentException();
unitOfWork.Execute(() => repository.Save(contact));
}
Метод расширения выглядит следующим образом:
public static class UnitOfWorkExtensions
{
public static void Execute(this IUnitOfWork unitOfWork, Action action)
{
try
{
unitOfWork.Start();
action.Invoke();
unitOfWork.Commit();
}
catch
{
unitOfWork.Rollback();
throw;
}
}
}
Подробнее об этом:http://www.agileatwork.com/refactoring-c-style /
Большое преимущество структурирования вашего кода таким образом заключается в том, что вы можете воспользоваться механизмом перехвата Unity и сделать много интересных вещей, таких как перемещение единицы рабочего кода в аспект (атрибут):
[UnitOfWork]
public void Add(Contact contact)
{
if (!validator.IsValid(contact)) throw new ArgumentException();
repository.Save(contact);
}
Вы можете использовать аналогичный метод для добавления дополнительных функций, таких как ведение журнала, обработка исключений и безопасность.
Комментарии:
1. Да, перенастройка конструктора, чтобы не требовать контакта, лучше, поскольку в моем случае сервис является не более чем оболочкой для рабочих процессов, поэтому нет необходимости вводить контакт в конструкторе, поскольку я не поддерживаю никакого состояния. Спасибо!