Reputation: 2663
I'm trying to inject a couple email accounts that I have in appsettings.json into an email service.
EDIT: My EmailRepository.cs
needs a DbContext
injected as well. I used @Nkosi 's answer, which worked without needing a DbContext. I'm planning on using DbContextPool
in production, so how do I pull one of those out in my ConfigureServices
method?
appsettings.json:
"SanSenders": [
{
"Host": "mail.theFourSeasons.com",
"FromName": "The Four Seasons",
"IsNoReply": true,
"IsSssl": true,
"Password": "tooGoodToBeTrue",
"Port": 465,
"Username": "[email protected]"
},
{
"Host": "mail.theFourSeasons.com",
"FromName": "Franki",
"IsNoReply": false,
"IsSssl": true,
"Password": "cantTakeMyEyesOffYou",
"Port": 465,
"Username": "[email protected]"
}
]
SanSender.cs:
public class SanSender
{
public string FromName { get; set; }
public string Host { get; set; }
public bool IsNoReply { get; set; }
public bool IsSsl { get; set; }
public string Password { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public async Task<bool> SendEmailAsync(
string toAddress, string subject, string htmlMessage)
{
throw new NotImplementedException();
}
}
EmailRepository.cs:
public class EmailRepository
{
public IEnumerable<SanSender> SanSenders { get; set; }
//Edit: I need a DbContext injected as well.
public EmailRepository(ApplicationDbContext applicationDbContext,
IEnumerable<SanSender> sanSenders)
{
SanSenders = sanSenders;
}
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<List<SanSender>>((settings) =>
{
Configuration.GetSection("SanSenders").Bind(settings);
});
services.AddScoped<EmailRepository>();
services.AddControllersWithViews();
}
The Controller:
public class HomeController : Controller
{
public HomeController(
IOptions<List<SanSender>> optionsSanSenders, EmailRepository emailService)
{
}
public IActionResult Index()
{
return View();
}
}
In the controller I added IOptions<List<SanSender>> optionsSanSenders
and I can get access to them there, but EmailService.cs
is in a class library and I would prefer to not add unnecessary dependencies to it.
The EmailService does have IEnumerable<SanSender> SanSenders
, but it has a zero length/count.
What am I doing wrong?
Upvotes: 7
Views: 6069
Reputation: 5155
Introducing an additional configuration level as mentioned in answer of Nkosi is not needed (anymore?) in .NET 6.
You can use IOptions<List<SanSender>>
to inject and fetch the configuration in classes.
Additionally I would recommend to use binding to tell how the configuration is fetched like
services.Configure<List<SanSender>>(
options => Configuration.Bind("SanSenders", options));
Upvotes: 1
Reputation: 247213
Change the approach.
public class SanSenderOptions {
public List<SanSender> SanSenders { get; set; }
}
Extract the settings from configuration and then register them where needed
public void ConfigureServices(IServiceCollection services) {
SanSender[] senders = Configuration.GetSection("SanSenders").Get<SanSender[]>();
services.Configure<SanSenderOptions>(options => {
options.SanSenders = senders.ToList();
});
services.AddScoped<EmailRepository>(sp =>
new EmailRepository(sp.GetRequiredService<ApplicationDbContext>(), senders));
services.AddControllersWithViews();
}
The repository will get the senders injected being resolved.
The controller should be refactored to get the configured options.
public class HomeController : Controller {
public HomeController(IOptions<SanSenderOptions>> optionsSanSenders,
EmailRepository emailService) {
var senders = options.Value.SanSenders; //<--
}
public IActionResult Index() {
return View();
}
}
Reference Configuration in ASP.NET Core
Reference Options pattern in ASP.NET Core
Upvotes: 7