如何在C# .NET中实现方法依赖注入并解决日志参数缺失问题
我尝试实现一个写入文件的日志记录器,日志文件路径存储在appSettings.json中,已通过模型类关联该配置。以下是我的LogWriter.cs代码:
public class LogWriter { public void WriteLog(string message, IOptions<AppSettings> appSettings) { AppSettings _appSettings = appSettings.Value; using (StreamWriter writer = new StreamWriter(_appSettings.LogFilePath)) { writer.Write("[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") +"] " + message); } } }
我希望通过WriteLog方法注入appSettings依赖,无需实例化LogWriter类即可调用该方法,以下是program.cs的依赖配置代码:
var builder = WebApplication.CreateBuilder(args); builder.Configuration .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); var appSettings = new AppSettings(); builder.Configuration.GetSection("AppSettings").Bind(appSettings); //Add services to the container. builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings")); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddScoped<IMessageService, MessageService>(); builder.Services.AddScoped<LogWriter>();// DI for LogWriter builder.Services.AddDbContext<MailContext>( o => o.UseNpgsql(appSettings.ConnectionStrings.MailDb) ); var app = builder.Build(); app.UseSwagger(); app.UseSwaggerUI(); app.UseAuthorization(); app.MapControllers(); app.Run();
但当我在控制器中以LogWriter.WriteLog("Construktor wird ausgeführt")方式调用时,提示缺少一个参数,控制器代码如下:
[Route("[controller]")] [ApiController] public class MessageController : ControllerBase { private readonly IMessageService _mailService; public MessageController(IMessageService mailServiceCustom ) { _mailService = mailServiceCustom; LogWriter.WriteLog("Construktor wird ausgeführt"); } // ... }
方案一:遵循.NET依赖注入最佳实践(推荐)
这种方式通过构造函数注入依赖,符合DI设计原则,便于测试和维护:
重构
LogWriter,将配置依赖移至构造函数
把IOptions<AppSettings>通过构造函数注入,同时修复日志写入时的覆盖问题(添加append: true参数,并用WriteLine实现换行):public class LogWriter { private readonly AppSettings _appSettings; // 构造函数注入配置 public LogWriter(IOptions<AppSettings> appSettings) { _appSettings = appSettings.Value; } public void WriteLog(string message) { // 追加写入日志,避免覆盖原有内容 using (StreamWriter writer = new StreamWriter(_appSettings.LogFilePath, append: true)) { writer.WriteLine($"[{DateTime.Now:MM/dd/yyyy HH:mm:ss}] {message}"); } } }在控制器中注入
LogWriter实例
修改控制器构造函数,注入LogWriter,然后调用实例方法:[Route("[controller]")] [ApiController] public class MessageController : ControllerBase { private readonly IMessageService _mailService; private readonly LogWriter _logWriter; // 构造函数注入LogWriter public MessageController(IMessageService mailServiceCustom, LogWriter logWriter) { _mailService = mailServiceCustom; _logWriter.WriteLog("Construktor wird ausgeführt"); } // 其他控制器方法... }保持现有
Program.cs配置不变
你已经添加了builder.Services.AddScoped<LogWriter>();,这部分配置无需修改,DI容器会自动处理依赖注入。
方案二:静态调用方式(不推荐)
如果一定要无需实例化即可调用,可以将LogWriter改为静态类,并在程序启动时初始化配置:
修改
LogWriter为静态类public static class LogWriter { private static AppSettings _appSettings; // 初始化配置,在程序启动时调用 public static void Initialize(IOptions<AppSettings> appSettings) { _appSettings = appSettings.Value; } public static void WriteLog(string message) { using (StreamWriter writer = new StreamWriter(_appSettings.LogFilePath, append: true)) { writer.WriteLine($"[{DateTime.Now:MM/dd/yyyy HH:mm:ss}] {message}"); } } }在
Program.cs中初始化静态类var app = builder.Build(); // 获取配置服务并初始化静态LogWriter var appSettings = app.Services.GetRequiredService<IOptions<AppSettings>>(); LogWriter.Initialize(appSettings); // 后续中间件配置不变 app.UseSwagger(); app.UseSwaggerUI(); // ...控制器中静态调用
此时可以直接调用LogWriter.WriteLog("Construktor wird ausgeführt");,无需注入实例。
注意:静态类方式耦合度高,难以进行单元测试,不推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者Razielruss

