Вопрос Unity Injection, передающий информацию в несколько слоев - PullRequest
1 голос
/ 23 марта 2011

Я пытаюсь использовать Unity для внедрения зависимости с помощью нескольких сквозных классов. Сейчас у меня есть некоторая инфраструктура кэширования, которую я обернул вокруг корпоративной библиотеки MS. Я обертываю это, потому что я могу хотеть использовать что-то еще позже. Кроме того, я могу захотеть смешивать и сопоставлять разные хранилища кеша.

Итак, у меня есть общий интерфейс кеширования и конкретная реализация:

public interface ICacheProvider
{
    void Add(object key, object value);

    void Remove(object key);

    object GetData(object key);

    void Flush();
}

public class MyCacheProvider : ICacheProvider
{
    private ICacheManager cacheManager;

    public MyProvider(ICacheManager manager)
    {
        cacheManager = manager;
    }
}

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

<unity>
<typeAliases>
  <typeAlias alias="string" type="System.String, mscorlib" />
  <typeAlias alias="ICacheProvider" type="DomainBase.Caching.ICacheProvider, DomainBase" />
  <typeAlias alias="MSCacheProvider" type="Caching.MyCacheProvider, Caching" />
</typeAliases>
<containers>
  <container>
    <types>
      <register type="ICacheProvider" mapTo="MSCacheProvider" />
    </types>
  </container>
</containers>

Вот как я настраиваю свой контейнер для единства:

 private IUnityContainer rootContainer;

 rootContainer = new UnityContainer().LoadConfiguration();
 var configurator = new UnityContainerConfigurator(rootContainer);
 EnterpriseLibraryContainer.ConfigureContainer(configurator, ConfigurationSourceFactory.Create());

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

//note that's ICacheProvider which my interface for abstracting caching.  NOT
//the enterprise library interface
ICacheProvider customersCache = rootContainer.Resolve<ICacheProvider>(); //works
ICacheProvider productsCache = rootContainer.Resolve<ICacheProvider>("ProductsCache"); //doesn't work

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

Кроме того, я попытался явно определить именованную регистрацию, и я все еще получаю тот же экземпляр CacheManager, даже если определены два отдельных экземпляра. Я полагаю, что после того, как начальное разрешение выполнено, оно смотрит на конструктор и у него не осталось «имени», а просто внедряется на основе значения по умолчанию?

Спасибо за вашу помощь

1 Ответ

1 голос
/ 23 марта 2011

Нашел ответ на свой вопрос. Единственный способ понять это - использовать пользовательское расширение и проверить тип. Вот образец

 public class WrappedResolver : UnityContainerExtension
{

    protected override void Initialize()
    {
        this.Context.Strategies.Add(new WrappedBuilder(this.Container), Microsoft.Practices.Unity.ObjectBuilder.UnityBuildStage.PreCreation);

    }
}

public class WrappedBuilder : BuilderStrategy
{
    IUnityContainer baseContainer;

    public WrappedBuilder(IUnityContainer container)
    {
        baseContainer = container;
    }

    public override void PreBuildUp(IBuilderContext context)
    {

        if (context.BuildKey.Type.Name.Contains("ICacheProvider") && context.OriginalBuildKey.Name != null)
        {
            string originalName = context.OriginalBuildKey.Name;
            Type mytype = Type.GetType("Microsoft.Practices.EnterpriseLibrary.Caching.ICacheManager, Microsoft.Practices.EnterpriseLibrary.Caching");
            Type originalType = context.BuildKey.Type;// Type.GetType("DomainBase.Caching.ICacheProvider, DomainBase");
            context.Existing = baseContainer.Resolve(originalType, new ParameterOverride("manager",
                                                                         new ResolvedParameter(mytype, originalName)));

            context.BuildComplete = true;

        }
        base.PreBuildUp(context);
    }   
}
...