Autofac — компоненты игнорируют зависимость, определенную в области жизненного цикла

Я вполне мог что-то неправильно понять, поэтому, возможно, здесь есть простой ответ, но сейчас я ломаю голову.

У меня есть класс UnitOfWork, который реализует IUnitOfWork (да, да, я знаю). Конструктор единицы работы принимает IPrincipalFactory. TResponder — это верхний уровень графа, который принимает IUnitOfWork.

Я пытаюсь зарегистрировать ApplicationPrincipalFactory как конкретный экземпляр в области действия... это зависит от некоторых свойств, переданных функции HandleAsync. Я делаю следующее:

    public async Task<TResponse> HandleAsync<TMessage, TResponse, TResponder>(TMessage message)
        where TMessage : class
        where TResponder : IRespondAsync<TMessage, TResponse>
    {
        using (var scope = this.BeginLifetimeScope(message))
        {
            var responder = scope.Resolve<TResponder>();
            return await responder.Respond(message);
        }
    }

    private ILifetimeScope BeginLifetimeScope<TMessage>(TMessage message)
    {
        var unwrapped = GetDomainContext(message);
        var applicationPrincipalFactory = this.CreateApplicationPrincipalFactory(unwrapped);

        var lifetime = this.container.BeginLifetimeScope(
            r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());

        return lifetime;
    }

    private ApplicationPrincipalFactory CreateApplicationPrincipalFactory(IDomainContext unwrapped)
    {
        var applicationPrincipalFactory =
            new ApplicationPrincipalFactory(
                unwrapped.Tenant,
                unwrapped.ActingTenant,
                unwrapped.Username);

        return applicationPrincipalFactory;
    }

Основываясь на всем, что я прочитал, определение зависимости в BeginLifetimeScope(r => должно переопределить привязку родительского контейнера, поэтому, когда я вызываю разрешение, все должно быть аккуратно совмещено.

Однако я получаю исключение:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Platform.Engine.Persistence.UnitOfWork' can be invoked with the available services and parameters: Cannot resolve parameter 'Platform.Engine.Security.IPrincipalFactory principalFactory' of constructor

Я не регистрирую IPrincipalFactory где-либо, кроме как в этом методе. IUnitOfWork определяется во внешней области следующим образом:

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();

Я также попытался переопределить регистрацию единицы работы в дочернем контейнере, если это было причиной проблемы, зарегистрировав ее во внешнем контейнере, а не во временном:

        var lifetime = this.container.BeginLifetimeScope(
            r => r.RegisterInstance(applicationPrincipalFactory).As<IPrincipalFactory>());

        var overrides = new ContainerBuilder();
        overrides.RegisterType<UnitOfWork>().As<IUnitOfWork>();
        overrides.Update(lifetime.ComponentRegistry);

        return lifetime;

Я не уверен, что мне не хватает... есть идеи или предложения?


person beyond-code    schedule 15.07.2014    source источник
comment
У вас есть линия builder.RegisterType для вашего IPrincipalFactory?   -  person DavidG    schedule 15.07.2014
comment
Я не... не будет ли здесь RegisterInstance(...).As‹IPrincipalFactory› действовать на своем месте?   -  person beyond-code    schedule 15.07.2014
comment
Не совсем уверен, я не использовал Autofac таким образом, но, судя по сообщению об ошибке, я думаю, что нет. Обычно я просто регистрирую каждый из своих типов с помощью компоновщика, а Autofac позаботится обо всем остальном.   -  person DavidG    schedule 15.07.2014
comment
Не могли бы вы опубликовать репродукцию, пожалуйста. Возьмите за основу следующую суть: gist.github.com/alexandrnikitin/9799e871bbcd573fc20b   -  person Alexandr Nikitin    schedule 15.07.2014
comment
Из какой области (контейнера или жизненного цикла) вы разрешаете IUnitOfWork?   -  person Peter Lillevold    schedule 16.07.2014


Ответы (1)


Зарегистрируйте свою фабрику вместе с остальными типами во время первоначальной настройки контейнера.

builder.RegisterType<ApplicationPrincipalFactory>().As<IPrincipalFactory>();

Затем в вашей жизненной области разрешите фабрику делегатов, в которую вы можете передать контекст.

var factory = container.Resolve<Func<IDomainContext, IPrincipalFactory>>();
var instance = factory(context);

Вы также можете добавить три параметра string к подписи Func<>, но, поскольку у вас уже есть хороший объект контекста, я бы просто передал его вместо этого.

Наконец, используйте фабрику по мере необходимости.

instance.DoesSomethingButNotSureWhat();

Это избавит вас от необходимости обновлять область жизненного цикла только для передачи параметра контекста.

person Alex Meyer-Gleaves    schedule 16.07.2014