Every now and then you come across something so obvious and simple, you wonder why you missed it before.
OK, every now and then I come across something so obvious and simple, I wonder why I missed it before!
Happened to me the other day, so I thought I’d add a post here, so I can find it again when I forget next time! I can’t afford therapy, so I work out my personal issues in my blog instead 🙂
Anyway, when I was wrapping the code I’d written to access Google Drive into a Nuget package, I needed to access the Google service account credentials from inside the package. The problem was that the package doesn’t know (nor should need to know) anything about the code using it, so doesn’t know where to pick up the credentials.
At the time, I took the decision to require the developer to have the credentials stored in a JSON file wittily named credentials.json, in the root folder of the application. This wasn’t ideal, as you may not want them there, you may already have a file of that name for something else, you may want to store the credentials in a database, or in an Azure secret or any number of other things. However, not knowing of any better solution, I went ahead and did it that way.
I came across the answer to this issue the other day whilst wrapping some other code up into another Nuget package, and couldn’t believe why I hadn’t thought of it. OK, I can believe it, because I’m dozy, but we’ll move quickly over that point!
Without dependency injection, the obvious way to pass settings into a class is to add them as parameters in the constructor. However, when using DI, we don’t create the object, so don’t call the constructor, so can’t pass anything in.
However, what we can do is inject a settings class. All we have to do is make sure that the settings class contains the right data. Turns out that this is really easy.
The latest package wraps up my standard code for an email service. That needs to know the mail server settings. The usual way to do this sort of thing is to create a settings class, and have Core populate it from (say) your app configuration file. For example, if you have the following in appSettings.json…
"Smtp": { "Server": "your.smtp.server", "Port": 999, "UserName": "your.username", "Password": "your.password", "FromEmail": "[email protected]", "FromName": "Jim Spriggs" }
…you can create a settings object as follows…
SmtpSettings smtpSettings = Configuration.GetSection("Smtp").Get<SmtpSettings>();
This assumes that Configuration is an injected reference.
What I didn’t realise is that if you add that object as a service, then it will get injected as-is in any code that requires it. As ail server settings are highly unlikely to change over the lifetime of the application, we can inject the object as a singleton…
services.AddSingleton(smtpSettings);
Note that we are passing in an object, not a type, so the object we set up here will be injected, not a new instance of the same type. That was the bit I’d missed until now.
Now when we inject the email service into one of our classes, it will have the settings class injected, with the appropriate data available.
All so obvious when you see it.
The end result is that my new Pixata.Email Nuget package can be set up in just a few lines, and allows the developer to choose how to load the settings that are to be accessed by the package. See the Github page for full instructions.
Now all I have to do is work out how to change the Google package without causing havoc for the other people using it. Although I only wrote these packages to make reuse easier for myself and my huge team of developers (ie my son!), it seems that other people have used them as well. Oh well, that’s another story for another day.
Be First to Comment