Время жизни Autofac и поставщик по умолчанию в соответствующей области времени жизни

У меня есть веб-приложение ASP.NET MVC, использующее Autofac для внедрения зависимостей. Иногда это веб-приложение запускает поток, выполняющий некоторую работу отдельно от потока запроса. Когда этот фоновый поток запускается, он устанавливает новую область действия Autofac из корневого контейнера и выполняет некоторое действие.

public IAsyncResult Run<T>(Action<T> action)
{
    var NewTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
        using (var Scope = Runtime.Container.BeginLifetimeScope())
        {
            var Input = Scope.Resolve<T>();
            action(Input);
        }
    });

    return NewTask;
}

Одна из моих зависимостей, зарегистрированных в Autofac, имеет две разные реализации: одна, подходящая для времени жизни http-запроса, и другая, подходящая для всех других времен жизни. Я попытался зарегистрировать их следующим образом:

builder
.Register(c => new Foo())
.As<IFoo>()
.InstancePerLifetimeScope();

builder
.Register(c => new FooForHttp(HttpContext.Current))
.As<IFoo>()
.InstancePerMatchingLifetimeScope(WebLifetime.Request);

Автофак выбирает FooForHttp для http запросов (как и ожидалось). Однако, когда мой фоновый поток раскручивается, любая попытка разрешить IFoo приводит к исключению:

Из области, в которой был запрошен экземпляр, не видна область с тегом, совпадающим с httpRequest. Как правило, это указывает на то, что компонент, зарегистрированный в качестве запроса HTTP, запрашивается компонентом SingleInstance() (или аналогичным сценарием). При веб-интеграции всегда запрашивают зависимости из DependencyResolver.Current или ILifetimeScopeProvider.RequestLifetime, а не из самого контейнера.,

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

Я что-то упустил или есть лучший подход к выбору провайдера на основе тега текущей области действия?

2 ответа

Решение

Зарегистрируйте веб-Foo как обычно, но не регистрируйте другой Foo. При создании области действия для асинхронной задачи используйте перегрузку BeginLifetimeScope(), которая выполняет действие над ContainerBuilder. Зарегистрируйте фоновое Foo в этом действии (b => b.Register()), и это должно переопределить веб-действие. (Маленькая клавиатура здесь извините:))

Это также может быть решено с помощью тегов времени жизни. Зарегистрируйте свой первый Foo как экземпляр вашей помеченной области:

builder.RegisterType<Foo>().As<IFoo>.InstancePerMatchingLifetimeScope("YourScopeTag");

И создайте область с тем же тегом, что вы зарегистрировали свою зависимость:

  using (var Scope = Runtime.Container.BeginLifetimeScope("YourScopeTag"))
        {
            var Input = Scope.Resolve<T>();
            action(Input);
        }

Не проверял, но это должно работать

http://docs.autofac.org/en/latest/lifetime/instance-scope.html

Другие вопросы по тегам