I am developing a NuGet package which contains shared code for various ASP.NET Core projects. I am planning to use the strategy pattern to solve the same problem in a few different ways. So there will be a few different implementations of a common interface. See - https://deviq.com/design-patterns/strategy-pattern
My question is - should the consumers of this package select the specific strategy they wish to utilize via a registration with the IoC container? I know that some NuGet packages just use static methods (e.g. JsonConvert.DeserializeObject), but I would like to avoid this since I have multiple, valid, differing implementations, and I would like the consumers of the package to be able to choose between them.
3 Answers 3
Your library should be stand-alone. It should work without any kind of dependency injection container, because that is an implementation detail of the application and a library should not care.
I think many people would appreciate if instead of an example in your docs of how to use your library with a specific dependency injection container, you would simply publish another package, using both your stand-alone package and a specific DI technology and providing helper functions that do all the wiring.
That way, if I do use for example the ServiceCollection that is default for most apps, I have an easy way to do so with your additional package, but if I use another mechanism or maybe even none at all, I can still include your package and don't have to worry about all the dependencies you bring that I explicitely do not want to use.
That is a common pattern.
Let's say you name your package "MyCoolAlgorithm" then you can have a package "MyCoolAlgorithm.Unity" or "MyCoolAlgorithm.ServiceCollection" or any other container technology you want to provide for people to make it easier using you library with that technology.
I have multiple, valid, differing implementations, and I would like the consumers of the package to be able to choose between them.
Good.
should the consumers of this package select the specific strategy they wish to utilize via a registration with the IoC container?
What IoC container? I don't need no stinking container to use NuGet, the Strategy Pattern, or choose my own "differing implementations".
Oh I see the problem. You need a better example of the Strategy Pattern. That's one in C# that actually puts the new
s high up the call stack where they belong.
When accessing them from a library they aren't much different:
Notice how that looks a bit like the Strategy Pattern diagram? This is from a fairly popular library.
Any one of those ISomething
types can stand in for Strategy
. The grey boxes can stand in for the ConcreteStrategies
. Only thing missing is the Context
. You can leave that as an exercise for your user. Or maybe you have something in mind for Context
. Fine, make the library user build one of these concrete types and hand it to you.
The important thing about the Strategy Pattern is that you don't have to know at compile time what you're using. It certainly isn't what IoC container someone talked you into using.
-
Thank you for the helpful answer! I appreciate it. :)Treker– Treker08/26/2022 15:55:39Commented Aug 26, 2022 at 15:55
Why do you have multiple strategies? There's two options here:
A One is universally superior to the others.
In this case, you can safely discard all the others and use the superior one by default.
B They each have their own strengths and weaknesses.
This is a justification to keep multiple strategies. Given the different pros and cons of each strategy, your consumer will want to choose the strategy that best fits their use case.
I would suggest making this choice optional. Provide a default implementation, but make it overridable when a consumer so chooses.
-
Obviously, since I am choosing to keep multiple strategies, "B" is the case in my scenario. I am asking about HOW the consumer should choose the strategy they want. Via DI or just choosing a class.Treker– Treker08/26/2022 15:25:26Commented Aug 26, 2022 at 15:25
Explore related questions
See similar questions with these tags.
IServiceCollection
(and other containers) which allow configuration to be provided/wired on app startup. For example, EasyNetQ (a wrapper library around RabbitMQ.Client) includes an extension method which can register EasyNetQ with the DI container: github.com/EasyNetQ/EasyNetQ/blob/develop/Source/…