首页 文章

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

提问于
浏览
9

我为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();
    }
}

Startup.cs

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

我原以为我可能需要在IServiceCollection服务中添加Serilog,但是文章Leaner,更简单的ASP.NET Core 2登录https://nblumhardt.com/2017/08/use-serilog/告诉我这是不必要的 .

然后您可以继续删除任何其他 Logger 配置:appsettings.json中不需要“Logging”部分,任何地方都不需要AddLogging(),也不需要通过Startup.cs中的ILoggerFactory进行配置 . UseSerilog()取代内置的ILoggerFactory,以便应用程序中的每个 Logger ,无论是Serilog的Log类,Serilog的ILogger还是Microsoft.Extensions.Logging.ILogger,都将使用相同的Serilog实现进行备份,并通过相同的配置进行控制 .

What I Expected

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

using Serilog;
public MyTestClass(ILogger logger) { ... }

What I Got - Web (Startup) Project

如果我使用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.");
    }
}

如果我尝试注入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.");
    }
}

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

My Bigger Issue - OtherProjects

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

当我尝试使用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) { ... }

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

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

Questions

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

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

2 回答

  • 2

    此解决方案正确地将 Logger 注入外部项目或库中的类 .

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

    我在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);
            }
        }
    }
    
  • 4

    一种对我有用的方法:

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

    services.AddSingleton((ILogger)new LoggerConfiguration()
                .MinimumLevel.Information()
                .WriteTo.File(<...>)
                .CreateLogger());
    

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

相关问题