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

问题描述

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

这是我的控制台应用程序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'.

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

我试过这个这个SO 帖子,但他们没有帮助。

标签: c#asp.net-web-apiconsole-applicationprojects-and-solutionsappsettings

解决方案


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

<!-- 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 runWeb API文件。appsettings.json

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

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

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

推荐阅读