使用 StructureMap 配置混凝土 Class 的 属性
Configure a Property of a Concrete Class using StructureMap
我在 Application
实例中使用了一组通用电子邮件 类。它们都共享相同的界面,但我需要能够(可选)"shim-in" 另一个 "common" 类型的实例作为 属性.
从这里开始:鉴于此起点...
注意,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
{
}
让我们添加: 现在让我们创建另一个 IInstanceProvider 并将其添加到应用程序...
但首先,请注意 IEmailNotification 和 IInstanceProvider 是常见类型而不是 "generic types"...这意味着它们不是 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
}
此时 StructureMap 不再理解如何填充...
- RequestToFlowEmailNotification.DistributionListProvider
问:如何更新注册表以强制正确填写 StructureMap?
下面是我的整个注册表...
注意:
我不想设置默认值...有没有办法在不设置默认值的情况下做到这一点?
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>();
}
使用 [SetterProperty]
属性,StructureMap 将尝试为 属性 构建并附加一个值作为对象构建的一部分。
但是 setter 属性需要默认实现,因为它无法确定在有多个实现时要使用哪个实现,尤其是在未添加默认实现的情况下。
对于 RequestToFlowEmailNotification.DistributionListProvider
,容器不知道要使用哪个实现。
要覆盖此行为,请对 RequestToFlowEmailNotification.DistributionListProvider
使用内联 setter 配置
//...
.Setter(x => x.RequestToFlowEmailNotification)
.Is<RequestToFlowEmailNotification>(_ =>
_.Setter(d => d.DistributionListProvider)
.Is<DistributionListProvider>()); //<<-- change to which ever one is needed
注意 Setter
配置的链接,以便设置 RequestToFlowEmailNotification
然后是内部 DistributionListProvider
我在 Application
实例中使用了一组通用电子邮件 类。它们都共享相同的界面,但我需要能够(可选)"shim-in" 另一个 "common" 类型的实例作为 属性.
从这里开始:鉴于此起点...
注意,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
{
}
让我们添加: 现在让我们创建另一个 IInstanceProvider 并将其添加到应用程序...
但首先,请注意 IEmailNotification 和 IInstanceProvider 是常见类型而不是 "generic types"...这意味着它们不是 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
}
此时 StructureMap 不再理解如何填充...
- RequestToFlowEmailNotification.DistributionListProvider
问:如何更新注册表以强制正确填写 StructureMap?
下面是我的整个注册表...
注意:
我不想设置默认值...有没有办法在不设置默认值的情况下做到这一点?
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>();
}
使用 [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