5

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;
            }
                
    }
5
  • Please show the code where you add/build the Configuration. Commented Sep 23, 2020 at 14:19
  • Take a look at this, and there are plenty of other examples online. garywoodfine.com/configuration-api-net-core-console-application Commented Sep 23, 2020 at 14:20
  • Thanks, I'll take a look at that article and see if I can get it incorporated into my code. Commented Sep 23, 2020 at 14:42
  • @RomanDoskoch the Configuration comes from the "using System.Configuration" which is from the NuGet package "System.Configuration.ConfigurationManager". Commented Sep 23, 2020 at 14:43
  • 2
    Why are you using System.Configuration.ConfigurationManager? That's for working with app.config and web.config, not appsettings.json. Commented Sep 23, 2020 at 14:59

4 Answers 4

4

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;"
  },
  .....
}
Sign up to request clarification or add additional context in comments.

11 Comments

This got me closer. I can now get the connectionstring from appsettings before adding the DbContext but I'm getting a different error with my file manager. Not sure what I messed up and I backed out the code that I added to get the connectionstring and still get the FileManager error so it's probably unrelated. I'll have to back out all of the FileManger stuff to see if I can get something to work. Frustrated with this again...Core has been a much harder language for me to grasp than any of the ASP concepts I've worked with in the past.
This certainly works for me. What is the error exactly?
The only difference I see from code that supposedly works is that in your constructor you are using the concrete class, and not the ILogger interface: public FileManager(Logger<FileManager> log, IConfiguration config). I know this doesn't seem like it should make a difference, though.
Got it working now even with the FileManager back in place. Not sure what was going on with FileManger but added it back as it was and it didn't error. However, I had to add back the hard coded connectionstring into the DbContext's OnConfiguring function. How do I get the connection string inside of the OnConfiguring function of DbContext?
I'm not sure I understand what you're asking. Are you saying you don't want to set the connection string in the configuration code, as in the example, but instead in the DbContext class? If so, do you have a particular reason why you feel you need to do it that way?
|
3

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

Comments

1

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"));

            }
        }

Comments

0

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.