控制台应用程序配置无法使用 `dotnet run` 加载

时间:2021-02-14 14:32:08

标签: c# .net-core

我目前正在 .net 核心中制作(至少尝试)一个简单的控制台应用程序。该应用程序是一个简单的控制台应用程序。没什么特别的,RabbitMQ的一个小实验。

.net 版本(今天早上刚更新到最新最好的):

dotnet --version
5.0.103

操作系统(不确定是否有用):

macOS Big Sur 11.2.1

当我从 IDE(在本例中为 Rider)运行应用程序时,没问题。在这种情况下,一切都符合预期。

由于我想从终端运行应用程序,因此发生了以下情况:应用程序无法启动,因为它无法创建到本地主机的连接。

我使用的命令

dotnet run --project src/RabbitMQ.Publisher/RabbitMQ.Publisher.csproj

...

Unhandled exception. RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable
 ---> System.AggregateException: One or more errors occurred. (Connection failed)
 ---> RabbitMQ.Client.Exceptions.ConnectFailureException: Connection failed
 ---> System.ArgumentNullException: Value cannot be null. (Parameter 'hostName')

...

阅读了一些关于 .NET Generic Hostdotnet run 的文档,我找不到任何关于为什么会失败的特殊原因。在过去,只有在我忘记将 appsettings.json 包含到项目中时才会发生这种情况(以我目前的经验)。我检查的第一件事。

<ItemGroup>
   <Content Include="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
   </Content>
</ItemGroup>

接下来我检查的是 Host.CreateDefaultBuilder 方法的实现,因为我认为发生了一些变化。一切似乎都很好并且向后兼容。

源代码:

public static void Main(string[] args)
{
    using IHost host = CreateBuilder(args).Build();
    using Publisher? publisher = host.Services.GetService<Publisher>();

    Debug.Assert(publisher != null, nameof(publisher) + " != null");
    
    publisher.BasicPublish(new BasicPayload
    {
        Message = "Test message"
    });
}

private static IHostBuilder CreateBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.Configure<RabbitMQ>(hostContext.Configuration.GetSection("RabbitMQ").Bind);
            services.AddTransient<IConnectionFactory>(provider =>
            {
                IOptions<RabbitMQ>? options = provider.GetService<IOptions<RabbitMQ>>();
                
                Debug.Assert(options != null, nameof(options) + " != null");
                
                return new ConnectionFactory
                {
                    HostName = options.Value.HostName
                };
            });
            services.AddTransient<Publisher>();
        });

选项类:

using System.ComponentModel.DataAnnotations;

public sealed class RabbitMQ
{
    [Required] public string HostName { get; set; } = default!;

    [Required] public string Queue { get; set; } = default!;
    
    [Required] public bool Durable { get; set; }
}

appsettings.json 的内容:

{
    "Logging": {
        "LogLevel": {
            "Default": "Debug",
            "System": "Information",
            "Microsoft": "Information"
        }
    },
    "RabbitMQ": {
        "HostName": "localhost",
        "Queue": "basic",
        "Durable": false
    }
}

其余文件的内容并不重要。

我还在 SO、不同的博客文章等上查看了一些其他类似的问题。我想我错过了一些东西,但出于对应用程序配置的热爱,我似乎无法找到它。还有什么我想到的,我可能会错过的吗?

由于这是一个实验性项目,我的 CDO 在弄清楚发生了什么之前不允许我继续:)

编辑:

最新实验:

.ConfigureAppConfiguration(builder =>
{
    string path = Assembly.GetExecutingAssembly().Location;
    string? directoryName = Path.GetDirectoryName(path);
    builder.AddJsonFile($"{directoryName}/appsettings.json", optional: false);
})

似乎“修复”了这个问题。所以,现在我正在研究实际复制到输出目录的内容。 CreateDefaultBuilder 是“搜索”appsettings.json 时的默认选项是optional。我假设这会失败(我可以重写应用程序并手动配置提供程序来证明这个假设,但不值得花时间),如果将其设置为 true

会及时通知您调查结果:)

编辑#2:

在检查 CreateDefaultBuilder 的代码后,一切开始变得有意义。结合 dotnet run --project ./projects/proj1/proj1.csproj(来自 dotnet run 文档页面的示例),它当然会失败。因为它将“搜索”文件的路径基于 Directory.GetCurrentDirectory()。我从存储库的根目录运行命令,那么自然不会包含 appsettings.json 文件。项目结构:

.
├── Example.RabbitMQ.sln
├── README.md
├── docker-compose.yaml
├── src
│   └── RabbitMQ.Publisher
│       ├── Application
│       ├── Models
│       ├── Options
│       ├── Program.cs
│       ├── Properties
│       ├── RabbitMQ.Publisher.csproj
│       ├── appsettings.json
│       ├── bin
│       └── obj
└── test

为了给后代说明这一点:)

当我以下列方式运行命令时:dotnet run --project src/RabbitMQ.Publisher/RabbitMQ.Publisher.csproj 那么它将“搜索”应用设置的路径基于该 src 目录。其中,根据项目结构,手头没有文件:)

感谢橡皮鸭们,这是一个有趣的实验。现在回到最初的实验开始。

0 个答案:

没有答案