Настройте свойство конкретного класса, используя StructureMap - PullRequest
0 голосов
/ 27 июня 2018

У меня есть общий набор классов электронной почты, используемых в экземпляре Application. Все они используют один и тот же интерфейс, но мне нужно иметь возможность (необязательно) "вставить" экземпляр другого "общего" типа в качестве свойства.

НАЧНИТЕ ЗДЕСЬ: Учитывая эту отправную точку ...
Обратите внимание, что MyApplication запускается со всеми 3 свойствами. И, поскольку DistributionListProvider является единственным настроенным IInstanceProvider ... никаких проблем не возникает.

public class MyApplication : IMyApplication
{       
    #region notifications

    [SetterProperty]
    public IEmailNotification RequestToFlowEmailNotification { get; set; }

    [SetterProperty]
    public IEmailNotification ApprovalToFlowEmailNotification{ get; set; }

    #endregion

    #region instance providers

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

    #endregion
}

public class RequestToFlowEmailNotification : IEmailNotification
{
    #region <Properties>

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

    #endregion
}

public class ApprovalToFlowEmailNotification : IEmailNotification
{

}

public class DistributionListProvider : ComponentProviderBase, IInstanceProvider
{

}

LETS ADD: Теперь давайте создадим еще один IInstanceProvider и добавим его в приложение ...
Но сначала обратите внимание, что IEmailNotification & IInstanceProvider являются общими типами, а не «универсальными типами» ... это означает, что они не являются EmailNotificationFor<T> типами. Это влияет на то, как вы настраиваете их в реестре.

// NOW...LETS ADD THIS !!
public class AuthorizationToFlowMeterDocumentRecallProvider : ComponentProviderBase, IInstanceProvider
{

}

public class MyApplication : IMyApplication
{       
    #region notifications

    [SetterProperty]
    public IEmailNotification RequestToFlowEmailNotification { get; set; }

    [SetterProperty]
    public IEmailNotification ApprovalToFlowEmailNotification{ get; set; }

    #endregion

    #region instance providers

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

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

    #endregion
}

На данный момент СтруктураКарта НЕ ДОЛЖНА ПОНИМАТЬ, как заполнить ...

  • RequestToFlowEmailNotification.DistributionListProvider

В: Как обновить реестр, чтобы заставить StructureMap заполняться правильно?
Ниже весь мой реестр ...

ПРИМЕЧАНИЕ:
Я НЕ хочу устанавливать значение по умолчанию ... есть ли способ сделать это без установки DEFAULT?

