Установка свойства для нескольких реализаций одного и того же интерфейса - PullRequest
0 голосов
/ 11 июня 2018

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

  • ПРИМЕЧАНИЕ. Я пробовал множество примеров в Интернете, ниже приведена только последняя версия

Например ... Когда я смотрю на объект приложения в Quick Watch, я получаю следующее

enter image description here

МОЯ КОНФИГУРАЦИЯ: Очевидно, я разобрал все остальные объекты ...

public ContainerRegistry()
{
    Scan(
        scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
            scan.LookForRegistries();
            scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
            scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.XXX.MeasurementContracts", true, null));
            scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));
            scan.AddAllTypesOf(typeof(IInstanceProvider));
            scan.SingleImplementationsOfInterface();
        });

    // --------
    // NAMED INSTANCES - IInstanceProvider
    For<IInstanceProvider>().Use<DistributionListProvider>();
    For<IInstanceProvider>().Add<FirstDeliveryNoticeDocumentRecallManager>().Named("firstDeliveryNoticeDocumentRecallManager");

    // --------
    // APPLICATION
    For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()

        // Component
        .Setter(x => x.DistributionListProvider).Is<DistributionListProvider>()
        .Setter(x => x.FirstDeliveryNoticeDocumentRecallManager).IsNamedInstance("firstDeliveryNoticeDocumentRecallManager");
}

ПРИЛОЖЕНИЕ Пример: Очевидно, я разобрал все другие объекты ...

public class MeasurementContractsApplication : IMeasurementContractsApplication
{
    [SetterProperty]
    public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }

    [SetterProperty]
    public IInstanceProvider DistributionListProvider { get; set; }

    [SetterProperty]
    public IInstanceProvider FirstDeliveryNoticeDocumentRecallProvider { get; set; }
}

IInstanceProvider's:

public class DistributionListProvider : ProviderBase, IInstanceProvider
{
    // Purposely left-out Properties, Methods etc.
}

public class FirstDeliveryNoticeDocumentAdminUpdateProvider : ProviderBase, IInstanceProvider
{
    // Purposely left-out Properties, Methods etc.
}

public class ProviderBase
{
    [SetterProperty]
    public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }

}

---------------------------------------- ОБНОВЛЕНИЯ: Из вопросов, заданных мне Для того, чтобы привести вещи к ЧРЕЗВЫЧАЙНОМУ ОСНОВНОМУ уровню ... Я решил реализовать МИНИМАЛЬНЫЙ набор из 2 классов, чтобы попробовать предложения:

public interface ITesting
{
    string Name();
}

public class Foo : ITesting
{
    public string Name()
    {
        return string.Empty;
    }
}

public class Bar : ITesting
{
    public string Name()
    {
        return string.Empty;
    }
}

public ContainerRegistry()
{
    Scan(
        scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
            scan.LookForRegistries();
            scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
            scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.MeasurementContracts", true, null));
            scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));
            scan.AddAllTypesOf(typeof(IManager<>));
            scan.AddAllTypesOf(typeof(IDocumentDependency));
            scan.AddAllTypesOf(typeof(IDataItemProviderFor<>));
            scan.AddAllTypesOf(typeof(IDatasetBuilderFor<>));
            scan.AddAllTypesOf(typeof(IXmlTransformerFor<>));
            scan.AddAllTypesOf(typeof(IWorkflowProvider));
            scan.AddAllTypesOf(typeof(IInstanceProvider));
            scan.AddAllTypesOf(typeof(IPdfConverterClient));
            scan.AddAllTypesOf(typeof(IReportFor<>));
            scan.AddAllTypesOf(typeof(IAdminUpdateCommandFor<>));
            scan.AddAllTypesOf(typeof(ITesting));
            scan.SingleImplementationsOfInterface();
        });

         Component Providers
        For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()
            Setter(x => x.Bar).Is<Bar>()
            Setter(x => x.Foo).Is<Foo>();
}

Один из двух результатов всегда происходит

  1. Свойство равно NULL
  2. Я получаю следующее сообщение об ошибке

"Экземпляр по умолчанию не зарегистрирован и не может быть автоматически определен для типа 'IInstanceProvider' Нет значения по умолчаниюуказан экземпляр. "

В: Где находятся целевые реализации?

XXX.MeasurementContracts.Business Содержит «ContainerRegistry» и все классы, интерфейсы и т. Д.

XXX.MeasurementContracts.Web Содержит "StructuremapMvcConfig", инициализатор "IoC" и собственную "DefaultRegistry"

MeasurementContracts.UnitTests Добавляет Business «ContainerRegistry» в свой инициализатор «IoC» ..., а затем добавляет свою собственную «ContainerRegistry».

ATTEMPT: попытка именованных регистраций Я добавил следующее в «ContainerRegistry»", и в то же время ОБА заселены ... они типа" Бар "

