Simple Injector dynamic context-based injection at runtime between two registrations - c#

I have a Mediator application using Simple Injector for command handler registration, and injection and handlers is all setup and working perfectly.
class DoWashingCommandHandler : IRequestHandler<DoWashingCommand,object>
{
IBus bus;
public DoWashingCommandHandler(IBus bus) { this.bus = bus; }
Task<object> Handle(DoWashingCommand command)
{
this.bus.Send(new OtheCommand());
}
}
I have a need for 2 registrations of a IBus implementations.
The first can be of any lifetime, the second has a background thread so i initially thought it would need to be a singleton but on review i believe it could also be of any lifetime and just have a static worker thread class within it (this would be important for scope):
// register as non-singleton to allow scope usage
// keep static worker thread as if it were Singleton
class DispatchOnBackgroundThread : IBus
{
static Worker = new Worker();
public Task<object> Send(object command)
{
Worker.Post(command);
}
public void Start(Container container, CancelationToken stoppingToken)
{
Worker.Start(container,stoppingToken);
}
class Worker
{
public void Post(object command) { /* snip */ }
public void Start(Container container, CancelationToken stoppingToken)
{ /* snip */ }
public void Thread()
{
/* loop */
var item = ReadFromQueue();
// get command handler type
// get command handler instance from container
// if instantiated instance has IBus dependency in this
// section then it must have used DispatchInThread as the
// concrete implementation for IBus (including if the handler
// calls container.GetInstance<IBus>()
handler.Handle(item.Request, cancellationToken);
}
// anything outside this Thread should use
// DispatchOnBackgroundThread for IBus
}
}
Then the registrations would be as follows (not sure how to avoid the double registration issue of IBus):
// i need to be able to register two types
container.Register<IBus,DispatchOnBackgroundThread>();
container.Register<IBus,DispatchInThread>();
// this would return any IBus references with DispatchOnBackgroundThread
var handler = this.container.GetInstance(requestHandlerType);
using(SomeSope.BeingScope(container))
{
// this would return any IBus references with DispatchInThread
var handler = this.container.GetInstance(requestHandlerType);
// and if handler or other code referenced container and called
// GetInstance, and IBus dependencies would be returned as
// DispatchInThread whilst in this scope
}
// this would return any IBus references with DispatchOnBackgroundThread
var other = this.container.GetInstance(requestHandlerType);
I think and in summary, this is a mix of Context-based injection and custom scope.
How can I achieve the above or is this a terrible code smell?
To give further context if required I need the above switchable resolved types in order to implement the solution of another question https://stackoverflow.com/a/61782405/915839
DI code is removed in above link, but i am very much using SimpleInjector in the actual implementation

I'm not sure I fully understand your use case, and what it is that leads to this, but what you can do is create a wrapper IBus implementation that forwards the call to the correct bus, while changing the forwarded bus implementation while running on a background thread.
This wrapper might look as follows:
class SwitchableBus : IBus
{
private readonly DispatchInCallingThread defaultBus;
private readonly DispatchOnBackgroundThread backgroundBus;
public SwitchableBus(
DispatchInCallingThread defaultBus, DispatchOnBackgroundThread backgroundBus)
{
this.defaultBus = defaultBus;
this.backgroundBus = backgroundBus;
this.Bus = defaultBus;
}
public IBus Bus { get; private set; }
public void SwitchToBackgroundBus() => this.Bus = this.backgroundBus;
public Task<object> Send(object command) => this.Bus.Send(command);
}
With this wrapper, you can use the following registrations:
container.Register<IBus, SwitchableBus>(Lifestyle.Scoped);
container.Register<SwitchableBus>(Lifestyle.Scoped);
container.Register<DispatchInCallingThread>(Lifestyle.Scoped);
container.Register<DispatchOnBackgroundThread>(Lifestyle.Scoped);
This allows you to have DispatchInCallingThread used in the graph as follows:
using(SomeSope.BeingScope(container))
{
var handler = this.container.GetInstance(requestHandlerType);
handler.Handle(request);
}
In other words, by default the DispatchInCallingThread is used.
And DispatchOnBackgroundThread can be used by the graph as follows:
using(SomeSope.BeingScope(container))
{
container.GetInstance<SwitchableBus>().SwitchToBackgroundBus();
var handler = this.container.GetInstance(requestHandlerType);
handler.Handle(request);
}
Concequence of this is, however, that you should always resolve within an active Scope. But that would be a good idea anyway, because it is likely there will be Scoped dependencies in a graph anyway. Simple Injector does not allow resolving a graph with Scoped dependencies outside the context of an active scope.

