【问题标题】:Configuring dependencies (e.g. logging) in Program.cs when EF Migrations don't go through Program.cs当 EF 迁移不通过 Program.cs 时,在 Program.cs 中配置依赖项(例如日志记录)
【发布时间】:2017-07-16 07:30:37
【问题描述】:

我会尽量解释我的情况,我希望这是有道理的。

我的项目是一个 .NET 核心 Web API。使用一个单独的类库项目,其中包含模型,包括我的 DbContext 东西。

问题 #1 我希望能够从 Startup.cs 中登录到控制台

原因:我目前正在调试从环境变量设置变量。我想将设置的内容输出到控制台。

示例:How do I write logs from within Startup.cs

现在,解决方案是将 ILoggerFactory 添加到 Program.cs 中的 Service 容器中:

var host = new WebHostBuilder()
        .UseKestrel()
        .ConfigureServices(s => {
            s.AddSingleton<IFormatter, LowercaseFormatter>();
        })
        .ConfigureLogging(f => f.AddConsole(LogLevel.Debug))
        .UseStartup<Startup>()
        .Build();

        host.Run();

接下来,更改 Startup.cs 构造函数以接收 ILoggerFactory,这将从我们刚刚注册的容器中获取。如下:

public class Startup {

  ILogger _logger;
  IFormatter _formatter;

  public Startup(ILoggerFactory loggerFactory, IFormatter formatter){
    _logger = loggerFactory.CreateLogger<Startup>();
    _formatter = formatter;
  }

  public void ConfigureServices(IServiceCollection services)  {
    _logger.LogDebug($"Total Services Initially: {services.Count}");

    // register services
    //services.AddSingleton<IFoo, Foo>();
  }

  public void Configure(IApplicationBuilder app, IFormatter formatter) {
    // note: can request IFormatter here as well as via constructor
    _logger.LogDebug("Configure() started...");
    app.Run(async (context) => await context.Response.WriteAsync(_formatter.Format("Hi!")));
    _logger.LogDebug("Configure() complete.");
  }

这解决了我的问题 - 我可以运行应用程序,它现在可以正常工作,记录我需要的地方。

但是。

当我尝试运行 dotnet ef database update --startup-project=myAPIProject

它现在失败了,因为 EF 不通过 Program.cs,而是尝试直接实例化我的 Startup 类。而且因为现在我的构造函数需要 ILoggerFactory,所以 EF 不知道该做什么并引发异常。

有人知道解决这个问题的方法吗?

【问题讨论】:

    标签: entity-framework asp.net-core entity-framework-core


    【解决方案1】:

    好的,所以我找到了解决方案。

    而不是将 ILoggerFactory 传递给 Startup.cs 构造函数。传递ILogger如下:

    private ILogger<Startup> _logger;
        public Startup(IHostingEnvironment env, ILogger<Startup> logger) {
            _env = env;
            _logger = logger;
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
    
                _configuration = builder.Build();
        }
    

    我的 Program.cs 看起来像:

        var host = new WebHostBuilder() 
                .UseKestrel()
                .UseConfiguration(config)
                .ConfigureServices(s => s.AddSingleton<IConfigurationRoot>(config))
                .ConfigureLogging(f => {
                    f.AddConsole()
                    .AddDebug();
                })
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .Build();
    
            host.Run();
    

    这是因为我们的 Startup 构造函数通过 DI 容器传递给 ILogger(即使通过 EF 迁移运行并且我们没有配置记录器)。

    我在阅读后发现了这一点:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup(在“启动时可用的服务”下)。

    现在...我在 .NET 核心中遇到了很多类似这样令人沮丧的问题。我猜这可能是因为它仍处于起步阶段,最佳实践等文档仍在改进。因为我读过的大多数指南都没有这样做。

    我觉得这也部分是因为 .NET 核心中向“约定优于配置”的转变——这显然有缺点。使用 C# 等强类型语言的美妙之处在于,您可以让编译器在运行时帮助您识别此类问题。

    (请记住,使用 ILoggerFactory 一切正常,直到您使用无法访问 Program.cs 中添加的服务的 EF 运行迁移)

    渴望听到人们对此的想法。我敢肯定,其他人一定也有同样的挫败感。不要误会我的意思,我喜欢 .NET 核心,但是在这个应用程序的开发过程中,有很多次我被困在像这样最简单的愚蠢问题上几个小时(有时更长),这些问题本来可以花在写代码。

    【讨论】:

    • 是的,您将看到 ASP.NET Core 2.0 向此模型移动,因此在启动时可以使用日志记录。另外,请参见此处:ardalis.com/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-16
    • 2022-11-08
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 2022-06-14
    相关资源
    最近更新 更多