.NET 5.0 C#项目Shared与DbContext子项目循环依赖如何解决?
核心逻辑是把日志的接口定义和具体实现拆分到不同项目,让依赖方只依赖抽象接口,不依赖具体实现,从编译层面切断循环依赖链。
具体操作步骤
第一步:新增纯抽象层项目
ProjectName.Shared.Logging.Abstractions
该项目仅定义日志服务的公共接口,不包含任何业务实现,也不依赖任何其他业务项目。示例接口定义如下:namespace ProjectName.Shared.Logging.Abstractions; public interface ILoggerService { void Info(string message, params object[] args); void Error(Exception exception, string message, params object[] args); // 其他你需要的日志方法定义 }第二步:调整
ProjectName.DbContext依赖
移除ProjectName.DbContext对具体日志实现项目的依赖,仅引用上述抽象层项目,所有日志调用都通过构造注入的ILoggerService接口完成,不需要关心日志的具体实现逻辑:using ProjectName.Shared.Logging.Abstractions; public class YourDbContext : DbContext { private readonly ILoggerService _logger; public YourDbContext(DbContextOptions<YourDbContext> options, ILoggerService logger) { _logger = logger; } public override int SaveChanges() { _logger.Info("执行数据保存操作"); return base.SaveChanges(); } }第三步:单独实现数据库日志逻辑
新建ProjectName.Logging.Implementation项目用于存放写数据库的日志实现,该项目依赖两个项目:日志抽象层ProjectName.Shared.Logging.Abstractions、数据层ProjectName.DbContext,实现代码示例:using ProjectName.Shared.Logging.Abstractions; using ProjectName.DbContext; public class DbLoggerService : ILoggerService { private readonly YourDbContext _dbContext; public DbLoggerService(YourDbContext dbContext) { _dbContext = dbContext; } public void Info(string message, params object[] args) { _dbContext.Logs.Add(new Log { Level = "Info", Content = string.Format(message, args), CreateTime = DateTime.Now }); _dbContext.SaveChanges(); } public void Error(Exception exception, string message, params object[] args) { // 错误日志写入逻辑 } }第四步:入口项目统一注册依赖
你的Web/Console等启动入口项目依赖所有抽象和实现项目,在DI容器中完成服务注册即可,运行时容器会自动完成依赖注入:// Program.cs 注册逻辑 builder.Services.AddScoped<ILoggerService, DbLoggerService>(); builder.Services.AddDbContext<YourDbContext>(options => { // 你的数据库连接配置 });
可选优化
如果不想新增太多子项目,也可以直接把日志抽象接口放在现有ProjectName.Shared项目中,只要保证ProjectName.DbContext仅依赖日志接口,具体数据库日志实现放在不被ProjectName.DbContext依赖的项目中即可。如果希望进一步解耦,也可以为日志表单独创建独立的DbContext放在日志实现项目中,不需要依赖业务DbContext,结构会更干净。
内容的提问来源于stack exchange,提问作者Jana Weschenfelder

