如何根据最顶层的父名称空间注册服务条件

How to register service conditional based on top most parent namespace

我有以下 classes,我在使用 SimpleInjector.

解决问题时遇到了问题

配置界面

Namespace Infrastructure.Base.Interfaces
public interface ILdapConfigService 
{
    ..... 
}

会话界面

Namespace Infrastructure.Base.Interfaces
public interface ISessionService 
{
    LdapConnection GetConnection(); 
}

会话实施

Namespace Infrastructure.Base.Services
public class SessionService : ISessionService {

    ILdapConfigService _ldapConfigService;        
    public SessionService (ILdapConfigService ldapConfigService) 
    {
        _ldapConfigService =  ldapConfigService;
    }

    public LdapConnection GetConnection()
    {
        .........
    }
}

配置服务实现 1

namespace Infrastructure.Old.Services
public class OldConfigService : ILdapConfigService 
{
    .... 
}

配置服务实现 2

namespace Infrastructure.New.Services
public class NewConfigService : ILdapConfigService 
{
    .... 
}

这个想法是让 ISessionServiceSessionService 在一个基础项目中。然后有不同的项目从基础项目中实现 LdapConfigService 实现 ILdapConfigService

不同的项目也将提供使用基础库中的存储库的服务 class。

我需要知道如何注册这些接口,或者甚至可以这样注册吗?

Infrastructure.New.Service.SomeService 使用 Infrastructure.Base.Interfaces.IRepositoryInfrastructure.Old.Service.SomeOtherService 使用 Infrastructure.Base.Interfaces.IRepository.

Infrastructure.Base.Repositories.Repository 实现 Infrastructure.Base.Interfaces.IRepositoryInfrastructure.Base.Repositories.Repository 使用 Infrastructure.Base.Interfaces.ISessionService.

Infrastructure.Base.Services.SessionService 实施 Infrastructure.Base.Interfaces.ISessionServiceInfrastructure.Base.Services.SessionService 使用 Infrastructure.Base.Interfaces.ILdapConfigService.

Infrastructure.New.Services.LdapConfigService 实施 Infrastructure.Base.Interfaces.ILdapConfigService.

Infrastructure.Old.Services.LdapConfigService 实施 Infrastructure.Base.Interfaces.ILdapConfigService.

如何使用 Simple Injector 注册此逻辑。我使用了 RegisterConditional 但这不太奏效,因为 ILdapConfigService 的消费者位于 base.

container.RegisterConditional<
     ILdapConfigService,
     Old.Services.LdapConfigService>(
     c =>  c.Consumer.ImplementationType.Namespace.Contains("Old"));

container.RegisterConditional<
     ILdapConfigService,
     New.Services.LdapConfigService>(
     c =>  c.Consumer.ImplementationType.Namespace.Contains("New"));

container.Register<ISessionService, SessionService>();
container.Register<ILdapRepository, LdapRepository>(); 

每个 LdapConfigService 与一个 app.config 对话,所有重要信息都加载到其中。

Base 完成 OpenLdap 的整个实现,但 Config 需要注入 SessionService 以便它与正确的服务器通信。谁知道抽象会变得如此复杂。

我的设计模式可能有缺陷吗?

Is my design pattern perhaps flawed?

只要你确定你没有违反 Liskov 替换原则,我就找不到它的任何缺陷,尽管这种设计确实让配置容器变得有点困难。

我认为这里的技巧是创建两个 ISessionService 实现;一个用于 New 东西,一个用于 Old 东西。这使您可以根据类型进行区分。这是必需的,因为 Simple Injector 的 RegisterConditional 有限制,只允许您查看注册的直接消费者类型。您正在有条件地注册 ILdapConfigService,但它总是被注入 SessionService。通过为每个 ILdpConfigService 提供自己的 ISessionService,您可以根据 ISessionSerice.

的消费者创建条件

Simple Injector 的这种限制是故意的,存在是为了防止用户进行无效配置。例如,如果SessionService被注册为单例,它不可能有两个不同的ILdapConfigServices

由于创建两个 ISessionService 实现是一个 'configuration trick',您可以简单地将第二个实现定义为组合根的一部分并从第一个实现继承。通过这样做,您可以根据类型进行匹配,如下所示:

class NewSessionService : SessionService {
    public NewSessionService(ILdabConfigService s) { ... }
}

container.RegisterConditional<ISessionService, SessionService>(
    c => c.Consumer.ImplementationType.Namespace.Contains("Old"));

container.RegisterConditional<ILdabConfigServices, Old.LdapConfigService>(
    c => c.Consumer.ImplementationType == typeof(SessionService));


container.RegisterConditional<ISessionService, NewSessionService>(
    c => c.Consumer.ImplementationType.Namespace.Contains("New"));

container.RegisterConditional<ILdabConfigServices, New.LdapConfigService>(
    c => c.Consumer.ImplementationType == typeof(NewSessionService));