Related

How to pass parameter to a class whose dependencies are wired through IoC container?

I have a class that works with a network via multiple resources. Its constructor receives arguments that are resolved at runtime by IoC container (StructureMap):
public NetworkWorker(IRetryService retryService, ILog log)
{ ... }
What I need is to control the number of resources this class uses on a use-case level - for example, client A need NetworkWorker instance that allows only one operation at a time, while client B need 10 ops at a time.
Currently this number is hardcoded in the constructor. The only way I see is to add a method void Configure(int resourceCount) that each client of NetworkWorker would call with a different value. Or may be there's a better way I don't see?
This class can do different things, but number of resources is required for every method call (Get/Send/etc methods).
P.S. is this a known technique (with a Configure method)? If it is, what's the name for it? smth like 'two-step initialization'?
I'll presume this NetworkWorker has multiple methods (otherwise you could just add a parameter to that single method).
You could use a factory pattern:
public interface INetworkWorkerFactory
{
NetworkWorker Create(int numberOfResources);
}
public class NetworkWorkerFactory : INetworkWorkerFactory
{
private readonly IContainer _container;
public NetworkWorkerFactory(IContainer container)
{
_container = container;
}
public NewtorkWorker Create(int numberOfResources)
{
var retryService = _container.GetInstance<IRetryService>();
var log = _container.GetInstance<ILog>();
return new NewtorkWorker(retryService, log, numberOfResources);
}
}
(or simply inject the required dependencies instead of the container)
and then simply
private readonly INetworkWorkerFactory _networkWorkerFactory;
public C(INetworkWorkerFactory networkWorkerFactory)
{
_networkWorkerFactory = networkWorkerFactory;
}
public void M()
{
var networkWorker = _networkWorkerFactory.Create(10);
}
Autofac uses delegate factories for this.
Other containers have equivalent mechanisms of providing auto-generated Abstract Factories - #ploeh has an awesome SO post aggregating examples.
The code in your question would look like so:
public delegate NetworkWorker Factory(IRetryService retryService);
public NetworkWorker(IRetryService retryService, ILog log)
{ ... }
A consumer would look like so (stolen from Alex's answer)
readonly NetworkWorker.Factory _networkWorkerFactory;
public C(NetworkWorker.Factory networkWorkerFactory)
{
_networkWorkerFactory = networkWorkerFactory;
}
public void M()
{
var networkWorker = _networkWorkerFactory(10);
...
}
The key difference is that you do not declare either an interface or an impl for the Abstract Factory - the delegate is the interface and Autofac 'just knows' to make the rest happen.
Another benefit of this approach (other than the code reduction) is that there's a natural path to transitioning the code to Pure DI)

Using Dependency Injection (Autofac) and avoiding Service Locator pattern

I'm taking a stab at properly implementing DI in my Xamarin Android application using Autofac but I'm having issues understanding how I should handle instantiating objects that require data passed into their constructor. For example one of our viewmodels needs a string and a guid passed in to its constructor. Something that looks promising is Delegate Functions offered by Autofac. This is where the line between Service Locator and DI appears to blur, at least in my mind. In order to use the Delegate Functions you must call container.Resolve, or rather it's recommended to use the IComponentContext.Resolve. Many blogs recommend not using Resolve outside of the bootstapper/main entry point. Is there something I am missing here? Is there a better way to create objects using DI? I am familiar with the Factory pattern to create objects but I feel that I'm losing the benefits of DI going that route since I am back to manually passing in services/objects to the newly created object. Thanks for any feedback!
It is not recommended to call container.Resolve() to use a delegate factory. The correct way is shown on the delegate factories page that you already linked to:
public class Portfolio
{
Shareholding.Factory ShareholdingFactory { get; set; }
IList<Shareholding> _holdings = new List<Shareholding>();
public Portfolio(Shareholding.Factory shareholdingFactory)
{
ShareholdingFactory = shareholdingFactory;
}
public void Add(string symbol, uint holding)
{
_holdings.Add(ShareholdingFactory(symbol, holding));
}
}
When the docs show an explicit call to container.Resolve() you should realize that they are not showing best practice, they are simply proving that it can be resolved without coding up a whole new class (like Portfolio) to consume it.
In order to use the Delegate Functions you must call container.Resolve
No, at least not in this case.
Assuming you have registered Shareholding. Now you can ask a dependency on Func<Shareholding>, ie. something hat returns a Shareholding when you call it.
But as the Shareholding constructor has two parameters, it cannot be resolved without supplying those parameters. Just add them to the declaration like this: Func<string, uint, Shareholding>. Now you can resolve the dependency when you supply those parameters.
Here is a better example.
I recently (yesterday) faced the same problem I wound up using the ServiceClient object you see in the code below. This object addresses your question about using the container outside of the bootstrapper. I have read arguments that say not to pass the container around and I think they are mostly valid. In my case however the ServiceClient class represents a single point of entry into my service layer so I thought it was appropriate to pass the container.
The way I use this at the moment is to pass an instance of ServiceClient into my BaseController:
// In Global.asax.cs
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<ServiceClient>().As<IServiceClient>();
BaseController:
public abstract class BaseController<T> : Controller where T :class
{
public IServiceClient ServiceClient { get; set; }
public BaseController(IServiceClient serviceClient)
{
ServiceClient = serviceClient;
}
}
In my controller I can resolve, instantiate, and call a service that uses unmanaged resources with just one line like this:
myViewModel = await ServiceClient.OfType<ICustomerService>().TryAsync(x => x.GetCustomerByID(id));
ServiceClient:
public class ServiceClient : IServiceClient
{
private IComponentContext _container;
public ServiceClient(IComponentContext container)
{
_container = container;
}
public ServiceCallWrapper<T> OfType<T>() where T : class, IDisposable
{
return new ServiceCallWrapper<T>(_container);
}
}
public class ServiceCallWrapper<T> : IServiceCallWrapper<T> where T : class, IDisposable
{
private IComponentContext _container;
internal ServiceCallWrapper(IComponentContext container)
{
_container = container;
}
public void Try(Action<T> method)
{
// consider try/catch/log/throw here
using (T client = _container.Resolve<T>())
{
method(client);
}
}
public TResult Try<TResult>(Func<T, TResult> method)
{
using (T client = _container.Resolve<T>())
{
return method(client);
}
}
public async Task TryAsync(Func<T, Task> method)
{
using (T client = _container.Resolve<T>())
{
await method(client);
}
}
public async Task<TResult> TryAsync<TResult>(Func<T, Task<TResult>> method)
{
using (T client = _container.Resolve<T>())
{
return await method(client);
}
}
}

Event dispatching library with IoC

In the past I've built a MessageDispatcher component that scans an assembly for types decorated with certain attributes and initializes an instance of each. Then, when any object is fed to the MessageDispatcher instance, every previously initialized instance which contains a method which signature contains the type of the passed object has said method triggered with the specified parameter. For example, in a scenario like:
[Listener]
public class MyListener
{
MessageDispatcher _dispatcher; //Assigned elsewhere
[MessageListener]
public async Task DoSomething(int value)
{
var otherValue = await _dispatcher.Next<string>();
Console.WriteLine($"{value} is {otherValue}.");
}
}
The following code initializes an instance of the MyListener class, calls DoSomething and prints "7 is okay.":
var listener = new MessageDispatcher(typeof (ListenerAttribute));
listener.Dispatch(7);
listener.Dispatch("okay");
I would like to know if there are any libraries out there that are dedicated to or include a service like such. It has to be able to:
Scan assemblies and initialize types based on an attribute.
Dynamically "subscribe" to certain types
"Wait" on a value to be pumped from the dispatcher (like with the Next method in my example).
(as library recommendations is not allowed per the SO rules, here is an attempt to instead answer with an implementation)
You can get that with virtually any IoC. All they need is to be able to register services using an attribute or some other conventional way.
As for the message dispatching. Just create an interface like IMessageHandler<TMessage>. Implement it on all classes that should handle messages.
Example:
public interface IMessageHandler<TMessage>
{
void Handle(TMessage msg);
}
public class SomeService : IMessageHandler<UserCreated>
{
//[.. all other methods ..]
public void Handle(UserCreated msg)
{
// ...
}
}
To publish messages you create a dispatcher. Since you use a container you do not have to make it static. Use your container inside it (service location) to dispatch the messages. Now some peeps might say oohh no, service location is anti-pattern, buhuhuhu. Well no. Not in all cases. In this case it's an implementation details in a class with the specific purpose to identify and invoke other classes.
public interface IMessageDispatcher
{
void Dispatch<TMessage>(TMessage msg);
}
// The actual implementation differs
// depending on your choice of container.
public class ContainerBasedMessageDispatcher : IMessageDispatcher
{
Container _container;
public ContainerBasedMessageDispatcher(Container container)
{
_container = container;
}
public void Dispatch<TMessage>(TMessage message)
{
using (var scope = container.BeginLifetimeScope())
{
var handlers = scope.Resolve<IEnumerable<IMessageHandler<TMessage>>();
foreach (var handler in handlers)
{
handler.Handle(message);
}
}
}
}
The code is written directly in SO. So it might not work as-is. But hopefully it's given you an idea how to achieve what you want.
Usage:
public class UserService
{
IMessageDispatcher _dispatcher;
public UserService(IMessageDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public void Create(User user)
{
//[...]
_dispatcher.Dispatch(new UserCreated(user.Id));
}
}
this do however not dynamically allow you to subscribe on what you want. If just ignoring unwanted messages is not feasible. Then this answer is not for you.

How to unit test decorator registrations using SimpleInjector 3+?

Follow up to an older question here. Say I have a registration like the following:
container.Register(typeof(IHandleCommand<>), _handlerAssemblies, Lifestyle.Transient);
container.RegisterDecorator(typeof(IHandleCommand<>),
typeof(MetricsCommandHandlerWrapper<>), Lifestyle.Singleton);
Where the MetricsCommandHandlerWrapper is defined like so:
public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T> where T: ICommand
{
private readonly ICollectMetrics _metrics;
private readonly Func<IHandleCommand<T>> _handlerFactory;
public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
Func<IHandleCommand<T>> handlerFactory)
{
_metrics = metrics;
_handlerFactory = handlerFactory;
}
public async Task HandleAsync(T command)
{
// code to record metrics around command handling which eventually invokes
await _handlerFactory().HandleAsync(command).ConfigureAwait(false);
}
}
How can I write a unit test that asserts the actual decoratee handlers are registered with Transient lifestyle?
I have tried composing the root and inspecting the registration for a closed IHandleCommand<FakeCommand> type, which reveals an ImplementationType of MetricsCommandHandlerWrapper<FakeCommand> as expected. Invoking GetRelationships() on that registration reveals its 2 dependencies, ICollectMetrics and the one I am interested in, the Func<IHandleCommand<FakeCommand>> factory delegate, which is registered as a Singleton. However invoking .Dependency.GetInstance() on that factory delegate throws an exception that the instance producer returned null.
Is there any way to assert that the inner decoratee is registered as Transient, and if so, how?
The use of the Func<T> delays the building of the object graph, and from perspective of the diagnostic system, the graphs stops at that point. So, it's not possible to do this analysis.
Instead of completely relying on Simple Injector's internals however, you can also choose to make some minor changing in your application to allow testing decorators.
What you can do is implement an IDecorator abstraction on your decorators:
public interface IDecorator {
object Decoratee { get; }
}
Now each decorator can implement this interface. For the MetricsCommandHandlerWrapper<T>, it might look as follows:
public class MetricsCommandHandlerWrapper<T> : IHandleCommand<T>, IDecorator where T: ICommand
{
private readonly ICollectMetrics _metrics;
private readonly Func<IHandleCommand<T>> _handlerFactory;
public MetricsCommandHandlerWrapper(ICollectMetrics metrics,
Func<IHandleCommand<T>> handlerFactory) {
_metrics = metrics;
_handlerFactory = handlerFactory;
}
public object Decoratee { get { return _handlerFactory(); }
public async Task HandleAsync(T command) { ... }
}
On top of the IDecorator interface, you can define a simple extension method:
public static IEnumerable<Type> GetDecoratorChain(this IDecorator decorator) {
while (decorator != null) {
yield return decorator.GetType();
decorator = decorator.Decoratee as IDecorator;
}
}
Inside your unit test you can now resolve a handler and ask for the list of applied decorators. Using this list you can verify whether decorators are applied in the correct order.

How to deal with run-time parameters when using lifetime scoping?

Warning, long post ahead.
I've been thinking a lot about this lately and I'm struggling to find a satisfying solution here. I will be using C# and autofac for the examples.
The problem
IoC is great for constructing large trees of stateless services. I resolve services and pass the data only to the method calls. Great.
Sometimes, I want to pass a data parameter into the constructor of a service. That's what factories are for. Instead of resolving the service I resolve its factory and call create method with the parameter to get my service. Little more work but OK.
From time to time, I want my services to resolve to the same instance within a certain scope. Autofac provides InstancePerLifeTimeScope() which is very handy. It allows me to always resolve to the same instance within an execution sub-tree. Good.
And there are times when I want to combine both approaches. I want data parameter in constructor and have have the instances scoped. I have not found a satisfying way to accomplish this.
Solutions
1. Initialize method
Instead of passing data into the constructor, just pass it to Initialize method.
Interface:
interface IMyService
{
void Initialize(Data data);
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public void Initialize(Data data)
{
mData = data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myService = context.Resolve<IMyService>();
myService.Init(data);
// somewhere else
var myService = context.Resolve<IMyService>();
After resolving the service for the first time and calling Initialize I can happily resolve within the same context and get the same initialized instance. I don't like the fact that before calling Initialize I have an unusable object. There is a danger that the instance will be resolved and used somewhere else before I call Initialize().
2. Holder pattern
This is a pattern that holds a reference to the data object and instead of injecting the data object itself I inject the holder object.
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(IDataHolder dataHolder)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>();
builder.RegisterType<DataHolder>().As<IDataHolder>().InstancePerLifetimeScope();
Usage:
var holder = context.Resolve<IDataHolder>();
holder.Data = data;
// somewhere else
var myService = context.Resolve<IMyService>();
This is a little bit better as I moved the responsibility of holding an instance to a different class. I can now use the holder in other services too. Other advantage is that I can hot swap data in holder if necessary. I don't like the fact that it obfuscates the code and adds another interface I have to mock during testing.
3. Let container hold the instance
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(Data data)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myServiceFactory = context.Resolve<Func<Data, IMyService>>();
myServiceFactory(data);
// somewhere else
var myService = context.Resolve<IMyService>();
That's right. I don't store the result of a factory call anywhere, because autofac stores it for me. This is pretty surprising to anybody who will read the code. I'm not sure if autofac was even meant to be used like this. Nice thing about this is that I need neither an extra initialize method nor extra class for holding instance.
Question
What is your take on this? How do you handle a situation with run-time data parameters and lifetime scoping? Am I missing a better approach?
Autofac now supports this out of the box with an extension to the lifetime scopes. The BeginLifetimeScope() method has an overload that takes an Action<ContainerBuilder> that allows for adding new registrations specific to only that lifetime scope. So for the given example it would look something like:
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope(
builder =>
{
builder.RegisterInstance(new Data(....));
}))
{
// References to 'IMyService' will always be resolved to the same instance within this lifetime scop
// References to 'Data' will be resolved to the instance registered just for this lifetime scope.
var svc = scope.Resolve<IMyService>();
}
Most of the time, runtime data is the non static info you need to pass in any process, like x in a math function, so the easiest way to deal with it is using a parameter in the function:
class MyService : IMyService
{
public MyService(){}
public void DoStuff(Data mData)
{
//...
}
}
var myService = context.Resolve<IMyService>();
myService.DoStuff(data);
But, assuming your example is just a example and you are asking because your class need to keep runtime data to run more processes and you don't wanna to pass the same argument in every function:
1.- If you don't loose the scope of the runtime data in every Resolve you can resolve with TypedParameter:
Ej:
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//any point of your app
Data mData = new Data("runtimeData"); // must to be accesible in every place you Resolve
using(var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service.DoStuff();
}
using(var scope = container.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service2.DoStuff();
}
2.- If you don't have a reference to runtime data in every place you are resolving you can RegisterInstance when and where you create runtime data. Autofac should inyect mData instance thanks to Direct Depency Policy
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//where you create or modify runtime data. When runtime data changes you have to update the container again.
var mData = new Data("runtimeData");
updatedBuilder= new ContainerBuilder();
updatedBuilder.RegisterInstance(mData).As<Data>
updatedBuilder.Update(builder);
//in any point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>();
service.DoStuff();
}
//in any other point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>();
service2.DoStuff();
}
My take on this is that you've done about as good as you can do. The only niggle that I have about it is that Autofac doesn't really do a great job of helping you manage those lifetime scopes, so you're stuck calling their BeginLifetimeScope somewhere. And they can be nested.
Ninject, on the other hand, does some really cool stuff that doesn't require turning your brain inside-out. Their named scope extension makes it possible for you to create a (gasp) named scope and bind the lifetime of objects within that scope. If you are using factories (clearly you are, judging from the question) you'll also want to use the context preservation extension, so that stuff activated out of factories gets the lifetime management from the named scope that the factory was activated within. Bindings wind up looking something like this:
var scopeName = "Your Name Here";
Bind<TopLevelObject>().ToSelf().DefinesNamedScope(ScopeName);
Bind<ISomeScopedService>().To<SomeScopedService>().InNamedScope(ScopeName);
// A minor bit of gymnastics here for factory-activated types to use
// the context-preservation extension.
Bind<FactoryActivatedType>().ToSelf().InNamedScope(ScopeName);
Bind<IFactoryActivatedType>().ToMethod(x => x.ContextPreservingGet<FactoryActivatedType>());
The nice part about this is that the scope of those bindings is specifically tied to the named scope rather than just being tied to whatever the nearest lifetime scope up the chain is. IMHO, it makes the lifetimes of those objects much more predictable.
Many IoC frameworks support registration of a factory function (or lambda expression), that takes as one of its arguments an instance of the container / scope / resolution context itself.
This allows using additional levels of indirection, as well as the use of information that uniquely identifies the context or scope. Additionally many provide hooks, like event handlers or the option to derive from a life cycle scope class, to interact with a scope being started or ended.
Principle
For AutoFac and your specific example, the following principle would work, using additional levels of indirection in registration.
// Inject `Data` instance resolved from current scope.
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
// Extra level of indirection, get a "factory" for a 'Data' instance.
builder.Register<Data>(ctx => ctx.Resolve<Func<Data>>()()).InstancePerLifetimeScope();
// The indirection resolves to a map of scopes to "factory" functions.
builder.Register<Func<Data>>(ScopedDataExtensions.GetFactory);
We can use any available unique property on a context / scope to construct this mapping.
// Maps scopes to data "factories".
public static class ScopedDataExtensions
{
private static readonly ConcurrentDictionary<object, Func<Data>> _factories = new ConcurrentDictionary<object, Fund<Data>>();
public static Func<Data> GetFactory(this IComponentContext ctx)
{
var factory = default(Func<Data>);
return _factories.TryGetValue(ctx.ComponentRegistry, out factory) ? factory : () => null;
}
public static void SetFactory(this ILifetimeScope scope, Func<Data> factory)
{
_factories[scope.ComponentRegistry] = factory;
}
}
We can use it like this to supply "local" data instances to be injected into our scoped service instances.
var myData = new Data("nested");
nestedScope.SetFactory(() => myData);
// ...
var myService = nestedScope.Resolve<IMyService>();
A more complete and generic example for AutoFac follows below.
Generic extension class for this pattern
public static class AutofacScopeExtensions
{
// Map from context => factories per type
public static readonly ConcurrentDictionary<object, ConcurrentDictionary<Type, object>> _factories =
new ConcurrentDictionary<object, ConcurrentDictionary<Type, object>>();
private static class ScopedFactoryFor<T>
{
public static Func<T> DefaultFactory = () => default(T);
public static Func<T> GetFactory(ConcurrentDictionary<Type, object> fromContext)
{
object factory;
return (fromContext.TryGetValue(typeof(T), out factory)) ? (Func<T>)factory : DefaultFactory;
}
}
public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle>
WithContextFactoryFor<T>(this ContainerBuilder builder, Func<T> defaultFactory = null)
{
if (defaultFactory != null)
ScopedFactoryFor<T>.DefaultFactory = defaultFactory;
builder.Register<Func<T>>(AutofacScopeExtensions.GetFactory<T>);
return builder.Register<T>(ctx => ctx.Resolve<Func<T>>()());
}
public static IContainer BuildContainer(this ContainerBuilder builder)
{
var container = builder.Build();
container.ChildLifetimeScopeBeginning += OnScopeStarting;
return container;
}
public static ILifetimeScope SetScopeFactory<T>(this ILifetimeScope scope, Func<T> factory)
{
ScopeMapFor(scope)[typeof(T)] = factory;
return scope;
}
public static ILifetimeScope SetScopeValue<T>(this ILifetimeScope scope, T instance)
{
return SetScopeFactory(scope, () => instance);
}
public static Func<T> GetFactory<T>(IComponentContext ctx)
{
return ScopedFactoryFor<T>.GetFactory(ScopeMapFor(ctx));
}
private static ConcurrentDictionary<Type, object> ScopeMapFor(IComponentContext ctx)
{
return _factories.GetOrAdd(ctx.ComponentRegistry, x => new ConcurrentDictionary<Type, object>());
}
private static void OnScopeStarting(object sender, LifetimeScopeBeginningEventArgs evt)
{
evt.LifetimeScope.ChildLifetimeScopeBeginning += OnScopeStarting;
evt.LifetimeScope.CurrentScopeEnding += OnScopeEnding; // so we can do clean up.
}
private static void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs evt)
{
var map = default(ConcurrentDictionary<Type, object>);
if (_factories.TryRemove(evt.LifetimeScope.ComponentRegistry, out map))
map.Clear();
}
}
Allowing the following syntax for registration:
builder.WithContextFactoryFor<Data>(() => new Data("Default")).InstancePerLifetimeScope();
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
And resolve like:
// ...
var myData = new Data("Some scope");
// ...
context.SetScopeFactory(() => myData);
// ...
// Will inject 'myData' instance.
var myService = context.Resolve<IMyService>();
Simpler Alternative
If you explicitly start nested scopes and at the time you do, you know how the scoped Data instance is to be created, you can skip the extension class and register the "factory" delegate with the nested scope when you create it:
var nestedScope = container.BeginLifetimeScope(
"L2",
x => x.RegisterInstance<Func<Data>>(() => new Data("nested")));
If I understand you correctly you want to use factories by delegating object creation to container while passing some parameters to its constructor.
This is implemented in Castle Windsor with typed factory facility.
Example classes we want to resolve:
public interface IMyService
{
void Do();
}
public class MyService : IMyService
{
private readonly Data _data;
private readonly IDependency _dependency;
public MyService(Data data, IDependency dependency)
{
_data = data;
_dependency = dependency;
}
public void Do()
{
throw new System.NotImplementedException();
}
}
public class Data
{
}
public interface IDependency
{
}
public class Dependency : IDependency
{
}
We create a factory interface:
public interface IMyServiceFactory
{
IMyService Create(Data data);
void Release(IMyService service);
}
We won't be implementing this interface because Castle Windsor will be generating an implementation with Dynamic Proxy. There's an important detail here: parameter name(data) in factory method and the one in the constructor should match.
Then we do the registration and try to resolve the values.
[Test]
public void ResolveByFactory()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyServiceFactory>().AsFactory());
container.Register(Component.For<IMyService>().ImplementedBy<MyService>().LifestyleScoped());
container.Register(Component.For<IDependency>().ImplementedBy<Dependency>().LifestyleScoped());
IMyServiceFactory factory = container.Resolve<IMyServiceFactory>();
IMyService myService1;
IMyService myService2;
using (container.BeginScope())
{
myService1 = factory.Create(new Data());
myService2 = factory.Create(new Data());
myService1.Should().BeSameAs(myService2);
}
using (container.BeginScope())
{
IMyService myService3 = factory.Create(new Data());
myService3.Should().NotBeSameAs(myService1);
myService3.Should().NotBeSameAs(myService2);
}
}
You will see that the object created in the same scope are the same references. Let me know if this is the behaviour you want.

Categories

Resources