// Component Providers
For<ITesting>().Use<Bar>().Named("Bar");
For<ITesting>().Add<Foo>().Named("Foo");

// Component Providers
For<IMeasurementContractsApplication>().Use<MeasurementContractsApplication>()
     .Setter(x => x.Bar).Is<Bar>()
     .Setter(x => x.Foo).Is<Foo>();

КАК РАЗРЕШИТЬ" Фу "?Я также пытался ".Setter (x => x.Foo) .Is (c => c.GetInstance (" Foo "));"

АНАЛИЗ: Использование container.WhatDoIHave () Хорошо, с помощью «WhatDoIHave» отображается, что я правильно настроил экземпляры «ITesting».

  • Transient - XXX.MeasurementContracts.Business.Providers.Bar ('bar') - bar (по умолчанию)
  • Переходный процесс - XXX.MeasurementContracts.Business.Providers.Foo ('foo') - foo

КАК РАЗРЕШИТЬ "Foo" & "Bar" на соответствующие свойства?

1 Ответ

0 голосов
/ 14 июня 2018

Удалите явные атрибуты сеттера для свойств DistributionListProvider и FirstDeliveryNoticeDocumentRecallProvider.

Явное внедрение сеттера с атрибутами [SetterProperty]

БезАтрибуты [SetterProperty], украшающие сеттеры, StructureMap будет игнорировать свойства DistributionListProvider и FirstDeliveryNoticeDocumentRecallProvider при создании объекта MeasurementContractsApplication.С помощью атрибутов StructureMap попытается построить и прикрепить значения для двух свойств как часть конструкции объекта.

public class MeasurementContractsApplication : IMeasurementContractsApplication {
    [SetterProperty]
    public IMeasurementContractsUnitOfWork UnitOfWork { get; set; }


    public IInstanceProvider DistributionListProvider { get; set; }


    public IInstanceProvider FirstDeliveryNoticeDocumentRecallProvider { get; set; }
}

И так как он не может определить, какой интерфейс использовать, для какого свойства он применяетсяпервый зарегистрированный интерфейс для обоих свойств.

Именно поэтому, в этом случае, вам следует просто применить встроенные сеттеры

Конфигурация встроенного сеттера

Любое свойство сеттера, не настроенное с [SetterProperty] или политиками сеттера в следующем разделе, все еще может заполняться StructureMap, если встроенная зависимость настроена в соответствии с этим свойством сеттера, как показано в примере ниже:

For<IMeasurementContractsApplication>()
    .Use<MeasurementContractsApplication>()
    // Component
    .Setter(x => x.DistributionListProvider)
        .Is<DistributionListProvider>()
    .Setter(x => x.FirstDeliveryNoticeDocumentRecallManager)
        .Is<FirstDeliveryNoticeDocumentAdminUpdateProvider>();

Следующий пример Minimal Complete и Verifiable демонстрирует вышеприведенное и проходит тестирование.

namespace StructureMap.Unit_Tests.Misc {
    [TestClass]
    public class StructureMapTests {
        [TestMethod]
        public void _Inline_Setter_Should_Populate_Multiple_Implementations() {
            //Arrange
            var registry = new StructureMap.Registry();
            registry.IncludeRegistry<ContainerRegistry>();
            // build a container
            var container = new StructureMap.Container(registry);

            //Act
            var application = container.GetInstance<IMeasurementContractsApplication>();

            //Assert
            application.Should().NotBeNull();
            application.Foo.Should().BeOfType<Foo>();
            application.Bar.Should().BeOfType<Bar>();
        }
    }

    class ContainerRegistry : StructureMap.Registry {
        public ContainerRegistry() {
            Scan(
                scan => {
                    scan.TheCallingAssembly();
                    scan.WithDefaultConventions();
                    scan.LookForRegistries();
                    scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Demo.Common", true, null));
                    scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("XXX.MeasurementContracts", true, null));
                    scan.AddAllTypesOf(typeof(IMeasurementContractsApplication));                    
                    scan.AddAllTypesOf(typeof(ITesting));
                    scan.SingleImplementationsOfInterface();
                });

            //Component Providers
            For<IMeasurementContractsApplication>()
                .Use<MeasurementContractsApplication>()
                .Setter(x => x.Bar)
                    .Is<Bar>()
                .Setter(x => x.Foo)
                    .Is<Foo>();
        }
    }

    public interface IMeasurementContractsApplication {
        ITesting Foo { get; set; }
        ITesting Bar { get; set; }
    }

    public class MeasurementContractsApplication : IMeasurementContractsApplication {
        public ITesting Foo { get; set; }
        public ITesting Bar { get; set; }
    }

    public interface ITesting {
        string Name();
    }

    public class Foo : ITesting {
        public string Name() {
            return string.Empty;
        }
    }

    public class Bar : ITesting {
        public string Name() {
            return string.Empty;
        }
    }
}

Quick watch

...