.NET Core DI 和子 类
.NET Core DI and sub classes
这里是 .NET Core 的新手。我已经搜索了另一个文档、线程或指南来回答我的问题,但找不到,如果你认为有,请指出。
我正在尝试使用 DI 创建一个简单的 .NET 5 控制台应用程序,但实际上却陷入了使用日志记录构建 classes 的困境。
这是在 .NET Core 中使用 DI 将记录器(或任何其他服务)传递给子 class 的正确方法吗?
按照下面的代码,在我的父 class 构造函数中,我为每个子 class 例如获取一个额外的 ILogger。
ILogger<SubClass>
?
public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config)
如何在静态过程中初始化记录器 StaticProc
?
public static async Task<bool> StaticProc()
Program.cs:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string[] args)
{
var builder = new ConfigurationBuilder();
BuildConfig(builder);
var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddTransient<ITestClass, TestClass>();
services.AddTransient<ISubClass, SubClass>();
})
.ConfigureLogging(logBuilder =>
{
logBuilder.SetMinimumLevel(LogLevel.Trace);
logBuilder.AddLog4Net("log4net.config");
})
.Build();
var log = host.Services.GetService<ILoggerFactory>().CreateLogger<Program>();
log.LogInformation($"Application Started");
var svc = ActivatorUtilities.CreateInstance<TestClass>(host.Services);
await svc.Run();
log.LogInformation($"Application Ended");
}
static void BuildConfig(IConfigurationBuilder builder)
{
builder.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"}.json", optional: true)
.AddEnvironmentVariables();
}
}
}
TestClass.cs:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class TestClass : ITestClass
{
private readonly ILogger<TestClass> _log;
private readonly ILogger<SubClass> _subClassLog;
private readonly IConfiguration _config;
public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config)
{
_log = log;
_subClassLog = subClassLog;
_config = config;
}
public async Task Run()
{
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogDebug("Loop debug {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogInformation("Loop info {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogWarning("Loop warn {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogError("Loop error {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogCritical("Loop critical {loopNumber}", i);
var subClass = new SubClass(_subClassLog, _config);
await subClass.AnotherProc();
await SubClass.StaticProc();
}
}
}
SubClass.cs:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
public class SubClass : ISubClass
{
private readonly ILogger<SubClass> _log;
private readonly IConfiguration _config;
public SubClass(ILogger<SubClass> log, IConfiguration config)
{
_log = log;
_config = config;
}
public async Task AnotherProc()
{
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogDebug("Loop debug {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogInformation("Loop info {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogWarning("Loop warn {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogError("Loop error {loopNumber}", i);
for (int i = 0; i < _config.GetValue<int>("Loop"); i++)
_log.LogCritical("Loop critical {loopNumber}", i);
}
public static async Task<bool> StaticProc()
{
var returnBool = true;
try
{
throw new Exception("");
}
catch (Exception ex)
{
returnBool = false;
// No instance, so no _log exception.
// How to create standalone ILogger?
}
return returnBool;
}
}
}
appsettings.json:
{
"Loop": 15
}
log4net.config:
<?xml version="1.0" encoding="utf-8"?>
<log4net>
<appender name="Info" type="log4net.Appender.RollingFileAppender">
<threshold value="DEBUG" />
<param name="File" value="App_Data\Log\Info.log"/>
<param name="AppendToFile" value="true"/>
<maximumFileSize value="5120KB"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<maxSizeRollBackups value="1000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{yyyy-MM-dd HH:mm:ss} - [%t] %-5p %c %x - %m%n" />
</layout>
</appender>
<appender name="Error" type="log4net.Appender.RollingFileAppender">
<threshold value="Error" />
<param name="File" value="App_Data\Log\Error.log"/>
<param name="AppendToFile" value="true"/>
<maximumFileSize value="5120KB"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<maxSizeRollBackups value="1000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{yyyy-MM-dd HH:mm:ss} - [%t] %-5p %c %x - %m%n" />
</layout>
</appender>
<root>
<appender-ref ref="Info" />
<appender-ref ref="Error" />
</root>
</log4net>
总结
您也可以注入 ILoggerFactory
而不是 ILogger
:
public TestClass(ILoggerFactory loggerFactory, IConfiguration config)
{
// create a class logger
_log = loggerFactory.CreateLogger<TestClass>();
// and whenever you need a new instance of a special class logger use this:
_subClassLog = loggerFactory.Create<SubTestClass>();
_config = config;
}
但请注意,这会创建一个新的 ILogger 实例。 Logging in asp net core
在您的情况下,如果您确实需要带有记录器的静态方法,则仅当它已经存在时才创建它:
private static readonly ILogger<SubClass> _log;
private readonly IConfiguration _config;
public SubClass(ILoggerFactory loggerFactory, IConfiguration config)
{
_log = _log ??= loggerFactory.CreateLogger<SubClass>();
_config = config;
}
但我会更喜欢或更好地建议您在没有静态的情况下这样做,只需将服务注册为单例即可。
示例 1
我在这里添加了一个完整的例子:dotnet fiddle Example 1
还有像评论中提到的控制台应用程序的工作 DI。
示例 2
我觉得你不应该将它与静态方法一起使用。看看我这里的第二个例子 dotnet fiddle Example 2
这里是 .NET Core 的新手。我已经搜索了另一个文档、线程或指南来回答我的问题,但找不到,如果你认为有,请指出。
我正在尝试使用 DI 创建一个简单的 .NET 5 控制台应用程序,但实际上却陷入了使用日志记录构建 classes 的困境。
这是在 .NET Core 中使用 DI 将记录器(或任何其他服务)传递给子 class 的正确方法吗? 按照下面的代码,在我的父 class 构造函数中,我为每个子 class 例如获取一个额外的 ILogger。
ILogger<SubClass>
?public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config)
如何在静态过程中初始化记录器
StaticProc
?public static async Task<bool> StaticProc()
Program.cs:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.IO; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static async Task Main(string[] args) { var builder = new ConfigurationBuilder(); BuildConfig(builder); var host = Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.AddTransient<ITestClass, TestClass>(); services.AddTransient<ISubClass, SubClass>(); }) .ConfigureLogging(logBuilder => { logBuilder.SetMinimumLevel(LogLevel.Trace); logBuilder.AddLog4Net("log4net.config"); }) .Build(); var log = host.Services.GetService<ILoggerFactory>().CreateLogger<Program>(); log.LogInformation($"Application Started"); var svc = ActivatorUtilities.CreateInstance<TestClass>(host.Services); await svc.Run(); log.LogInformation($"Application Ended"); } static void BuildConfig(IConfigurationBuilder builder) { builder.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"}.json", optional: true) .AddEnvironmentVariables(); } } }
TestClass.cs:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System.Threading.Tasks; namespace ConsoleApp1 { public class TestClass : ITestClass { private readonly ILogger<TestClass> _log; private readonly ILogger<SubClass> _subClassLog; private readonly IConfiguration _config; public TestClass(ILogger<TestClass> log, ILogger<SubClass> subClassLog, IConfiguration config) { _log = log; _subClassLog = subClassLog; _config = config; } public async Task Run() { for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogDebug("Loop debug {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogInformation("Loop info {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogWarning("Loop warn {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogError("Loop error {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogCritical("Loop critical {loopNumber}", i); var subClass = new SubClass(_subClassLog, _config); await subClass.AnotherProc(); await SubClass.StaticProc(); } } }
SubClass.cs:
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; namespace ConsoleApp1 { public class SubClass : ISubClass { private readonly ILogger<SubClass> _log; private readonly IConfiguration _config; public SubClass(ILogger<SubClass> log, IConfiguration config) { _log = log; _config = config; } public async Task AnotherProc() { for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogDebug("Loop debug {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogInformation("Loop info {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogWarning("Loop warn {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogError("Loop error {loopNumber}", i); for (int i = 0; i < _config.GetValue<int>("Loop"); i++) _log.LogCritical("Loop critical {loopNumber}", i); } public static async Task<bool> StaticProc() { var returnBool = true; try { throw new Exception(""); } catch (Exception ex) { returnBool = false; // No instance, so no _log exception. // How to create standalone ILogger? } return returnBool; } } }
appsettings.json:
{ "Loop": 15 }
log4net.config:
<?xml version="1.0" encoding="utf-8"?> <log4net> <appender name="Info" type="log4net.Appender.RollingFileAppender"> <threshold value="DEBUG" /> <param name="File" value="App_Data\Log\Info.log"/> <param name="AppendToFile" value="true"/> <maximumFileSize value="5120KB"/> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <maxSizeRollBackups value="1000"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d{yyyy-MM-dd HH:mm:ss} - [%t] %-5p %c %x - %m%n" /> </layout> </appender> <appender name="Error" type="log4net.Appender.RollingFileAppender"> <threshold value="Error" /> <param name="File" value="App_Data\Log\Error.log"/> <param name="AppendToFile" value="true"/> <maximumFileSize value="5120KB"/> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <maxSizeRollBackups value="1000"/> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%d{yyyy-MM-dd HH:mm:ss} - [%t] %-5p %c %x - %m%n" /> </layout> </appender> <root> <appender-ref ref="Info" /> <appender-ref ref="Error" /> </root> </log4net>
总结
您也可以注入 ILoggerFactory
而不是 ILogger
:
public TestClass(ILoggerFactory loggerFactory, IConfiguration config)
{
// create a class logger
_log = loggerFactory.CreateLogger<TestClass>();
// and whenever you need a new instance of a special class logger use this:
_subClassLog = loggerFactory.Create<SubTestClass>();
_config = config;
}
但请注意,这会创建一个新的 ILogger 实例。 Logging in asp net core 在您的情况下,如果您确实需要带有记录器的静态方法,则仅当它已经存在时才创建它:
private static readonly ILogger<SubClass> _log;
private readonly IConfiguration _config;
public SubClass(ILoggerFactory loggerFactory, IConfiguration config)
{
_log = _log ??= loggerFactory.CreateLogger<SubClass>();
_config = config;
}
但我会更喜欢或更好地建议您在没有静态的情况下这样做,只需将服务注册为单例即可。
示例 1
我在这里添加了一个完整的例子:dotnet fiddle Example 1 还有像评论中提到的控制台应用程序的工作 DI。
示例 2
我觉得你不应该将它与静态方法一起使用。看看我这里的第二个例子 dotnet fiddle Example 2