Единство: распространять именную регистрацию - PullRequest
0 голосов
/ 09 июня 2011

В Unity (2.0) я регистрирую два именованных интерфейса IFoo, сопоставленных с двумя различными реализациями:

Container
   .RegisterType<IFoo, Foo1>("first")
   .RegisterType<IFoo, Foo2>("second");

Ну, у меня есть такая служба:

public class ServiceImpl : IService {

    public ServiceImpl(IFoo foo, IDependency dep, IJustAnother stuff) { ... }

    public MyValueObject[] FindVOs() { ... }

}

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

 Container
   .RegisterType<IService, ServiceImpl>(
      "first", 
      new InjectionConstructor(
         new ResolvedParameter<IFoo>("first"),
         new ResolvedParameter<IDependency>(),
         new ResolvedParameter<IJustAnother>()
      )
   )
   .RegisterType<IService, ServiceImpl>(
      "second", 
      new InjectionConstructor(
         new ResolvedParameter<IFoo>("second"),
         new ResolvedParameter<IDependency>(),
         new ResolvedParameter<IJustAnother>()
      )
   )

Это работает, но я считаю это уродливым и не умным, потому что для каждой новой реализации IFooМне нужно добавить два RegisterType звонка.Есть ли лучший способ (возможно, с расширением)?

Еще один вопрос: как Виндзорский контейнер справляется с этим?с автоматической регистрацией?

* РЕДАКТИРОВАТЬ *

Например, если мне нужен CompositeService, подобный этому:

public class CompositeService : IService {

    public ServiceImpl(IService[] services) { _services = services; }

    public MyValueObject[] FindVOs() { 
       return _services.SelectMany(_ => _.FindVOs() ); 
    }
}

Я мог бы зарегистрировать этопуть:

Container
   .RegisterType<IService, CompositeService>();

и Unity внедрит все именованные регистрации в составной конструктор.Проблема в том, что таким образом он работает, только давая имя всем IService.И я не могу ввести IFoo[] вместо IService, потому что IFoo используется только ServiceImpl, который является конкретной реализацией IService.Вот почему я спросил, есть ли лучший способ зарегистрировать их, избегая избыточности, в Unity.

Ответы [ 2 ]

2 голосов
/ 09 июня 2011

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

Foo1 может быть реализацией для административных страниц, а Foo2 для обычных пользователей

Вы можете эффективно решить эту проблему, зарегистрировав InjectionFactory.Самый короткий пример, который я могу придумать, следующий:

container.Register<IFoo>(new InjectionFactory(c =>
{
    if (HttpContext.User.IsInRole("SUPERUSERS"))
        return container.Resolve<Foo1>();

    return container.Resolve<Foo2>();
}));

Вы также можете решить эту проблему, определив декоратор / прокси-сервер IFoo, который это делает.Это делает вашу конфигурацию DI немного чище, но требует немного больше кода.Вот пример:

using System.Security.Principal;

public class UserBasedFoo : IFoo
{
    private readonly IPrincipal currentUser;
    private readonly IFoo normalUserFoo;
    private readonly IFoo superUserFoo;

    public UserBasedFoo(IPrincipal currentUser, 
        IFoo normalUserFoo, IFoo superUserFoo)
    {
        this.currentUser = currentUser;
        this.normalUserFoo = normalUserFoo;
        this.superUserFoo = superUserFoo;
    }

    object IFoo.FooMethod()
    {
        return this.CurrentUserFoo.FooMethod();
    }

    private IFoo CurrentUserFoo
    {
        get
        {
            if (this.currentUser.IsInRole("SUPERUSERS"))
                return this.superUserFoo;

            return this.normalUserFoo;
        }
    }
}

Вы можете настроить это следующим образом:

container.Register<IPrincipal>(
    new InjectionFactory(c => HttpContext.User));

container.Register<IFoo>(new InjectionFactory(c =>
{
    return new UserBasedFoo(container.Resolve<IPrincipal>(),
        container.Resolve<Foo1>(),
        container.Resolve<Foo2>());
}));

Недостатком этого последнего подхода является то, что это больше кода, но он более гибкий, многократно используемый ипроверяемый.Этот класс сам по себе не зависит от ASP.NET, что важно, если вы хотите выполнить его модульное тестирование.

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

0 голосов
/ 01 июля 2011

Я решил написать UnityContainerExtension (с его собственным BuilderStrategy), который позволяет мне сделать это:

Container
   .RegisterType<IFoo, Foo1>("first")
   .RegisterType<IFoo, Foo2>("second")

   .RegisterType<IService, ServiceImpl>(
       new InjectionPropagator<IFoo>()
   )
;

таким образом, мне не нужно регистрировать новое имя с именем IService для каждого с именем IFoo, для меня это очень полезно, потому что я могу добавить именованные IFoo регистрации в файле конфигурации XML.

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