public ContainerRegistry()
{
    Scan(
        scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
            scan.LookForRegistries();
            scan.SingleImplementationsOfInterface();
        });

    // ------------
    // UNIT OF WORK
    // ------------
    // DbContext
    For<DbContext>().Use<MeasurementContractsDbContext>();

    // UnitOfWork
    For<IMeasurementContractsUnitOfWork>().Use<MeasurementContractsUnitOfWork>();

    // GenericRepository
    For(typeof(ICompositeRepository<>)).Use(typeof(GenericRepository<>));

    // --------
    // HELPERS
    // --------
    For<IWindowsIdentityHelper>().Use<WindowsIdentityHelper>();

    For<ISmtpClientHelper>().Use<SmtpClientHelper>()
        .Ctor<ISmtpClient>().Is(new SmtpClient());

    For<IPdfConverterHelper>().Use<PdfConverterHelper>()
        .Ctor<IPdfConverterClient>().Is(new SelectPdfUrlConverterClient());

    // WARNING: Do not remove without replacing it with "some kind of" IConstructorSelector, so that, Unit Testing can be done
    For<IDataServiceFor<EmployeeData>>()
        .Use(x => new EmployeeDataService(new ODataProxyV4())); //<-- uses this constructor

    // --------
    // WORKFLOW
    // ---------
    For<IWorkflowProvider>().Use<WorkflowProvider>()
        .Ctor<Assembly>().Is(Assembly.GetExecutingAssembly());

    // --------
    // MANAGERS
    // --------
    For<IManager<Device>>().Use<DeviceManager>();
    For<IManager<Favorite>>().Use<FavoritesManager>();
    For<IManager<User>>().Use<UserManager>();

    // --------
    // DEPENDENCY MANAGERS
    // --------
    For<IDocumentDependency>().Use<DeviceAffinityProvider>();

    // --------
    // TRANSFORMERS
    // --------
    For<IXmlTransformerFor<AuthorizationToFlowMeterDocumentXmlDataSet>>().Use<AuthorizationToFlowMeterDocumentXmlTransformer>();
    For<IXmlTransformerFor<FirstDeliveryNoticeDocumentXmlDataSet>>().Use<FirstDeliveryNoticeDocumentXmlTransformer>();
    For<IXmlTransformerFor<RequestToFlowMeterDocumentXmlDataSet>>().Use<RequestToFlowMeterDocumentXmlTransformer>();

    // --------
    // PROVIDERS: DataItem Providers
    // --------
    For<IDataItemProviderFor<EmployeeData>>().Use<EmployeeDataProvider>();

    // --------
    // PROVIDERS: Document Providers
    // --------
    For<IDataItemProviderFor<RequestToFlowMeterDocument>>().Use<RequestToFlowMeterDocumentProvider>();
    For<IDataItemProviderFor<AuthorizationToFlowMeterDocument>>().Use<AuthorizationToFlowMeterDocumentProvider>();
    For<IDataItemProviderFor<FirstDeliveryNoticeDocument>>().Use<FirstDeliveryNoticeDocumentProvider>();

    // --------
    // COMMANDS
    // --------
    For<IAdminUpdateCommandFor<AuthorizationToFlowMeterDocument>>().Use<AuthorizationToFlowMeterDocumentAdminUpdateCommand>();

    // -----------
    // APPLICATION
    // -----------
    For<IMyApplication>().Use<MyApplication>()

        // Instance Provider
        .Setter(x => x.DistributionListProvider).Is<DistributionListProvider>()
        .Setter(x => x.AuthorizationToFlowMeterDocumentRecallProvider).Is<AuthorizationToFlowMeterDocumentRecallProvider>()

        // Email Notifications
        .Setter(x => x.ApprovalToFlowEmailNotification).Is<ApprovalToFlowEmailNotification>()
        .Setter(x => x.DenialToFlowEmailNotification).Is<DenialToFlowEmailNotification>()
        .Setter(x => x.ApprovalToFlowRecalledEmailNotification).Is<ApprovalToFlowRecalledEmailNotification>()
        .Setter(x => x.RequestToFlowEmailNotification).Is<RequestToFlowEmailNotification>()
        .Setter(x => x.FirstDeliveryNoticeEmailNotification).Is<FirstDeliveryNoticeEmailNotification>();
}

1 Ответ

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

С атрибутом [SetterProperty] StructureMap попытается создать и прикрепить значение для свойства как часть конструкции объекта.

Однако именно атрибут setter требует реализации по умолчанию, поскольку он не может определить, какая реализация предназначена для использования при наличии нескольких реализаций или, особенно, если реализация по умолчанию не была добавлена.

С RequestToFlowEmailNotification.DistributionListProvider контейнер не знал, какую реализацию использовать.

Чтобы переопределить это поведение, используйте конфигурацию встроенного сеттера для RequestToFlowEmailNotification.DistributionListProvider

//...
.Setter(x => x.RequestToFlowEmailNotification)
    .Is<RequestToFlowEmailNotification>(_ => 
        _.Setter(d => d.DistributionListProvider)
            .Is<DistributionListProvider>()); //<<-- change to which ever one is needed

Обратите внимание на цепочку конфигурации Setter, чтобы настроить RequestToFlowEmailNotification, а затем внутреннюю DistributionListProvider

...