Lets say that I have two services that depend on one interface:
class Service1
{
...
Service1(IDependency dependency) { ... }
...
}
and
class Service2
{
...
Service2(IDependency dependency) { ... }
...
}
IDependency is registered by some concrete implementation. How can I register decorator to IDependency implementation that can be consumed only by Service2? In other words IDependency should be resolved to an instance of the decorator only inside Service2. Is it possible?
You can use context-based injection
// Register decorators first
container.RegisterConditional<IDependency, DependencyDecorator1>(
c => c.Consumer.ImplementationType == typeof(Service1));
container.RegisterConditional<IDependency, DependencyDecorator2>(
c => c.Consumer.ImplementationType == typeof(Service2));
// Register the real implementation last using !c.Handled
container.RegisterConditional<IDependency, RealImplementationDependency>(
c => !c.Handled);
See the note from the documentation:
Note: In many cases context based injection is not the best solution, and the design should be reevaluated. In some narrow cases however it can make sense.
Alternatively, you could derive separate interfaces that extend IDependency
and use those, one for each service. This might be more appropriate to differentiate the dependencies. In this case, you'd simply register different implementation/instances for each interface.
For example, you might have a file storage abstraction against a cloud storage service. The basic interface encapsulates all the file storage actions, then you extend it for specific buckets within the storage container. You can provide a single implementation (via delegate registration) that takes the storage bucket as a constructor parameter for each named interface. The use of named interfaces that identify the bucket purpose enhance code comprehension.
public interface IFileStorage
{
...
}
public interface IUploadStorage : IFileStorage { /* empty interface */ }
public interface IContentStorage : IFileStorage { /* empty interface */ }
public class FileStorage : IUploadStorage, IContentStorage
{
public FileStorage(string containerName) { ... }
...
}
public UploadService(IUploadStorage storage)
{
...
}
public ContentService(IContentStorage storage)
{
...
}
container.Register<IUploadStorage>(() = new FileStorage(Containers.Upload));
container.Register<IContentStorage>(() = new FileStorage(Containers.Content));