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

时间:2017-12-07 19:39:50

标签: c# asp.net logging asp.net-core-mvc serilog

我为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,但https://nblumhardt.com/2017/08/use-serilog/上的文章 Leaner,meaner ASP.NET Core 2 logging 告诉我这是不必要的。

  

然后您可以继续删除任何其他记录器配置   闲逛:不需要“登录”部分   appsettings.json,没有AddLogging()在任何地方,没有配置   通过Startup.cs中的ILoggerFactory。

     

UseSerilog()替换内置的ILoggerFactory以便每个记录器   在你的应用程序中,无论是Serilog的Log类,Serilog的   将支持ILogger或Microsoft.Extensions.Logging.ILogger   具有相同的Serilog实现,并通过相同的控制   配置。

我的期望

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

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

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

如果我使用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:无法解析服务   尝试激活时输入'Serilog.ILogger'类型   'ObApp2.Web.Mvc.Controllers.HomeController'。

我的更大问题 - 其他项目

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

当我尝试使用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'

问题

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

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

4 个答案:

答案 0 :(得分:4)

一种对我有用的方法:

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

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

同时更改类文件中的引用以指向Serilog.Ilogger

答案 1 :(得分:4)

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

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

我在github上发布了一个完整的解决方案,其中包括一个控制台程序,用于设置DI(从ASP.NET Core运行相同),一个包含Serilog入门分区的外部库-zero演示,以及管理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);
        }
    }
}

答案 2 :(得分:3)

您不会通过Net Core中的DI访问Serilog。这是静态的。 在Program.Main()中正确配置并初始化了Logger之后,只需像启动,控制器等中的任何其他静态对象一样简单地进行访问即可,即

public void ConfigureServices(IServiceCollection services)
            {
    Serilog.Log.Information("here I am in startup");
    //further options
};

或在顶部添加:

using static Serilog.Log;

简单地:

Information("keystroke saving");

答案 3 :(得分:0)

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

  • 这取决于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");
    }
}

对于其他项目中的其他类,只需确保您依赖默认的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");
    }
}

由于某些原因,DI仅在需要ILogger<Type>时才实例化Logger实例,而对于ILogger则不实例化。为什么我完全不知道为什么,也许别人可以回答那个。