I'm building a Folder Monitor Service to show files in multiple folders that have been sitting in the folder for over an hour. I'm having an issue injecting the appsettings.json
values in to multiple classes.
appsettings.json file
{
"FolderLocations": {
"InsertLocation": "C:\\Insert\\",
"ReplaceLocation": "C:\\Replace\\",
"DeleteLocation": "C:\\Delete\\"
},
"EmailSettings": {
"SmtpServer": "host",
"SmtpPort": 25
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
AppSettingsConfiguration,cs
public class AppSettingsConfiguration
{
public string InsertLocation { get; set; }
public string ReplaceLocation { get; set; }
public string DeleteLocation { get; set; }
public string SmtpServer { get; set; }
public int SmtpPort { get; set; }
}
Program.cs
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "Folder Monitor";
})
.ConfigureServices((hostContext, services) => {
services.Configure<AppSettingsConfiguration>(hostContext.Configuration.GetSection("FolderLocations"));
services.AddSingleton<IFolderMonitorManager, FolderMonitorManager>();
services.Configure<AppSettingsConfiguration>(hostContext.Configuration.GetSection("EmailSettings"));
services.AddLogging();
services.AddSingleton<IEmail, Email>();
services.AddHostedService<WindowsBackgroundService>();
})
.Build();
await host.RunAsync();
WindowsBackgroundService.cs
public class WindowsBackgroundService : BackgroundService
{
private readonly IFolderMonitorManager _folderMonitorManager;
private readonly ILogger<WindowsBackgroundService> _logger;
public WindowsBackgroundService(
IFolderMonitorManager folderMonitorManager,
ILogger<WindowsBackgroundService> logger) =>
(_folderMonitorManager, _logger) = (folderMonitorManager, logger);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogWarning($"===== Starting Folder Monitor @ {DateTime.Now:MM/dd/yy HH:mm:ss} =====");
await _folderMonitorManager.StartMonitoringProcess();
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
FolderMonitorManager.cs
internal class FolderMonitorManager : IFolderMonitorManager
{
private readonly AppSettingsConfiguration _config;
private readonly ILogger<FolderMonitorManager> _logger;
private List<string> _folders;
private List<string> _files;
private List<string> _filesFoundOverHour;
private readonly IEmail _email;
public FolderMonitorManager(IOptions<AppSettingsConfiguration> config, ILogger<FolderMonitorManager> logger)
{
_config = config.Value;
_logger = logger;
_filesFoundOverHour = new List<string>();
}
public async Task StartMonitoringProcess()
{
try
{
await CheckFoldersFromAppSettings();
}
catch (Exception)
{
throw;
}
}
private async Task CheckFoldersFromAppSettings()
{
//File Locations from appsettings.json
_folders = new(){
_config.InsertLocation,
_config.DeleteLocation,
_config.ReplaceLocation
};
try
{
foreach (var folder in _folders)
{
_files = FolderLocations.GetFilesInLocation(folder);
foreach (var file in FolderLocations.GetFileLastWriteTime(_files))
{
_filesFoundOverHour.Add(file);
}
}
}
catch (Exception)
{
throw;
}
_logger.LogWarning($"===== Finished Folder Monitor @ {DateTime.Now:MM/dd/yy HH:mm:ss} =====");
Console.WriteLine(_filesFoundOverHour.Count);
SendEmail();
}
public void SendEmail()
{
Console.WriteLine("Email Send hit");
_email.Send(); //Getting Null Exception here
}
}
Email.cs
public class Email : IEmail
{
private readonly AppSettingsConfiguration _config;
private readonly ILogger<Email> _logger;
private string FromEmailAddress = "[email protected]";
public Email()
{
}
public Email(IOptions<AppSettingsConfiguration> config, ILogger<Email> logger)
{
_config = config.Value;
_logger = logger;
}
public async Task Send()
{
// create email message
var email = new MimeMessage();
email.From.Add(MailboxAddress.Parse(FromEmailAddress));
email.To.Add(MailboxAddress.Parse("[email protected]"));
email.Subject = "Test Email Subject";
email.Body = new TextPart(TextFormat.Html) { Text = "<h1>Example HTML Message Body</h1>" };
using (var client = new SmtpClient())
{
//Here's where I need to be able to read the appsettings.json
client.Connect(_config.SmtpServer, _config.SmtpPort, false);
// Note: only needed if the SMTP server requires authentication
//client.Authenticate("joey", "password");
client.Send(email);
client.Disconnect(true);
}
}
}
In the using
statement of Email.Send()
is where I need to be able to read the SmtpServer
and SmtpPort
values.
In the FolderMonitorManager.cs
file, I'm getting a Null Exception
with _email.Send()
. I understand why. Is there a way to be able to read the AppSettingsConfiguration.cs
values across all classes?
CodePudding user response:
Since the JSON does not map to the object model then they need to be bound manually when configuring options
IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "Folder Monitor";
})
.ConfigureServices((hostContext, services) => {
//Configure settings
services.Configure<AppSettingsConfiguration>(options => {
hostContext.Configuration.GetSection("FolderLocations").Bind(options);
hostContext.Configuration.GetSection("EmailSettings").Bind(options);
});
services.AddSingleton<IFolderMonitorManager, FolderMonitorManager>();
services.AddLogging();
services.AddSingleton<IEmail, Email>();
services.AddHostedService<WindowsBackgroundService>();
})
.Build();
Reference: Bind hierarchical configuration
FolderMonitorManager
also does not assign a value to _email
as it is not being injected into the constructor
public FolderMonitorManager(IOptions<AppSettingsConfiguration> config, ILogger<FolderMonitorManager> logger, IEmail email)
{
_config = config.Value;
_logger = logger;
_filesFoundOverHour = new List<string>();
_email = email; //<--
}