Having something like a string parameter in a constructor makes dependency injection very messy. Think:
public class CurrencyActor
{
public CurrencyActor(string currency, IRepository repository)
{
...
There have been other questions (such as this one) to address this particular problem with dependency injection. Often this is solved by rethinking the design and refactoring.
However, what if it actually makes sense to have multiple versions of an object that are each responsible for different data (e.g. a CurrencyActor for each currency)? This is pretty normal when using an actor model such as Akka .NET, but makes sense even outside that domain.
What is the best way to create these multiple instances using dependency injection while passing in the initial state they need?
Having a dependency in a constructor is not messy, it's very very common. There is nothing wrong with this.
You could create a default props static method on the CurrencyActor that takes in your dependencies:
public static Props CreateProps(string currency, Irepository repo)
{
return Props.Create(() => new CurrrncyActor(currency, repo));
}
Then create as many as you like:
var usCurrency = system.ActorOf(CurrencyActor.CreateProps("US", someRepo), "US");
var swedishCurrency = system.ActorOf(CurrencyActor.CreateProps("SEK", someRepo), "SEK");
[Update]
Regarding the use of DI containers with Akka, this was listed as no. 2 out of the top 7 mistakes people make when using akka.net
https://petabridge.com/blog/top-7-akkadotnet-stumbling-blocks/
Thus it’s considered to be a good practice for actors to manage their own dependencies, rather than delegate that work to a DI framework.
So basically don't do it. And if you must, according to that article, Autofac is the best choice
[Update 2]
If you want to dynamically create new instances of the same Actor but change some initial state, then you could have a Supervisor that is responsible for creating them:
public class MatchesSupervisor : ReceiveActor
{
List<IActorRef> _matches = new List<IActorRef>();
public void MatchesSupervisor()
{
Receive<SomeCommandToStartANewMatch>(msg =>
{
// store the currently active matches somewhere, maybe on a FullTime message they would get removed?
_matches.Add(Context.ActorOf(MatchActor.Create(msg.SomeMatchId)));
}
}
}
In the above example, there is no DI container being used, and if each MatchActor needed something else, like an IRepository, then this would be passed into the MatchesSupervisor when it is created, and subsequently passed to each MatchActor when they are created.
It also kinda depends where the state is coming from, and what the mechanism is for starting a new Match - i've just presumed some other Actor is sending a message.
(I'm typing on an ipad so the above code might not actually compile but hopefully you get the idea, i also left out an implementation of MatchActor, but it would just be an Actor that gets some values passed into its constructor)
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With