从 .NET 6 Minimal API 调用的类库方法进行 Serilog 日志记录
我设置了一个 .Net 6 Core Minimal API,以使用 SeriLog 登录到 MS SQL Server。在我的类库中,仅当我修改类库中的构造函数时,我才能够使用 SeriLog 进行日志记录。我试图避免修改类库类或方法的构造函数。
根据我使用控制台应用程序的经验,如果我在主 Program.cs 中设置 SeriLog,那么我可以在类库中的任何类中使用日志记录,而无需将记录器传递给构造函数。因此,我可以在类库中的任何位置使用 Log.Information("my message") 并且它可以工作。我试图在 .Net 6 最小 API 项目中使用我的 Program.cs 实现相同的目标。
我觉得通过查看有关该主题的其他问题应该可以做到。特别是这个,其中答案指出:
您无需在类库中执行任何操作。只有主应用程序具有组合根(应用程序生命周期中可以设置对象图的最早点)。
因此,根据上面的内容,在我的 API Program.CS 中,我有以下代码(我已在注释中指出了哪些有效,哪些无效):
//Configure SeriLog
builder.Logging.ClearProviders();
var appSettings = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var logDB =
builder.Configuration.GetSection("ConnectionStrings:Default").Value;
var sinkOpts = new MSSqlServerSinkOptions { TableName = "Logs" };
var columnOptions = new ColumnOptions();
var logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft",
Serilog.Events.LogEventLevel.Information)
.WriteTo.MSSqlServer(
connectionString: logDB,
sinkOptions: sinkOpts,
columnOptions: columnOptions,
appConfiguration: appSettings
).CreateLogger();
builder.Logging.AddSerilog(logger);
//Depency injection for Class Library method
//LoggerTestClass is a class in my Class Library project
builder.Services.AddScoped<ILoggerTestClass, LoggerTestClass>();
var app = builder.Build();
app.ConfigureTestAPI();
方法“ConfigureTestAPI()”位于扩展类中,如下所示
public static class API_Test
{
public static void ConfigureTestAPI(this WebApplication app)
//Extension method for app
{
app.MapGet("/test/", GetTest);
}
private static async Task<IResult> GetTest(int id,
ILogger<LoggerTestClass> logger, ILoggerTestClass testClass)
{
try
{
try
{
//This works
logger.LogInformation("Starting test now");
//This does NOT work
Log.Information("Using Log. directly");
testClass.Test(); //Call to class library method
logger.LogInformation("Test finished"); //Also works
return Results.Ok("OK");
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
}
}
:最后这是我的类库中带有测试方法的类:
namespace TestingLib.Testing;
public class LoggerTestClass : ILoggerTestClass
{
private Microsoft.Extensions.Logging.ILogger _logger;
public LoggerTestClass(ILogger<LoggerTestClass> logger)
{
_logger = logger;
}
public void Test()
{
try
{
//Does not work
Log.Information("Test logging from class library using Log.");
//Does not work
Log.Logger.Information("In Test Class in DLL. Trying loging with [Log.Logger.Information]");
//This works
_logger.LogInformation("In Test Class in DLL. Trying loging with [_logger.LogInformation]");
}
catch (Exception ex)
{
Log.Error("An error in class library");
}
}
}
I have a .Net 6 Core Minimal API set up to use SeriLog to log to MS SQL Server. In my class library I have managed to get logging working with SeriLog ONLY IF I modify the constructors in my class libraries. I am trying to avoid modifying the constructors of my class library classes or methods.
In my experience with console apps, if I set up SeriLog in my main Program.cs, then I can use logging in any class in my class library without passing the logger to the constructors. So, I can just use Log.Information("my message") anywhere in the class library and it works. I am trying to achieve the same with my Program.cs in a .Net 6 minimal API project.
I sense it should be possible to do from looking at other questions on this topic. In particular this one in which the answer stated that:
You don't have to do anything in your class library. Only the main application has a composition root (earliest point in an application lifecycle you can set up your object graph).
So following from the above, in my API Program.CS, I have this code (I have indicated what works and what does not in the comments):
//Configure SeriLog
builder.Logging.ClearProviders();
var appSettings = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var logDB =
builder.Configuration.GetSection("ConnectionStrings:Default").Value;
var sinkOpts = new MSSqlServerSinkOptions { TableName = "Logs" };
var columnOptions = new ColumnOptions();
var logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft",
Serilog.Events.LogEventLevel.Information)
.WriteTo.MSSqlServer(
connectionString: logDB,
sinkOptions: sinkOpts,
columnOptions: columnOptions,
appConfiguration: appSettings
).CreateLogger();
builder.Logging.AddSerilog(logger);
//Depency injection for Class Library method
//LoggerTestClass is a class in my Class Library project
builder.Services.AddScoped<ILoggerTestClass, LoggerTestClass>();
var app = builder.Build();
app.ConfigureTestAPI();
The Method "ConfigureTestAPI()" is in a Extension Class that is shown below:
public static class API_Test
{
public static void ConfigureTestAPI(this WebApplication app)
//Extension method for app
{
app.MapGet("/test/", GetTest);
}
private static async Task<IResult> GetTest(int id,
ILogger<LoggerTestClass> logger, ILoggerTestClass testClass)
{
try
{
try
{
//This works
logger.LogInformation("Starting test now");
//This does NOT work
Log.Information("Using Log. directly");
testClass.Test(); //Call to class library method
logger.LogInformation("Test finished"); //Also works
return Results.Ok("OK");
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
}
}
And finally here is the class with the test method in my class library:
namespace TestingLib.Testing;
public class LoggerTestClass : ILoggerTestClass
{
private Microsoft.Extensions.Logging.ILogger _logger;
public LoggerTestClass(ILogger<LoggerTestClass> logger)
{
_logger = logger;
}
public void Test()
{
try
{
//Does not work
Log.Information("Test logging from class library using Log.");
//Does not work
Log.Logger.Information("In Test Class in DLL. Trying loging with [Log.Logger.Information]");
//This works
_logger.LogInformation("In Test Class in DLL. Trying loging with [_logger.LogInformation]");
}
catch (Exception ex)
{
Log.Error("An error in class library");
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我发现问题出在我的 API Program.cs 文件中缺少一行代码。我需要添加:“Log.Logger = logger;”设置 SeriLog 记录器后。
工作解决方案的代码如下。
在我的 .NET6 API Program.cs 文件中,我有这样的:
然后在这个文件的下方,我有这样的:
调用类库的 API Get 方法现在看起来像这样(如果与问题中的原始方法相比,您将看到不再需要传递 ILogger):
最后,这是我的类库中的完整测试类。类库包含对 SeriLog 的引用:
我发现这非常适合我的项目。类库中的日志记录直接进入我的 SQL 数据库,其中包含自定义列等。
I found the problem was a single line of code that was lacking in my API Program.cs file. I needed to add: "Log.Logger = logger;" after setting up the SeriLog logger.
The code for the working solution is below.
In my .NET6 API Program.cs file I have this:
And then lower down in this file I have this:
My API Get method that calls into the Class Library now looks like this (if compared to the original one in the question, you will see there is no longer a need to pass ILogger around):
And finally, here is the full Test Class in my class library. The class library contains a reference to SeriLog:
I found this works perfectly for my project. Loggging from the class library goes directly into my SQL database with the custom columns etc.
我建议使用两阶段初始化:https ://github.com/serilog/serilog-aspnetcore#two-stage-initialization
因此请尽早初始化
Log.Logger
,而不是在builder.Build()
之前。代码>I would recommend to use Two-stage initialization: https://github.com/serilog/serilog-aspnetcore#two-stage-initialization
So init
Log.Logger
as early as possible not before thebuilder.Build()