Entity framework 当EF迁移不'时,在Program.cs中配置依赖项(例如日志记录);不要通过Program.cs

Entity framework 当EF迁移不'时,在Program.cs中配置依赖项(例如日志记录);不要通过Program.cs,entity-framework,asp.net-core,entity-framework-core,Entity Framework,Asp.net Core,Entity Framework Core,我会尽可能地解释我的情况,我希望这是有意义的 我的项目是一个.NET核心Web API。使用一个单独的类库项目,该项目包含包括我的DbContext内容在内的模型 问题1 我希望能够从Startup.cs中登录到控制台 原因:我目前正在调试环境变量中的变量设置。我想输出已设置为console的内容 例如: 现在,解决方案是将iLogger工厂添加到Program.cs中的服务容器中,如下所示: var host = new WebHostBuilder() .UseKestrel

我会尽可能地解释我的情况,我希望这是有意义的

我的项目是一个.NET核心Web API。使用一个单独的类库项目,该项目包含包括我的DbContext内容在内的模型

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

原因:我目前正在调试环境变量中的变量设置。我想输出已设置为console的内容

例如:

现在,解决方案是将iLogger工厂添加到Program.cs中的服务容器中,如下所示:

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

        host.Run();
var host=new WebHostBuilder()
.UseKestrel()
.ConfigureServices(s=>{
s、 AddSingleton();
})
.ConfigureLogging(f=>f.AddConsole(LogLevel.Debug))
.UseStartup()
.Build();
host.Run();
接下来,将Startup.cs构造函数更改为接收iLogger工厂,该工厂将从我们刚刚注册的容器中获取。详情如下:

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.");
  }
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();
    }
公共类启动{
ILogger\u记录器;
IFormatter格式化程序;
公共启动(iLogger工厂、IFormatter格式化程序){
_logger=loggerFactory.CreateLogger();
_格式化程序=格式化程序;
}
public void配置服务(IServiceCollection服务){
_logger.LogDebug($“最初的总服务:{Services.Count}”);
//注册服务
//services.AddSingleton();
}
公共void配置(IApplicationBuilder应用程序、IFormatter格式化程序){
//注意:您可以在此处以及通过构造函数请求IFormatter
_LogDebug(“Configure()已启动…”);
运行(异步(上下文)=>wait-context.Response.WriteAsync(_-formatter.Format(“Hi!”));
_LogDebug(“Configure()complete”);
}
这解决了我的问题-我可以运行应用程序,它现在可以正常工作,记录在我需要的地方

不过

当我尝试运行dotnet ef数据库更新时--startup project=myAPIProject

它现在失败了,因为EF没有通过Program.cs,而是尝试直接实例化我的启动类。而且因为现在我的构造函数需要一个iLogger工厂,EF不知道该做什么并抛出异常


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

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

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

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.");
  }
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();
    }
private ILogger\u记录器;
公共启动(IHostingEnvironment环境、ILogger记录器){
_env=env;
_记录器=记录器;
var builder=new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(“appsettings.json”,可选:false,reloadOnChange:true)
.AddJsonFile($“appsettings.{env.EnvironmentName}.json”,可选:true)
.AddenEnvironmentVariables();
_configuration=builder.Build();
}
My 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();
var host=new WebHostBuilder()
.UseKestrel()
.UseConfiguration(配置)
.ConfigureServices(s=>s.AddSingleton(配置))
.ConfigureLogging(f=>{
f、 AddConsole()
.AddDebug();
})
.UseContentRoot(目录.GetCurrentDirectory())
.Useii整合()
.UseStartup()
.Build();
host.Run();
这是因为我们的启动构造函数通过DI容器传递ILogger(即使在通过EF迁移运行时,我们还没有配置记录器)

我在阅读了以下内容后发现了这一点:(在“启动时可用的服务”下)

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

我觉得部分原因还在于.NETCore向“约定优先于配置”的转变——这显然是有缺点的。使用像C#这样的强类型语言的好处在于,您可以让编译器在运行前帮助您识别类似的问题

(请记住,在使用EF运行迁移之前,iLogger Factory的一切都很正常,而EF无法访问Program.cs中添加的服务)


渴望听到人们对此的想法。我相信其他人一定也经历过同样的挫折。别误会,我喜欢.NET core,但在这个应用程序的开发过程中,我已经被困了好几小时(有时更长)关于像这样最简单的愚蠢问题,可能只需要编写代码就可以了。

是的,您将看到ASP.NET Core 2.0朝着这个模式发展,这样在启动时就可以使用日志记录了。另外,请参见此处: