Unity - Как регистрировать типы, используя базовый тип - PullRequest
1 голос
/ 14 апреля 2011

У меня есть базовый класс и несколько производных классов. Базовый класс содержит свойство, которое необходимо ввести. Как настроить 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 result;
    }

    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 для этого?

Ответы [ 2 ]

2 голосов
/ 14 апреля 2011

Вы можете использовать UnitiContainer.BuildUp для внедрения зависимостей в существующий объект.Если у вас есть небольшой предопределенный набор значений для параметра конструктора, вы можете использовать класс 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 голос
/ 14 апреля 2011

Я пытаюсь избежать этой ситуации, структурируя такие вещи:

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.Net, если вы так катаетесь.

Поскольку метод 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);
}

Вы можете использовать похожую технику для добавления дополнительных действий, таких как ведение журнала, обработка исключений и безопасность.

...