Устранение одноэлементного компонента, который был зарегистрирован отдельно в разных дочерних областях через Autofac - PullRequest
0 голосов
/ 29 марта 2012

У меня проблема с разрешением одноэлементных компонентов в Autofac, и мне интересно, работает ли Autofac правильно или это подлинная ошибка.

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

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

public class ChildSingletonScopeTest
{
    readonly IContainer container;
    readonly ILifetimeScope scope1, scope2, childScope1;

    public ChildSingletonScopeTest()
    {
        var builder = new ContainerBuilder();
        container = builder.Build();

        scope1 = container.BeginLifetimeScope(ConfigureTenant);
        scope2 = container.BeginLifetimeScope(ConfigureTenant);

        childScope1 = scope1.BeginLifetimeScope();
    }

    void ConfigureTenant(ContainerBuilder builder)
    {
        builder.RegisterType<Testing>().As<ITesting>().SingleInstance();
    }

    [Xunit.Fact] /* this test fails */
    public void should_resolve_single_instance_for_each_tenant_scope()
    {
        var instance1 = scope1.Resolve<ITesting>();
        var instance2 = scope2.Resolve<ITesting>();

        Xunit.Assert.Equal(instance1, instance2);
    }

    [Xunit.Fact] /* this test passes */
    public void should_resolve_single_instance_down_child_scope_hierarchy()
    {
        var instance1 = scope1.Resolve<ITesting>();
        var instance2 = childScope1.Resolve<ITesting>();

        Xunit.Assert.Equal(instance1, instance2);
    }
}

interface ITesting { }

class Testing : ITesting
{
    public override string ToString()
    {
        return GetHashCode().ToString();
    }
}

Причина, по которой я пытаюсь сделать что-то сумасшедшее, сводится к тому, как мы реализуем многопользовательскую работу в нашем веб-приложении.Не слишком зацикливаясь на деталях, у нас есть требование иметь возможность программно «переключать» арендаторов в середине веб-запроса.

Способ, которым мы делаем это, - это вложение областей арендатора под каждый доступныйобъем запроса.Однако специфичные для арендатора синглтон-регистрации не разрешают один и тот же экземпляр для одного и того же арендатора в разных запросах.

Итак, мне интересно, является ли это ошибкой в ​​способе, которым Autofac обрабатывает эти синглтон-регистрации ИЛИ, если мне нужноизменить способ работы с одноэлементными компонентами в областях арендатора.

1 Ответ

2 голосов
/ 30 марта 2012

С вики-страница Autofac для областей действия экземпляра ...

При использовании одной области видимости один экземпляр возвращается из всех запросов в родительском и всех вложенных контейнерах.

Что означает, что у вас есть такие вложенные области видимости ...

container
  scope-1
    scope-2

Тогда, если вы зарегистрируете синглтон в "scope-1", тогда, когда вы разрешите его в "scope-2", вы получите тот же синглтон. С другой стороны, если вы попытаетесь разрешить это в контейнере, вы ничего не получите, потому что он там не был зарегистрирован - регистрации «наследуют» дерево, а не вверх, как показывают ваши тесты .

В блоге Ника Блумхардта есть хороший праймер для областей действия Autofac и разрешения компонентов. Вы можете заметить одну запутанную вещь: упоминание о том, как компоненты с одной областью действия разрешаются, если регистрация не входит в текущую область.

Допустим, вы зарегистрировали синглтон в "scope-1", и этот синглтон имеет зависимость. Далее, скажем, зависимость зарегистрирована как в «scope-1», так и в «scope-2». Теперь вы разрешаете синглтон из "scope-2". Так как синглтон зарегистрирован в "scope-1", он разрешит свои зависимости от "scope-1" вместо использования переопределения в "scope-2" - потому что, как только "scope-2" заканчивается, синглтон все равно должен остаться в «сферу действия-1» для других потреблять.

В других областях вашего сценария, , вы также можете столкнуться с "последним в выигрыше" . Если вы зарегистрируете синглтон в «контейнере», а затем другой в «scope-1», при разрешении из «scope-2» вы получите тот, который зарегистрирован в «scope-1», а не тот, который находится в корневом каталоге. Тем не менее, вы также должны быть в состоянии решить все из них, как ...

scope.Resolve<IEnumerable<IMySingleton>>();

Если вы разрешите IEnumerable вашего компонента, вы получите все зарегистрированные компоненты, а не только последний, который вы зарегистрировали.

Полагаю, это длинный способ сказать это не ошибка, вот как работает Autofac .

Если вы используете мультитенантность с Autofac, смотрели ли вы на AutofacContrib.Multitenant ? Это одна из предоставленных библиотек, которая имеет встроенную поддержку таких вещей, как синглтоны на основе арендаторов. Для этого тоже есть вики-страница на Autofac. Вы можете настроить значения по умолчанию на уровне приложения и затем переопределения для конкретного арендатора. Вы также можете делать такие вещи, как ...

containerBuilder.RegisterType<MyType>().As<IMyType>().InstancePerTenant();

... что делает регистрацию синглетов-арендаторов на корне довольно простой.

Пока нет пакета NuGet для библиотек contrib в Autofac (мы работаем над этим), поэтому вам придется перейти на сайт и загрузить вручную, но это может помочь решить вашу проблему.

[Полное раскрытие: я написал AutofacContrib.Multitenant.]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...