我有一个ASP.Net Core 2.1网站,它使用Azure SQL数据库作为Microsoft Identity组件。
我在该数据库中添加了一个Logs表,并使用SQL Server Sink将Serilog添加到我的网站。
当我在本地运行网站时,仍然连接到Azure SQL数据库,我可以在Logs
表中看到我的日志条目就好了。但是,当我将网站部署到我的Azure App Service时,我不再在数据库的Logs
表中获取任何日志条目。
请注意,在已部署的版本中,我正在连接并使用Azure SQL数据库来获取我的MS Identity,我可以创建新用户并编辑现有用户。所以我知道我的App Service应用程序设置中的连接字符串是正确的。
我已经审查了Serilog MSSQL Github,将他们的配置建议与我自己的配置建议进行比较,但找不到任何突出的东西。
我已将此设置在我部署到另一个Azure App Service的ASP.Net Core API上正常运行。该服务使用不同的数据库,但它位于同一SQL Server资源上。
我已经回顾了当我开始这个问题而没有运气时推荐的SO帖子列表。
我在第一次设置用户帐户时在数据库上运行了以下SQL;
EXEC sp_addrolemember N'db_datareader', N'myuser'
EXEC sp_addrolemember N'db_datawriter', N'myuser'
EXEC sp_addrolemember N'db_ddladmin', N'myuser'
而且,正如我所说,用户帐户可以更新并在AspNetUsers表中添加用户数据。因此,它似乎不是用户帐户问题。
我已经验证我的Azure应用服务DEV部署插槽(我正在测试的那个),应用程序设置,连接字符串中的连接字符串与我在本地DEV UserSecrets中的连接字符串完全相同。此外,再次,我可以在部署到Azure时读取/写入同一数据库中的AspNet *表。
这是我的Program.cs类,我设置了Serilog;
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddUserSecrets<Startup>()
.AddEnvironmentVariables()
.Build();
public static void Main(string[] args)
{
var connectionString = Configuration.GetConnectionString("MyConnectionString");
const string tableName = "Logs";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithThreadId()
.WriteTo.MSSqlServer(connectionString, tableName)
.CreateLogger();
// TODO Enable to debug any startup Serilog issues. Make sure to comment out for PROD
//Serilog.Debugging.SelfLog.Enable(msg =>
//{
// Debug.Print(msg);
// Debugger.Break();
//});
try
{
Log.Information("Starting Application");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog();
}
}
我在Azure中部署的用于将日志写入Azure SQL的API与此网站之间的唯一区别是API,这是旧的,我有
public static IWebHost BuildWebHost(string[] args)
在program.cs中,而较新的网站有
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
所以...任何想法都将非常感激。
[更新1/23/19]
我直接将连接字符串添加到了
var connectionString
在Program.cs中而不是从中获取它
Configuration.GetConnectionString("MyConnectionString")
它开始登录数据库。
因此,问题似乎是Program.cs能够从Azure App Service部署槽,应用程序设置,连接字符串部分读取连接字符串。
从Startup.cs正确读取此连接字符串,并且自从我第一次创建网站以来一直有效。
那么,Azure是否存在一些已知问题无法从Program.cs中读取部署槽应用程序设置/连接字符串中的值?
由于Azure似乎存在问题,因此在调用CreateWebHostBuilder之前它不会向Web应用程序提供应用程序设置,这是一种简单的解决方法(假设硬编码源代码中的连接字符串不是一个可行的选项)是配置Serilog在Startup.cs而不是Program.cs中使用SqlServer。 如果记录应用程序启动期间发生的初始事件很重要,可以在Program.cs中临时配置Serilog以写入文件。
Program.cs中:
public class Program
{
public static void Main(string[] args)
{
var AzureLogFilePath = @"D:\home\LogFiles\Application\log.txt";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.File(path: AzureLogFilePath, fileSizeLimitBytes: 1_000_000, rollOnFileSizeLimit: true, shared: true);
.CreateLogger();
try
{
Log.Information("Starting Application");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog();
}
Startup.cs:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName ?? "Production"}.json", optional: true)
.AddEnvironmentVariables();
if (env.IsDevelopment()) builder.AddUserSecrets<Startup>(); // according to the docs, AddUserSecrets should be used only in development
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("MyConnectionString");
const string tableName = "Logs";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithThreadId()
.WriteTo.MSSqlServer(connectionString, tableName)
.CreateLogger();
//...
}
}