Тип IUnitOfWork не имеет доступного конструктора с Umbraco 6.1, UmbracoApiController (веб-API) и внедрением зависимостей (Unity).

Я использую Umbraco 6.1 с UmbracoApiController, в конструктор которого внедрен IUnitOfWork. Для внедрения зависимостей я использую Unity, как и раньше со стандартными проектами Web API. Обычно я устанавливаю единство в файле Global.asax.cs. Поскольку в Umbraco этого нет, я создал свой собственный обработчик UmbracoEvents, который наследуется от IApplicationEventHandler и имеет следующие методы:

  1. OnApplicationInitialized
  2. OnApplicationStarting
  3. OnApplicationStarted
  4. Конфигапи

В методе OnApplicationStarted я настраиваю свою базу данных EF, инициализатор db и т. д. и вызываю ConfigureApi для настройки Unity. Мои методы OnApplication Started и ConfigureApi выглядят так:

    public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
    {
        _applicationContext = applicationContext;
        _umbracoApplication = umbracoApplication;
        _contentService = ApplicationContext.Current.Services.ContentService;
        this.ConfigureApi(GlobalConfiguration.Configuration);
        Database.SetInitializer(null);
        PropertySearchContext db = new PropertySearchContext();
        db.Database.Initialize(true);
    }

    private void ConfigureApi(HttpConfiguration config)
    {
        var unity = new UnityContainer();
        unity.RegisterType<PropertiesApiController>();
        unity.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
        config.DependencyResolver = new IoCContainer(unity);
    }

Мой код контроллера:

public class PropertiesApiController : UmbracoApiController
{
    private readonly IUnitOfWork _unitOfWork;

    public PropertiesApiController(IUnitOfWork unitOfWork)
    {
        if(null == unitOfWork)
            throw new ArgumentNullException();
        _unitOfWork = unitOfWork;
    }

    public IEnumerable GetAllProperties()
    {
        return new[] {"Table", "Chair", "Desk", "Computer", "Beer fridge"};
    }
}

Код My Scope Container/IoC Container: (согласно http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver)

public class ScopeContainer : IDependencyScope
{
    protected IUnityContainer container;

    public ScopeContainer(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        if (container.IsRegistered(serviceType))
        {
            return container.Resolve(serviceType);
        }
        else
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        if (container.IsRegistered(serviceType))
        {
            return container.ResolveAll(serviceType);
        }
        else
        {
            return new List<object>();
        }
    }

    public void Dispose()
    {
        container.Dispose();
    }
}

public class IoCContainer : ScopeContainer, IDependencyResolver
{
    public IoCContainer(IUnityContainer container)
        : base(container)
    {
    }

    public IDependencyScope BeginScope()
    {
        var child = this.container.CreateChildContainer();
        return new ScopeContainer(child);
    }
}

Мой код IUnitOfWork:

public interface IUnitOfWork : IDisposable
{
    GenericRepository<Office> OfficeRepository { get; }
    GenericRepository<Property> PropertyRepository { get; }
    void Save();
    void Dispose(bool disposing);
    void Dispose();
}

Моя реализация UnitOfWork:

public class UnitOfWork : IUnitOfWork
{
    private readonly PropertySearchContext _context = new PropertySearchContext();
    private GenericRepository<Office> _officeRepository;
    private GenericRepository<Property> _propertyRepository;

    public GenericRepository<Office> OfficeRepository
    {
        get
        {

            if (this._officeRepository == null)
            {
                this._officeRepository = new GenericRepository<Office>(_context);
            }
            return _officeRepository;
        }
    }
    public GenericRepository<Property> PropertyRepository
    {
        get
        {

            if (this._propertyRepository == null)
            {
                this._propertyRepository = new GenericRepository<Property>(_context);
            }
            return _propertyRepository;
        }
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    private bool disposed = false;

    public virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Я использовал unity/DI с контроллерами MVC4/WebAPI и эту реализацию UnitOfWork много раз без проблем, поэтому я думаю, что это специфично для Umbraco.

Я также отладил приложение и убедился, что оно попадает в OnApplicationStarted и что его параметры не равны нулю.

Метод GetAllProperties в контроллере — это просто тестовый метод, чтобы убедиться, что все работает нормально, однако, когда я пытаюсь получить доступ к этому действию, я получаю сообщение об ошибке:

"У типа IUnitOfWork нет доступного конструктора"

Есть ли у кого-нибудь опыт использования Umbraco 6.1 и его UmbracoApiController с внедрением зависимостей/Unity?

Кроме того, в несвязанной заметке, есть ли способ вернуть JSON вместо XML в действии? В веб-API вы бы просто определили средство форматирования в WebApi.config, но в Umbraco его нет.

Спасибо, Джастин


person JustinMoser    schedule 15.08.2013    source источник
comment
Предложение 1. Что произойдет, если вы добавите конструктор по умолчанию в UnitOfWork (который ничего не делает)?   -  person Halvard    schedule 15.08.2013
comment
Предложение 2: Вы видели этот вопрос? stackoverflow.com/questions/17898433/   -  person Halvard    schedule 15.08.2013
comment
Да, я видел это. в моем методе ConfigureApi я регистрирую тип IUnitOfWork/UnitOfWork с помощью HierarchicalLifetimeManager (что я всегда и делаю). Кроме того, я регистрирую тип, а не экземпляр. Возможно, мне нужно вместо этого зарегистрировать экземпляр для контроллера. На самом деле я не пытался явно объявлять пустой конструктор, так как думал, что если вы его пропустите, во время компиляции он все равно будет его использовать? Я все равно попробую и отчитаюсь :)   -  person JustinMoser    schedule 15.08.2013
comment
Я не ожидаю, что предложение пустого конструктора сработает, но было бы глупо, если бы что-то очевидное оказалось решением, и вы потратили много времени, пытаясь найти более сложную ошибку :)   -  person Halvard    schedule 15.08.2013
comment
Нет, добавление пустого конструктора не решило проблему. Я также пытался зарегистрировать экземпляр вместо типа, но не повезло! :(   -  person JustinMoser    schedule 15.08.2013
comment
мог быть я, но мой Umbraco 6.1.4 имеет файлы global.asax и global.asax.cs (скриншот: db.tt /N7kSBnIg), возможно, нужно просто обновить?   -  person Daniël Tulp    schedule 01.09.2013
comment
Это происходит, если ваш контейнер не знает о сопоставлении между IUnitOfWork и UnitOfWork. Он пытается напрямую создать экземпляр IUnitOfWork, что невозможно, поскольку это интерфейс. Убедитесь, что вы правильно зарегистрировали зависимость.   -  person Tony    schedule 30.09.2013


Ответы (1)


В случае, если вы не нашли решение своей проблемы? Загрузите этот пакет Nuget и сразу после создания контейнера Unity:

GlobalConfiguration.Configuration.DependencyResolver =
   new Unity.WebApi.UnityDependencyResolver(Bootstrapper.Container);

Обратите внимание на пространство имен, которое отличается от Unity.Mvc4.UnityDependencyResolver.

person Fabio Milheiro    schedule 18.08.2014