使用Azure SQL的ASP.Net Core 2.1 Serilog SQL Server Sink在本地工作,但不是从Azure应用服务工作

问题描述 投票:2回答:1

我有一个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 asp.net-core azure-sql-database asp.net-core-2.1 serilog
1个回答
2
投票

由于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();

        //...
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.