Разрешение Общей службы Autofac во время выполнения - PullRequest
2 голосов
/ 20 декабря 2011

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

class Message { }

interface IHandle<T> {
    void Handle(T message);
}

class Handle<Message> : IHandle<Message> {
    ...
}

class Bus {
    .ctor (? lookup) {
        _lookup = lookup;
    }

    void Send<T>(T message) {
        _lookup.GetHandler<T>().Handle(message);
    }
}

var builder = new ContainerBuilder();
builder.RegisterType<Handle<Message>>().As<IHandle<Message>>();
builder.RegisterType<Bus>();

var container = builder.Build();
container.Resolve<Bus>().Send<Message>(new Message());

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

Кстати, замковый способ iirc позволяет мне регистрировать что-то вроде этого:

interface IHandlerFactory {
    IHandle<T> GetHandler<T>();
}

container.Register<IHandlerFactory>().AsFactory();

Спасибо, Ник

Ответы [ 2 ]

4 голосов
/ 22 декабря 2011

Вы можете изолировать эту связь, создав бетон IHandlerFactory, скажем AutofacHandlerFactory, который получит ILifetimeScope. Такое соединение кажется неизбежным, поскольку контейнер - единственный, кто может решить правильные IHandler<T>.

Соединение с ILifetimeScope может быть плохой идеей, но тогда муфта изолируется внутри бетона IHandlerFactory, и Bus просто использует его через интерфейс. Допустим, вы изменили контейнер и начали использовать Ninject, вы могли бы просто реализовать NinjectHandlerFactory для выполнения этой работы.

4 голосов
/ 21 декабря 2011

Похоже, ответ «Нет».

Я пытался использовать AggregateService , который должен делать то, что вы хотите, но он вылетает во время разрешения фабрики с сообщением «Тип« Castle.Proxies.IComponentFactoryProxy »из сборки« DynamicProxyGenAssembly2, Version = 0.0.0.0, Culture = нейтральный, PublicKeyToken = null "попытался реализовать недоступный интерфейс. ' (Исходное сообщение на русском языке, я его перевел).

Я не могу найти другой подход, который бы работал без ручной (но довольно простой) реализации. Может, тебе стоит написать Николасу Блюмхардту.

На самом деле, мне лучше сделать это так:

public class Bus {
  readonly ILifetimeScope _OwnScope;

  // Autofac always provides ILifetimeScope that owns a component as a service to the component
  // so it can be used as a dependency
  public Bus(ILifetimeScope ownScope) {
    _OwnScope = ownScope;
  }

  void Send<T>(T message) {
    _OwnScope.Resolve<IHandler<T>>.Handle(message);
  }
}

Вы, вероятно, будете утверждать, что соединение с ILifetimeScope - плохая идея. Ну, это довольно простой интерфейс, который может быть включен в вашу собственную реализацию. Или вы можете выделить код в простой фабричный класс. Ну, похоже, ты знаешь, как это сделать без моих предложений.

...