I have the following classes which I'm having issues with resolving using SimpleInjector
.
Config Interface
Namespace Infrastructure.Base.Interfaces
public interface ILdapConfigService
{
.....
}
Session Interface
Namespace Infrastructure.Base.Interfaces
public interface ISessionService
{
LdapConnection GetConnection();
}
Session Implementation
Namespace Infrastructure.Base.Services
public class SessionService : ISessionService {
ILdapConfigService _ldapConfigService;
public SessionService (ILdapConfigService ldapConfigService)
{
_ldapConfigService = ldapConfigService;
}
public LdapConnection GetConnection()
{
.........
}
}
Config Service Implementation 1
namespace Infrastructure.Old.Services
public class OldConfigService : ILdapConfigService
{
....
}
Config Service Implementation 2
namespace Infrastructure.New.Services
public class NewConfigService : ILdapConfigService
{
....
}
The idea is to have the ISessionService
and SessionService
is in a base project. Then have different projects which implements the LdapConfigService
witch implements ILdapConfigService
from the base project.
The different projects will have services which makes use of a repository in the base class too.
I need to know how to register these interfaces, or is it even possible to register it like this?
Infrastructure.New.Service.SomeService
uses Infrastructure.Base.Interfaces.IRepository
.
Infrastructure.Old.Service.SomeOtherService
uses Infrastructure.Base.Interfaces.IRepository
.
Infrastructure.Base.Repositories.Repository
implements Infrastructure.Base.Interfaces.IRepository
.
Infrastructure.Base.Repositories.Repository
uses Infrastructure.Base.Interfaces.ISessionService
.
Infrastructure.Base.Services.SessionService
implements Infrastructure.Base.Interfaces.ISessionService
.
Infrastructure.Base.Services.SessionService
uses Infrastructure.Base.Interfaces.ILdapConfigService
.
Infrastructure.New.Services.LdapConfigService
implements Infrastructure.Base.Interfaces.ILdapConfigService
.
Infrastructure.Old.Services.LdapConfigService
implements Infrastructure.Base.Interfaces.ILdapConfigService
.
How can I register this logic with Simple Injector
. I used RegisterConditional
but that did not quite work, because the consumer of ILdapConfigService
sits in 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>();
Each LdapConfigService
talks to an app.config
where all the important information is loaded into.
Base does the whole implementation to OpenLdap
with exception with the Config with needs to be injected into the SessionService
so it talks to the right server. Who knew abstraction could get so complicated.
Is my design pattern perhaps flawed?
Is my design pattern perhaps flawed?
As long as you are sure you aren't violating the Liskov Substitution Principle, I can't find any flaws in it, although this design does make it a bit harder to configure the container.
I think the trick here is to create two ISessionService
implementations; one for the New
stuff, an one for the Old
stuff. This allows you to differentiate based on the types. This is needed, because Simple Injector's RegisterConditional
has the limitation that only allows you to look at the registration's direct consumer type. You are registering ILdapConfigService
conditionally, but it always gets injected into SessionService
. By giving each ILdpConfigService
its own ISessionService
, you allow making the condition based on the consumers of ISessionSerice
.
This limitation of Simple Injector is deliberate and exists to prevent the user from making invalid configurations. For instance, if SessionService
is registered as singleton, it will be impossible for it to have two different ILdapConfigServices
.
Since creating two ISessionService
implementation is a 'configuration trick', you can simply define the second implementation as part of your Composition Root and inherit it from the first. By doing so you can match based on types as shown below:
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));