【问题标题】:Using Serilog with Caliburn Micro .Net Core 3.1将 Serilog 与 Caliburn Micro .Net Core 3.1 一起使用
【发布时间】:2020-09-04 11:27:09
【问题描述】:

我正在尝试将 Serilog 注入到我的 .NET Core 3.1 WPF 应用程序中的类和项目中。

我正在使用 Caliburn.Micro 框架来处理 MVVM 方面的事情,Serilog Logger 已在 Bootstrapper 类中配置,我不清楚我如何注册记录器的实例以便它可用于我的应用程序中的 DI。

这是我在 Bootstrapper 类中的,我在构造函数中添加了一个简单的try-catch 以证明记录器已配置。

public class Bootstrapper : BootstrapperBase
{
    private SimpleContainer _container = new SimpleContainer();
    public Bootstrapper()
    {
        Initialize();

        try
        {
            Log.Information("In Bootstrapper Configure method");
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "The application failed to start correctly");
        }
        finally
        {
            Log.CloseAndFlush();
        }
    }

    protected override void Configure()
    {
        _container.Instance(_container);

        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .WriteTo.File("log.txt")
            .CreateLogger();

        _container
            .Singleton<IWindowManager, WindowManager>()
            .Singleton<IEventAggregator, EventAggregator>()
        

        _container
            .PerRequest<IMyDataHandler, MyDataHandler>();

        GetType().Assembly.GetTypes()
            .Where(type => type.IsClass)
            .Where(type => type.Name.EndsWith("ViewModel"))
            .ToList()
            .ForEach(viewModelType => _container.RegisterPerRequest(
                viewModelType, viewModelType.ToString(), viewModelType));


    }

    protected override void OnStartup(object sender, StartupEventArgs e)
    {
        DisplayRootViewFor<ShellViewModel>();
    }

    protected override object GetInstance(Type service, string key)
    {
        return _container.GetInstance(service, key);
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        _container.BuildUp(instance);
    }


}

任何帮助或指向文档的指针都会很棒。

【问题讨论】:

  • 你当前的代码有什么问题?
  • @PavelAnikhouski 我遇到的问题是,当尝试将记录器注册到容器时,它给了我错误类型名称 Logger 在类型 Log 中不存在,因此 DI 不起作用。

标签: c# .net-core caliburn.micro serilog


【解决方案1】:

您可以通过在容器上调用 Singleton 来注册 Serilog 的 ILogger,就像在应用中注册所有其他单例一样:

_container.Singleton<ILogger, Log.Logger>();

在您的应用程序中使用 Serilog 记录器的另一种方法(我个人更喜欢)是从您的任何类(ViewModels、Services 等)访问Log.Logger。使用Log.ForContext&lt;&gt; 也很容易获得contextual logger for every class,这在解决问题时很有用。例如

public class SomeViewModel
{
    private readonly ILogger _log = Log.ForContext<SomeViewModel>();
    // ...
}

public class SomeService
{
    private readonly ILogger _log = Log.ForContext<SomeService>();
    // ...
}

【讨论】:

  • 我认为我的项目中遗漏了一些东西。当我尝试使用容器注册 ILogger 时,我在 Log.Logger 下有一个红色波浪线,告诉我“类型名称 Logger 不存在于类型 Log 中”。如果尝试您的其他建议,则解决方案将编译并且行 _log.Information("some text");执行,但在 Bootstrapper 类的构造函数中写入的日志文件中没有任何内容。你能想到我可能缺少什么吗?
【解决方案2】:

Log是静态的,Logger是静态的所以不需要注册,也不用DI:

您使用Log.Information("something");Log.Fatal("something"); 的任何地方都会进入您的日志文件。

public class SomeViewModel
{
    public SomeViewModel()
    {
       Log.Information("i am in somethingVM");
    } 
}

如果你想使用 DI,你必须使用这样的实例:(我使用 Caliburn 提供的接口 ILog 并创建封装 Logger 的类 Log..)

public class Log : ILog
{
    #region Fields

    #endregion

    private readonly ILogger logger;
    #region Constructors
    public Log()
    {
        logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.File(@"d:\log.txt").CreateLogger();

    }
    #endregion

    #region Helper Methods
    private string CreateLogMessage(string format, params object[] args)
    {
        return string.Format("[{0}] {1}",
            DateTime.Now.ToString("o"),
            string.Format(format, args));
    }
    #endregion

    #region ILog Members
    public void Error(Exception exception)
    {
        logger.Error(CreateLogMessage(exception.ToString()), "ERROR");
    }

    public void Info(string format, params object[] args)
    {
        if (Array.FindIndex(args, t => t.ToString().Contains("Something i dont want to log")) >= 0)
            return;
        logger.Information(CreateLogMessage(format, args), "INFO");
    }

    public void Warn(string format, params object[] args)
    {
        logger.Warning(CreateLogMessage(format, args), "WARN");
    }
    #endregion
}

然后你将 ILog 与 Log 绑定

 _container.Singleton<ILog, Log>();


public class SomeViewModel
{
    public SomeViewModel(ILog logger)
    {
       logger.Info("i am in somethingVM");
    } 
}

我不是 simplecontainer 方面的专家,但是如果您想在引导程序中调用记录器,则必须在注册后将实例捕获在容器中(以进行测试):

IoC.Get<ILog>().Info("I am in boot");

通过这种编程方式,你做你想做的事,我已经为你的例子链接了类日志和 Serilog,但不需要使用它..


我使用 ninject,所以我们可以使用它:

        kernel.Bind<ILogger>().ToMethod(x => new LoggerConfiguration()
            .WriteTo.File(@"d:\toto.log")
            .CreateLogger());

这简化了绑定,但我不知道simplecontainer是否有这个功能,不需要声明类Log。

public class SomeViewModel
{
    public SomeViewModel(ILogger logger)
    {
       logger.Information("i am in somethingVM");
    } 
}

使用 simplecontainer 我看到了这种语法,但不确定它是否与 Ninject 相同:

        Container.RegisterHandler(typeof(ILogger), "Ilogger", x => new LoggerConfiguration()
            .WriteTo.File(@"d:\log.txt")
            .CreateLogger());

【讨论】:

  • 感谢您的帮助,感谢您抽出宝贵时间提供详细的选项说明。它在我的应用程序中工作,包括注入项目。
猜你喜欢
  • 1970-01-01
  • 2016-04-06
  • 1970-01-01
  • 1970-01-01
  • 2022-06-25
  • 2021-05-03
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多