Who handles dependency Injection in a class library?
Suppose there is a class library
TestService
which requires some dependencies.
Whose responsibility would it be to handle it?
1. Let caller handle DI. This means caller will need to know about the underlying classes in the class library to be able to come up with the dependencies and use it. Seems a bit cumbersome? Like new TestService(dep1, dep2...), where deps could be interfaces defined in the class library
2. Providing default implementation in the class library ( maybe in constructor? ), so if dependencies are not passed in when creating the service, we create default concrete classes within the class library constructor and use them instead.
// make parameters optional, and create actual deps inside the constructor
TestService(null, null)
3. Other ways?31 Replies
Maybe define functionality for DL injection methods as interfaces in the library and make the user handle the ancillary DI config through this mechanism first which enables the use of the rest of library. Or a middleware handler that will allow you to inject all necessary dependencies at startup based on the libraries middleware handler extension , like the aspnet.security.oauth2.providers library. I’m interested in this as well because today I ran into compiling the eBay sdk for notification api and it was just interfaces and concrete solutions for which I had to extract all concretes and implement in my consuming project and inject with the libraries interface
Yes. Currently this is how it works.
TestService
takes in some deps which are all interfaces. In the class library I've also implemented concrete classes based on those interfaces.
I'm expecting the caller to create instances of the concrete classes first, and then pass those instances when creating TestService
.
Does this sound like a good approach?If it’s good enough for eBay….
Lol
I’d personally create a middleware extension where you can go builder.services.AddMYCoolLibrary(provider => { options.Dep1; … options.Dep2… })
Centralized and clean
That way if they want to use your library they gotta know what dependencies are available and required
Or you can use autofac
I think middleware extension sounds like a good idea, don't wanna complicate it too much
Maybe you can use .NET IoC container
Extension method is how most libraries do it. Simply add a dependency on
Microsoft.Extensions.DependencyInjection.Abstractions
@Pobiega Interesting. I looked up online, looks like way of doing it is extending IServiceCollection in the library? Something like below, and then call this method inside configure service in startup.cs?
Microsoft.Extensions.DependencyInjection.Abstractions
looks interesting, I'll look it up thanksyes
the
Microsoft.Extensions.DependencyInjection.Abstractions
exposes IServiceCollection
thats why you need itAh yep I just saw that too, thanks!
So in the main project, the user would instantiate those services with parameterisied constructors manually, then calling this static method should resolve all the other ones as it resolves all the dependencies recursively.
no, most of the time the user would only call the extensionmethod
builder.Services.AddSaltPeppersLibrary();
and thats itSomethings would require instantiating though. Eg. A concrete repository class constructor would take in a connection string, wouldn't the user need to instantiate it manually though before doing the mapping?
no
stuff like a connection string would be injected into the repository, probably via a config object
look at how EntityFramework does it, for example
so you can add your own extensionmethod overload that takes a configuration action, like
AddDbContext
does, or you simply configure the options object in your extention method and inject it into your repositoryYep. So normally repository call something like
ConfigurationManager.ConnectionStrings["applicationDatabase"].ConnectionString;
to get connection string.
So I just map IConfigurationManagerWrapper
to ConfigurationManagerWrapper
like below and it should auto resolve then right?
what, no
ConfigurationManager
is dead
thats .net framework stuffRepo takes in IConfigurationManagerWrapper
Something along those lines would probably work, yeah, but the exact implementation bothers me
as in, the idea is correct
lmao
Rip ConfigurationManager
:we_have_no_bugs:
Right, so it works but it's ancient
yeah, its the "old" way of doing application config
Would newer way be using
IConfiguration
?the new one,
IConfiguration
+ IOptions<T>
warning: big post incoming
$optionsappsettings.json:
src/Foo/FooOptions.cs:
src/Foo/FooServiceCollectionExtensions.cs:
Program.cs / Startup.cs:
Bar.cs:
Bar
here is your repositoryRight, so this appsettings.json is stored in the caller project. But class libraries should be agnostic of such settings, which is why you defined
FooOptions.cs
right?
Thanks btw!appsettings is from the "main" project, yes
class libs generally dont add their own configuration files, the beauty of
IConfiguration
is that it doesnt specify how a config is stored
you can add settings from a json file, a yaml file, environment variables, the CLI arguments, a database, whatever
if you want support for something that doesnt already exist, its easy to make your own configuration providerRight, the actual project using this library will be configuring the config via ConfigurationBuilder, and we will add the settings files from there.
Then we do something like
services.Configure<XXXSettings>(Configuration.GetSection("XXXSettings"));
And in the class library we can inject IOptions<XXXSettings>
Am I in 2024 now? 😆yes
services.Configure<XXXSettings>(Configuration.GetSection("XXXSettings"));
would be in your libs extension method, as would the FooOptions
class itself
so the only thing the user does is add the config lines to their config file/provider of choice and call your ext methodMuch is appreciated!
🙏
Think I got this! The code you wrote helped out a lot!
Extension method
This is the DatabaseOptions class
It would be injected into a class like below, eg. in a repository
yup
tack sa mycket 🙏 🙏 🙏