Reputation: 3707
I’ve created a .Net Core 3.1 console app and I’m trying to use EntityFramework to work with my Oracle database. I’ve found several videos and articles on this subject but they all deal with HTTP apps and not a console app.
I used the powershell command to scaffold out the tables and create a DbContext
called ModelContext
. In my Program.cs I have a Host.CreateDefaultBuilder
and added the services.AddDbContext
as well as put the connectionstring in my appsettings.json file.
My issue is that I can’t get it to pull the connectionstring out of the appsettings at the point it’s trying to add the context to the services in the host. I get a design time error on the Configuration.GetConnectionString saying “Configuration does not contain a definition for ‘GetConnectionString’”
.
I installed System.Configuration.ConfigurationManager
through NuGet and add the using System.Configuration
in my Program.cs file.
How can I get the connectionstring from appsettings in my host builder?
Program.cs
var host = Host.CreateDefaultBuilder().ConfigureServices((context, services) =>
{
services.AddTransient<IAppHost, AppHost>();
services.AddTransient<IFileManager, FileManager>();
services.AddTransient<IDataManager, DataManager>();
var connstring = Configuration.GetConnectionString("DbConnection");
services.AddDbContext<ModelContext>(options =>
{
options.UseOracle(connstring);
});
services.AddLogging(builder =>
{
builder.AddNLog("nlog.config");
});
}).Build();
UPDATED CODE
Here is all the code from my Program.cs file. Unfortunately, not sure what I've done to cause this but now I'm getting an error with my FileManger Class.
Unable to resolve service for type 'Microsoft.Extensions.Logging.Logger`1[EmailUpdateExport.FileManager]' while attempting to activate 'EmailUpdateExport.FileManager'.
I've even backed out the code for getting the DbConnection from the appsettings that I just added but still getting the error.
class Program
{
static void Main(string[] args)
{
//Calls the Builder so that you can get to the appsettings.
var builder = new ConfigurationBuilder();
BuildConfig(builder);
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
logger.Debug("Initializing Program.Main");
var host = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Path.Combine(AppContext.BaseDirectory));
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
})
.ConfigureServices((context, services) =>
{
services.AddTransient<IAppHost, AppHost>();
services.AddTransient<IFileManager, FileManager>();
services.AddTransient<IDataManager, DataManager>();
var connstring = context.Configuration["ConnectionStrings:DbConnection"];
services.AddDbContext<ModelContext>(options =>
{
options.UseOracle(connstring);
});
services.AddLogging(builder =>
{
builder.AddNLog("nlog.config");
});
}).Build();
//Create instance of AppHost and call the Run() function to run the business logic.
var svc = ActivatorUtilities.CreateInstance<AppHost>(host.Services);
svc.Run();
}
catch (Exception ex)
{
//NLog: catch setup errors
logger.Error("Stopped program setup with Error. {0} | {1} | {2}", ex.Message, ex.StackTrace, ex.InnerException);
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit
NLog.LogManager.Shutdown();
}
}
static void BuildConfig(IConfigurationBuilder builder)
{
//Sets up the ability to talk to the appsettings.json
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables();
}
}
Here is my FileManger in case someone has a suggestion with that.
public class FileManager : IFileManager
{
private readonly ILogger<FileManager> _log;
private readonly IConfiguration _configuration;
public FileManager(Logger<FileManager> log, IConfiguration config)
{
_log = log;
_configuration = config;
}
public void CreateFileDirectory(string FilePath)
{
try
{
//create the target location if it doesn't exist
if (!Directory.Exists(FilePath))
{
_log.LogInformation("Create directory: " + FilePath);
Directory.CreateDirectory(FilePath);
}
}
catch (Exception ex)
{
_log.LogError("Error creating Export directory. {0} | {1} | {2} ", ex.Message, ex.StackTrace, ex.InnerException);
}
}
public void CopyFile(string sourceLocation, string destinationLocation, string fileName)
{
_log.LogInformation("Source location: {0} | Destination location: {1} | File Name: {2}", sourceLocation, destinationLocation, fileName);
var sourceFile = Path.Combine(sourceLocation, fileName);
var destinationFile = Path.Combine(destinationLocation, fileName);
_log.LogInformation("SourceFilePath: {0}", sourceFile);
_log.LogInformation("DestinationFilePath: {0}", destinationFile);
try
{
//check to make sure source exists first
if (File.Exists(sourceFile))
{
//get rid of the file if it already exists. Shouldn't be an issue most to the time.
if (File.Exists(destinationFile))
{
File.Delete(destinationFile);
}
File.Copy(sourceFile, destinationFile);
}
else
_log.LogInformation("Source file does not exist. File: {0}", sourceFile);
}
catch (Exception ex)
{
_log.LogError("Error copying file. Source: {0} | Destination: {1}. {2} | {3} | {4}", sourceFile, destinationFile, ex.Message, ex.StackTrace, ex.InnerException);
throw;
}
}
Upvotes: 4
Views: 3817
Reputation: 3707
Posting what I ultimately found that worked for me. I actually like it here since it's in the DbContext which is where .Net Framework gets it's connection string from as well. It's a similar location to what I've used in the past. Hopefully this helps someone else as well.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
.AddJsonFile("appsettings.json", optional: false)
.Build();
optionsBuilder.UseOracle(configuration.GetConnectionString("DbConnection"));
}
}
Upvotes: 1
Reputation: 36675
Unable to resolve service for type 'Microsoft.Extensions.Logging.Logger`1[EmailUpdateExport.FileManager]' while attempting to activate 'EmailUpdateExport.FileManager'.
The error is because you dependency injection wrong service,change your code like below(change Logger
to ILogger
):
public FileManager(ILogger<FileManager> log, IConfiguration config)
{
_log = log;
_configuration = config;
}
Upvotes: 0
Reputation: 12201
You need to build correct configuration:
var configuration = new ConfigurationBuilder()
.SetBasePath(Path.Combine(AppContext.BaseDirectory))
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) // add more configuration files if there is a need
.Build();
and then use it to get connection string:
var connstring = configuration.GetConnectionString("DbConnection"); // use configuration object created by ConfigurationBuilder
Upvotes: 3
Reputation: 819
This is one way you can do it. This example accesses the configuration values based on the key names. It's a good idea to map this configuration to a class, so retrieving settings is less prone to errors. You can check the link I posted in my comment for details about how to do that.
var host = Host.CreateDefaultBuilder()
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Path.Combine(AppContext.BaseDirectory));
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
})
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<ModelContext>(options =>
{
options.UseSqlServer(hostContext.Configuration["ConnectionStrings:DefaultConnection"]);
}, ServiceLifetime.Transient)
// add other services
})
.UseConsoleLifetime()
.Build();
appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=myDB;Trusted_Connection=True;"
},
.....
}
Upvotes: 4