在同一解决方案中的控制台应用项目中引用 Web API appsettings.json 文件 - dotnet run 问题

问题描述

我在一个 Visual Studio 解决方案中有一个 .net 5 ASP.NET Core Web API 和一个控制台应用程序。我的 API 的宿主项目中有一个 appsettings.json 文件,我想在我的控制台应用程序中引用该文件。该文件具有 copy if newercopy to Output Directory。 方案结构如下(无关项目略):

  • 解决方
    • ApiHostProject
      • appsettings.json
    • ConsoleAppProject

这是我的控制台应用程序的 Program.cs

public class Program
    {
        public static Task Main(string[] args) => CreateHostBuilder(args).Build().RunAsync();

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureServices((_,services) => services.AddStockUpdater());
    }

扩展方法 AddStockUpdater,我在其中添加控制台应用程序的依赖项:

internal static IServiceCollection AddStockUpdater(this IServiceCollection services)
        {
            var netFolder = Directory.GetCurrentDirectory();
            var debugFolder = Directory.GetParent(netFolder).FullName;
            var binFolder = Directory.GetParent(debugFolder).FullName;
            var consoleAppFolder = Directory.GetParent(binFolder).FullName;
            var solutionFolder = Directory.GetParent(consoleAppFolder).FullName;
            var pathToFile = Path.Combine(solutionFolder,"StockTradingSimulator.ApiHost","appsettings.json"); 

            var configuration = new ConfigurationBuilder()
                    .AddJsonFile(pathToFile,false)
                    .Build();

            //URL of the Web API
            services.AddHttpClient("Trading",client => client.BaseAddress = new Uri("http://localhost:4000"));

            return services
                .AddSingleton(configuration)
                .Configure<AppSettings>(configuration.GetSection("AppSettings"))
            // other dependencies omitted
}

如果我将 API 主机和控制台应用程序设置为启动项目并通过 Visual Studio(通过“开始”按钮或 Ctrl + 5)运行它们,这将起作用。 pathToFile"C:\\Users\\UserName\\Desktop\\SolutionFolder\\StockTradingSimulator.ApiHost\\appsettings.json"
但是,如果我使用 dotnet run 运行控制台应用程序项目(从包含控制台应用程序项目文件的目录,或从另一个目录将项目文件的路径作为 --project 参数传递给 dotnet run ),我收到一个错误

System.IO.FileNotFoundException: The configuration file 'StockTradingSimulator.ApiHost\appsettings.json' was not found and is not optional. The physical path is 'C:\Users\StockTradingSimulator.ApiHost\appsettings.json'.

无论控制台应用程序是通过 Visual Studio 还是通过 appsettings.json 命令运行,您能帮我让控制台应用程序找到 API 主机的 dotnet run 吗?

我尝试了 thisthis SO 帖子,但没有帮助。

解决方法

我已将以下内容添加到控制台应用项目文件中:

<!-- Try and nest the appsettings when it's not a web sdk project. -->
  <ItemGroup Condition="'$(IsSdkProject)' == 'true' AND '$(IsWebSdkProject)' == 'false'">
    <Content Include="..\StockTradingSimulator.ApiHost\appsettings.*.json">
      <DependentUpon>appsettings.json</DependentUpon>
    </Content>
    <Content Include="appsettings*.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </Content>
  </ItemGroup>

使用 dotnet run 运行控制台应用程序时,现在可以找到 Web API appsettings.json 文件。

我想从我的控制台应用发送电子邮件,电子邮件发件人位于 Web API 项目中并且依赖于 dbContext

派生自 DbContext 的 Web API 类使用以下内容获取连接字符串:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(_configuration.GetConnectionString("StockTrading"));

appsettings.json 包含到我的 SQL Server 数据库的连接字符串。

dotnet run 用于控制台应用程序引发错误 System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')

更新:

下面是我如何访问数据库连接字符串。

我在派生的 DbContext 类中有这个构造函数:

public TradingDbContext(DbContextOptions options) : base(options) { }

我想在派生的 OnConfiguring() 中的 DbContext 方法中获取连接字符串,并在此处仅使用 AddDbContext<TradingDbContext>() 但这在使用 dotnet run 运行时不起作用:

internal static IServiceCollection AddStockUpdater(this IServiceCollection services)
        {
            var configuration = new ConfigurationBuilder()
                    .AddJsonFile("appsettings.json",false)
                    .Build();

            services.AddHttpClient("trading",client => client.BaseAddress = new Uri("http://localhost:4000"));

            services
                .AddSingleton(configuration)
                .Configure<AppSettings>(configuration.GetSection("AppSettings"))
                .AddScoped<IEmailSender,EmailSender>()
                .AddScoped<IEmailService,EmailService>()
                .AddDbContext<TradingDbContext>(options => options
                    .UseSqlServer(configuration.GetConnectionString("StockTrading")))
                .AddAutoMapper(typeof(BusinessLayerServiceCollectionExtensions).Assembly)
                // other dependencies

            return services;
        }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...