当EF迁移不通过Program.cs

时间:2017-07-16 07:30:38

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

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

我的项目是.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数据库更新时--startup-project = myAPIProject

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

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

1 个答案:

答案 0 :(得分: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();

这是因为我们的启动构造函数通过DI容器传递ILogger(即使在通过EF迁移运行时我们还没有配置记录器)。

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

现在......我遇到过.NET核心这么多令人沮丧的问题。我猜这可能是因为它还处于婴儿期,并且最佳实践等文档仍在改进中。因为我读过的大多数指南都没有这样做过。

我觉得这也部分是因为.NET核心转向“约定优于配置” - 这显然有缺点。使用像C#这样的强类型语言的好处是你可以让编译器在运行时之前帮助你识别这样的问题。

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

热衷于听取人们对此的看法。我相信其他人一定会遇到同样的挫折。不要误会我的意思我喜欢.NET核心,但是在这个应用程序的开发过程中已经有很多次我在这样的最简单的愚蠢问题上被困了几个小时(有时候更长),这可能只花了写代码。