在多个项目中使用Asp.Net Core 2注入Serilog

pla*_*sjh 13 c# asp.net logging serilog asp.net-core-mvc

我为Asp.Net Core 2.0配置了Serilog,它在我的启动Web项目中通过.Net Core依赖注入工作得很好(如果我通过Microsoft.Extensions.Logging使用它),但我无法从任何其他项目访问它.

这就是我所拥有的:

Program.cs中

using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;

namespace ObApp.Web.Mvc
{
    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)
            .Build();

        public static void Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                .ReadFrom.Configuration(Configuration)
                .CreateLogger();

            try
            {
                Log.Warning("Starting BuildWebHost");

                BuildWebHost(args).Run();
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Host terminated unexpectedly");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseSerilog()
                .Build();
    }
}
Run Code Online (Sandbox Code Playgroud)

Startup.cs

启动.cs是纯默认的.我没有从新的Asp.Net Core MVC项目的原始模板中以任何方式改变它.

我以为我可能需要增加Serilog在IServiceCollection服务,但文章更精简,更猛烈的ASP.NET的Core 2记录https://nblumhardt.com/2017/08/use-serilog/告诉我这是不必要的.

然后你可以继续删除任何其他记录器配置:appsettings.json中不需要"Logging"部分,任何地方都不需要AddLogging(),也不需要通过Startup.cs中的ILoggerFactory进行配置.

UseSerilog()替换内置的ILoggerFactory,以便应用程序中的每个记录器,无论是Serilog的Log类,Serilog的ILogger还是Microsoft.Extensions.Logging.ILogger,都将使用相同的Serilog实现进行备份,并通过相同的配置进行控制.

我所期待的

能够在解决方案的任何项目中的任何类中通过构造函数简单地注入记录器.例如:

using Serilog;
public MyTestClass(ILogger logger) { ... }
Run Code Online (Sandbox Code Playgroud)

我得到了什么 - Web(启动)项目

如果我使用Microsoft.Extensions.Logging包装器,注入在HomeController中工作:

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogDebug("Controller instantiated.");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试注入Serilog.ILogger,则在任何项目/类中注入失败

using Serilog;
using Serilog.Extensions.Logging; // Not sure if this would help.

public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger logger)
    {
        _logger = logger;
        _logger.Debug("Controller instantiated.");
    }
}
Run Code Online (Sandbox Code Playgroud)

InvalidOperationException:尝试激活'ObApp2.Web.Mvc.Controllers.HomeController'时无法解析类型'Serilog.ILogger'的服务.

我的更大问题 - 其他项目

我更大的问题是,如果我在解决方案中的另一个项目中工作,我无法通过我尝试过的任何方法获取记录器.

当我尝试使用Microsoft.Extensions.Logging或使用Serilog注入时,我在构建时得到一个缺少的参数异常.

using Microsoft.Extensions.Logging;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger<MyTestClass> logger) { ... }

- or -

using Serilog;
namespace ObApp.Domain
{
    public class MyTestClass(ILogger logger) { ... }
Run Code Online (Sandbox Code Playgroud)

两者都生成类似于的构建错误:

没有任何参数对应于'MyTestClass.MyTestClass(ILogger)'所需的形式参数'logger'

问题

  1. 注入这种类型的Serilog配置时,是否建议我在我正在进行注入的类文件中引用Microsoft.Extensions.Logging或Serilog?

  2. 如何让DI在所有项目中运作?

McG*_*V10 6

此解决方案正确地将记录器注入到外部项目或库中的类中。

我也尝试了 Rufus 建议的答案。我没有 OP 描述的问题,但我遇到了一个更奇怪的问题:在ILogger注入外部项目后,登录到 MS SQL 停止工作。控制台日志记录工作。由于 Serilog 主要是一个静态服务,我意识到我应该将其Log.Logger视为工厂。好处是您仍然可以自定义ILogger引用(例如,ForContext在构造函数中添加)而不会影响“单例”服务。

我已经在github上发布了一个完整的工作解决方案,包括一个设置 DI 的控制台程序(在 ASP.NET Core 中的工作方式相同)、一个包含 Serilog 入门除零演示的外部库和另一个库将 Serilog 作为服务进行管理。

重要的部分,Serilog 服务注册,看起来像这样(作为奖励,我们绑定到ProcessExit透明清理):

using Microsoft.Extensions.DependencyInjection;
using System;

namespace Serilog.Injection
{
    public static class RegisterSerilogServices
    {
        public static IServiceCollection AddSerilogServices(this IServiceCollection services)
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.Console()
                .WriteTo.MSSqlServer(@"xxxxxxxxxxxxx", "Logs")
                .CreateLogger();

            AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush();

            return services.AddSingleton(Log.Logger);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Nin*_*ark 6

我实际上一直在为相同的设置而苦苦挣扎,但我设法让它发挥作用。该解决方案与您的代码示例仅在以下方面略有不同:

  • 这取决于Microsoft.Extensions.Logging.ILogger.
  • 记录器被注入使用 ILogger<Type>

您的控制器代码已经符合这些要求,这就是为什么它起作用的原因。

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    ILogger _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogInformation("Controller instantiated");
    }
}
Run Code Online (Sandbox Code Playgroud)

对于其他项目中的其他类,只需确保您依赖于默认的 ILogger 接口,而不是 Serilog 的实现。这还有一个好处,如果您以后想替换 Serilog,您可以这样做,而无需在其他项目中删除对它的所有引用。

using Microsoft.Extensions.Logging;

public class MyBusinessObject
{
    ILogger _logger;

    public MyBusinessObject(ILogger<MyBusinessObject> logger)
    {
        _logger = logger;
    }

    public void DoBusinessLog()
    {
        _logger.Information("Executing Business Logic");
    }
}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,DI 仅在需要ILogger<Type>但不是 for时才设法实例化 Logger 实例ILogger。为什么我不知道,也许其他人可以回答这个问题。

  • 这是使用 ASP.NET Core ILogger Extension 使用 Serilog 的正确答案 (2认同)

小智 5

一种对我有用的方法:

我在ConfigureServices方法中使用AddSingleton()方法添加了Serilog.Core.Logger的实例。这解决了DI问题。此步骤代替了在StartUp构造函数中将Logger实例分配给Log.Logger的步骤。

services.AddSingleton((ILogger)new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(<...>)
            .CreateLogger());
Run Code Online (Sandbox Code Playgroud)

还要更改类文件中的引用以指向Serilog.Ilogger