4

I've read a dozen questions here on SO and at least 4 blog posts but I cannot get this to work in a VS2017 solution with multiple class library projects. However, I can get it to work with a solution with a web application and one class library, albeit with a different pattern than the one I've found in the documentation and here on SO.

My solution contains 5 projects a WebApplication, Testing, Infrastructure, Services, Domain (the latter three are class libraries).

In the infrastructure project I have created a class called EmailConfigurationSettings and registered it in the StartUp class of the WebApp.

This class is in class library:

public class EmailConfigurationSettings
{
    public string Provider { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
}

This is in StartUp.cs in WebApp:

services.Configure<EmailConfigurationSettings>(Configuration.GetSection("EmailConfigurationSettings"));
services.AddOptions();

appsettings.json

"EmailConfigurationSettings": {
  "Provider": "gmail",
  "Username": "user@gmail.com",
  "Password": "mypassword" 
} 

I need the settings in the Services project. But for now I am just trying to ensure I can actually retrieve them. The code below follows all the code samples I found but generates:

public class LoadEmailSettingsFromAppSettings
{
    private readonly IOptions<EmailConfigurationSettings> _emailSettings;

    public LoadEmailSettingsFromAppSettings(IOptions<EmailConfigurationSettings> emailSettings)
    {
        _emailSettings = emailSettings;
        Message = "Our provider is " + _emailSettings.Value.Provider;
    }

    public string Message { get; set; }
}

_emailSettings is always null

So I tried testing it in the TestProject:

IOptions<EmailConfigurationSettings> someOptions = Options.Create<EmailConfigurationSettings>(new EmailConfigurationSettings());

Well, that's null too.

In the other solution, the one with the WebApp and one class library, using a slightly different pattern I found on one of the blogs I can actually retrieve the values from appsettings.json:

public class AuthMessageSender : IEmailSender, ISmsSender
{
    public AuthMessageSender(IOptions<EmailConfig> emailSettings)
    {
        _emailSettings = emailSettings.Value;
    }

    public EmailConfig _emailSettings { get; }

    public Task SendEmailAsync(string email, string subject, string message)
    {
        Execute(email, subject, message).Wait();
        return Task.FromResult(0);
    }

Class populated from appsettings.json

Please note the IOptions class was different with 9 properties but constructed the same way as the pattern above.

But using this pattern does not work in the multiple class library project. How can I understand how to get this to work in a multiple class library scenario?

Why they abandoned the ConfigurationManager I don't know, it was far easier.

halfer
  • 19,824
  • 17
  • 99
  • 186
dinotom
  • 4,990
  • 16
  • 71
  • 139

2 Answers2

1

In microservices you can simple do a bind to a new object that matches the json definition. So you would do.

var emailConfig = new EmailConfigurationSettings();
Configuration.GetSection("EmailConfigurationSettings").Bind(emailConfig);
services.AddSingleton(emailConfig);

Once you do this, all you have to do is request a copy of EmailConfigurationSettings in your service layers constructor. This will give you the dependency injected singleton of that object.

I would set a breakpoint on the "bind" and make sure that email config is populated.

willthiswork89
  • 617
  • 1
  • 4
  • 17
  • 1
    Running the project a putting a breakpoint on the AddSingleton call (In StartUp.cs) yields a null emailConfig. so this doesn't work, same as the OP methods. – dinotom Oct 10 '17 at 00:55
  • 1
    If that yields a null result then he has not loaded his app config properly. This code is taken from my personal mvc app so I know it works. If you set a variable to the return of getsection I'll bed it's returning null – willthiswork89 Oct 10 '17 at 13:13
0

Here is an interesting answer about class library : Class library.

In this part of your code:

private readonly IOptions<EmailConfigurationSettings> _emailSettings;

public LoadEmailSettingsFromAppSettings(IOptions<EmailConfigurationSettings> emailSettings)
{
    _emailSettings = emailSettings;         

the dependency injection don't work because you are in a class library so you should keep it that way.

Somewhere in your webapp you construct LoadEmailSettingsFromAppSettings

public class SomeClass
{
    public SomeClass(IOptions<EmailConfigurationSettings> emailSettings) // dependency injection works in your webapp
    {
        var loadEmail = new LoadEmailSettingsFromAppSettings(emailSettings); // send EmailSettings to your other class in your class library

        //(...)
    }
}

And the private readonly should be:

public IOptions<EmailConfigurationSettings> EmailSettings {get; private set;}

readonly vs get/set properties

I hope is clear and helpful

Sinan
  • 898
  • 1
  • 9
  • 23