Модуль является связующим контекстом для Autofac - PullRequest
3 голосов
/ 01 февраля 2012

У меня есть приложение, которое может потребоваться для подключения к нескольким базам данных.Но каждый модуль будет подключаться только к одному БД.Поэтому я думаю, что может иметь смысл выделить БД в каждый модуль, чтобы каждый модуль получал свое собственное автоматическое разрешение БД, и мне не нужно беспокоиться о именованной регистрации.Но, к моему удивлению, кажется, что модуль Autofac является больше модулем кода, чем логическим модулем (я здесь не прав?): IA

[Test]
public void test_module_can_act_as_scope_container()
{
    ContainerBuilder builder = new ContainerBuilder();
    builder.RegisterModule(new Module1());

    IContainer c = builder.Build();
    var o = c.ResolveNamed<CB>("One");
    Assert.That(o.A.Name, Is.EqualTo("One"));

    builder = new ContainerBuilder();
    builder.RegisterModule(new Module1());
    builder.RegisterModule(new Module2());
    c = builder.Build();
    var t = c.ResolveNamed<CB>("One");
    Assert.That(t.A.Name, Is.EqualTo("Two"));
}

И используемые интерфейсы / модули:

public interface IA
{
    string Name { get; set; }
}

public class CA : IA
{
    public string Name { get; set; }
}

public class CB
{
    public CB(IA a)
    {
        A = a;
    }
    public IA A { get; private set; }
}

public class Module1 : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(c => new CA() { Name = "One" }).As<IA>();
        builder.RegisterType<CB>().Named("One", typeof(CB));
    }
}

public class Module2 : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register(c => new CA() { Name = "Two" }).As<IA>();
        builder.RegisterType<CB>().Named("Two", typeof(CB));
    }
}

Ответы [ 2 ]

2 голосов
/ 01 февраля 2012

Да, вы правы.

Модули служат только для разделения конфигурации на несколько независимых частей.Они никак не влияют на конфигурацию.Наличие модулей на самом деле такое же, как если бы вы объединили код всех модулей Load методов в один метод конфигурации, а затем собрали контейнер.

В вашем случае ваш Module2 фактически отменяет регистрацию для IA интерфейс от Module1.

Мне также было интересно найти решение проблемы.Я пришел к следующему подходу:

Служба ключей

var key = new object();
builder.Register(c => new CA() { Name = "Two" }).Keyed<IA>(key);
builder.RegisterType<CB>().Named("Two", typeof(CB))
  .WithParameter(new ResolvedParameter(
      (pi, ctx) => pi.Type == typeof(IA),
      (pi, ctx) => ctx.ResolveKeyed<IA>(key)
  ));

Плюсы:

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

Против:

  1. Код довольно большой
  2. Он не делает IA компонент «внутренним» для модуля - другоеМодули все еще могут решить это, используя простой Resolve<IA>.Модули не изолированы.

Надеюсь, это поможет

ОБНОВЛЕНИЕ

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

Регистрация делегата

builder.Register(ctx => new CB(new CA { Name = "Two" }))
  .Named("Two", typeof(CB));

Плюсы:

  1. Вы не выставляетедля вашего модуля CA для других модулей

Против:

  1. Если CA и CB имеют сложные зависимости и много параметров конструктора, вы 'Вы получите беспорядок построения кода
  2. Если вам нужно использовать CA в нескольких местах внутри модуля, вам нужно будет найти способ избежать копирования-вставки

Экземпляры вложенных контейнеров

И еще один вариант - иметь независимый Container внутри каждого модуля.Таким образом, все модули смогут иметь свои частные конфигурации контейнеров.Однако, AFAIK, Autofac не предоставляет никаких встроенных средств для того, чтобы каким-либо образом связать несколько Container экземпляров.Хотя я полагаю, что реализовать это не должно быть очень сложно.

1 голос
/ 02 февраля 2012

Вы можете использовать области действия Nestet. Они образуют иерархию, в которой подскопы могут разрешать услуги, зарегистрированные в суперобласти. Кроме того, вы можете зарегистрировать уникальные сервисы в каждом подскопе, например:

var cb = new ContainerBuilder();
cb.RegisterModule<CommonModule>();
var master = cb.Build();

var subscope1 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module1>());
var subscope2 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module2>());

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

...