【问题标题】:.Net Core 3 console not able to get connectionstring from appsettings.Net Core 3 控制台无法从 appsettings 获取连接字符串
【发布时间】:2021-01-09 18:29:45
【问题描述】:

我创建了一个 .Net Core 3.1 控制台应用程序,并尝试使用 EntityFramework 来处理我的 Oracle 数据库。我找到了几个关于这个主题的视频和文章,但它们都涉及 HTTP 应用程序,而不是控制台应用程序。

我使用 powershell 命令搭建了表格并创建了一个名为 ModelContextDbContext。在我的 Program.cs 中,我有一个 Host.CreateDefaultBuilder 并添加了 services.AddDbContext 并将连接字符串放在我的 appsettings.json 文件中。

我的问题是,当它尝试将上下文添加到主机中的服务时,我无法将连接字符串从 appsettings 中拉出。我在 Configuration.GetConnectionString 上收到设计时错误,说 “Configuration does not contain a definition for ‘GetConnectionString’”

我通过 NuGet 安装了System.Configuration.ConfigurationManager,并在我的 Program.cs 文件中添加了using System.Configuration。 如何从主机构建器中的 appsettings 获取连接字符串?

程序.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();

更新代码

这是我的 Program.cs 文件中的所有代码。不幸的是,不确定我做了什么导致此问题,但现在我的 FileManger 类出现错误。

Unable to resolve service for type 'Microsoft.Extensions.Logging.Logger`1[EmailUpdateExport.FileManager]' while attempting to activate 'EmailUpdateExport.FileManager'.

我什至取消了从刚刚添加的 appsettings 中获取 DbConnection 的代码,但仍然出现错误。

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

这是我的文件管理器,以防有人对此提出建议。

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

【问题讨论】:

  • 请显示您添加/构建Configuration的代码。
  • 看看这个,网上还有很多其他的例子。 garywoodfine.com/configuration-api-net-core-console-application
  • 谢谢,我会看看那篇文章,看看是否可以将它合并到我的代码中。
  • @RomanDoskoch 配置来自 NuGet 包“System.Configuration.ConfigurationManager”中的“使用 System.Configuration”。
  • 你为什么使用 System.Configuration.ConfigurationManager?这适用于 app.config 和 web.config,而不是 appsettings.json。

标签: c# asp.net-core .net-core dependency-injection


【解决方案1】:

这是您可以做到的一种方式。此示例根据键名访问配置值。将此配置映射到一个类是一个好主意,因此检索设置不太容易出错。您可以查看我在评论中发布的链接,了解有关如何执行此操作的详细信息。

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;"
  },
  .....
}

【讨论】:

  • 这让我更接近了。我现在可以在添加 DbContext 之前从 appsettings 获取连接字符串,但我的文件管理器出现了不同的错误。不知道我搞砸了什么,我取消了我为获取连接字符串而添加的代码,但仍然得到 FileManager 错误,因此它可能不相关。我将不得不退出所有 FileManger 的东西,看看我能不能得到一些工作。再次对此感到沮丧……对我来说,核心语言比我过去使用过的任何 ASP 概念都更难掌握。
  • 这当然对我有用。究竟是什么错误?
  • 我从应该有效的代码中看到的唯一区别是,在您的构造函数中,您使用的是具体类,而不是ILogger 接口:public FileManager(Logger&lt;FileManager&gt; log, IConfiguration config)。不过,我知道这似乎不应该有所作为。
  • 即使在 FileManager 恢复原位的情况下也能正常工作。不确定 FileManger 发生了什么,但按原样将其添加回来并且没有出错。但是,我不得不将硬编码的连接字符串添加回 DbContext 的 OnConfiguring 函数。如何在 DbContext 的 OnConfiguring 函数中获取连接字符串?
  • 我不确定我是否明白你在问什么。您是说您不想像示例中那样在配置代码中设置连接字符串,而是在 DbContext 类中设置?如果是这样,您有什么特别的理由觉得需要这样做吗?
【解决方案2】:

您需要构建正确的配置:

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

然后用它来获取连接字符串:

var connstring = configuration.GetConnectionString("DbConnection"); // use configuration object created by ConfigurationBuilder

【讨论】:

    【解决方案3】:

    在尝试激活“EmailUpdateExport.FileManager”时无法解析“Microsoft.Extensions.Logging.Logger`1[EmailUpdateExport.FileManager]”类型的服务。

    错误是因为你的依赖注入错误的服务,改变你的代码如下(将Logger更改为ILogger):

    public FileManager(ILogger<FileManager> log, IConfiguration config)
    {
        _log = log;
        _configuration = config;
    }
    

    【讨论】:

      【解决方案4】:

      发布我最终发现对我有用的内容。我实际上很喜欢这里,因为它位于 DbContext 中,.Net Framework 也是从中获取连接字符串的地方。这与我过去使用的位置相似。希望这对其他人也有帮助。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-16
        • 2021-11-06
        • 1970-01-01
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多