将 DbContext 和 ILogger 注入数据库 DAL 构造函数,最佳实践
Injecting DbContext and ILogger into database DAL constructor, best practice
我正在使用 Entity Framework.Entity Framework 在 ASP.NET Core 3.1 中构建 Web API
我的数据库上下文在 Startup.cs:
中注册为服务
services.AddDbContext<LocalDbContext>(options =>
{
options.UseSqlServer(builderLocal.ConnectionString);
});
我正在使用 DI 在我的控制器中检索 DbContext
,当我为每个方法实例化它时将其传递到我的数据库访问-class (DAL)
private readonly LocalDbContext _context;
public HomeController(LocalDbContext context)
{
_context = context;
}
public IActionResult GetSomeData(int id)
{
var localDb = new LocalDb(_context);
return Ok(localDb.GetSomeDataById(id));
}
然后是我的数据库文件:
public class LocalDbContext : DbContext
{
public LocalDbContext(DbContextOptions<LocalDbContext> options)
: base (options) { }
**DbSets for my models**
}
public class LocalDb
{
private readonly LocalDbContext _context;
private readonly ILogger<LocalDb> _logger;
// I would want to avoid having to pass in logger in this contstructor
public LocalDb(LocalDbContext context)
{
_context = context;
// Can I retrieve a logger from somewhere else? From the context?
// _logger = logger;
}
public void AddStudent(Student student)
{
_context.Student.Add(student);
try
{
_context.SaveChanges();
}
catch (Exception ex)
{
_logger.LogError("logMessage about exception: " + ex.StackTrace);
throw;
}
}
}
所以我希望可以写入 _logger,但在我的代码中我没有将 _logger 设置为任何值。我知道 ILogger
存在于 DbContext 中,并且有很多指南解释了如何为上下文和 EF 添加和配置记录器。但是当我想使用我的 LocalDb
class 时,我是否必须在每次调用 var localDb = new LocalDb(_context, _logger)
时传入一个 ILogger 实例
我觉得每次都要传入一个logger实例有点奇怪,必须有更好的解决方案。是否可以将 LocalDb class 添加为服务,然后依赖项将上下文和记录器注入到 class 中?最佳做法是什么?
请注意 HomeController
不直接使用 LocalDbContext
,而只是将其传递给它的 real 依赖项,LocalDb
.因此,你不应该将 LocalDbContext
注入到 HomeController
的构造函数中,而是直接注入 LocalDb
。这优雅地解决了你的问题,因为现在 LocalDb
可以在 DI 容器中注册,它可以为你解决它可能具有的任何依赖关系。
这是一个直接依赖于 LocalDb
的 HomeController
示例。
public class HomeController : Controller
{
private readonly LocalDb _db;
public HomeController(LocalDb db)
{
_db = db;
}
public IActionResult GetSomeData(int id)
{
return Ok(_db.GetSomeDataById(id));
}
}
因为LocalDb
被注入到构造函数中,所以必须在DI Container中注册:
services.AddTransient<LocalDb>();
services.AddDbContext<LocalDbContext>(options =>
{
options.UseSqlServer(builderLocal.ConnectionString);
});
但是由于LocalDb
是由DI Container组成的,它可以用任何依赖来扩展,比如ILogger
依赖:
public class LocalDb
{
private readonly LocalDbContext _context;
private readonly ILogger<LocalDb> _logger;
public LocalDb(LocalDbContext context, ILogger<LocalDb> _logger)
{
_context = context;
_logger = logger;
}
...
}
提示: 防止在您的代码库中散布 catch
记录和重新抛出的语句。相反,更喜欢有一些全局基础设施来记录所有失败的请求。如果我没记错的话 ASP.NET Core 会为您开箱即用。如果没有,只需几行代码即可启用。这使代码(例如您的 LocalDb.AddStudent
更简单,并限制了 class 具有的依赖项数量。
我正在使用 Entity Framework.Entity Framework 在 ASP.NET Core 3.1 中构建 Web API
我的数据库上下文在 Startup.cs:
中注册为服务services.AddDbContext<LocalDbContext>(options =>
{
options.UseSqlServer(builderLocal.ConnectionString);
});
我正在使用 DI 在我的控制器中检索 DbContext
,当我为每个方法实例化它时将其传递到我的数据库访问-class (DAL)
private readonly LocalDbContext _context;
public HomeController(LocalDbContext context)
{
_context = context;
}
public IActionResult GetSomeData(int id)
{
var localDb = new LocalDb(_context);
return Ok(localDb.GetSomeDataById(id));
}
然后是我的数据库文件:
public class LocalDbContext : DbContext
{
public LocalDbContext(DbContextOptions<LocalDbContext> options)
: base (options) { }
**DbSets for my models**
}
public class LocalDb
{
private readonly LocalDbContext _context;
private readonly ILogger<LocalDb> _logger;
// I would want to avoid having to pass in logger in this contstructor
public LocalDb(LocalDbContext context)
{
_context = context;
// Can I retrieve a logger from somewhere else? From the context?
// _logger = logger;
}
public void AddStudent(Student student)
{
_context.Student.Add(student);
try
{
_context.SaveChanges();
}
catch (Exception ex)
{
_logger.LogError("logMessage about exception: " + ex.StackTrace);
throw;
}
}
}
所以我希望可以写入 _logger,但在我的代码中我没有将 _logger 设置为任何值。我知道 ILogger
存在于 DbContext 中,并且有很多指南解释了如何为上下文和 EF 添加和配置记录器。但是当我想使用我的 LocalDb
class 时,我是否必须在每次调用 var localDb = new LocalDb(_context, _logger)
我觉得每次都要传入一个logger实例有点奇怪,必须有更好的解决方案。是否可以将 LocalDb class 添加为服务,然后依赖项将上下文和记录器注入到 class 中?最佳做法是什么?
请注意 HomeController
不直接使用 LocalDbContext
,而只是将其传递给它的 real 依赖项,LocalDb
.因此,你不应该将 LocalDbContext
注入到 HomeController
的构造函数中,而是直接注入 LocalDb
。这优雅地解决了你的问题,因为现在 LocalDb
可以在 DI 容器中注册,它可以为你解决它可能具有的任何依赖关系。
这是一个直接依赖于 LocalDb
的 HomeController
示例。
public class HomeController : Controller
{
private readonly LocalDb _db;
public HomeController(LocalDb db)
{
_db = db;
}
public IActionResult GetSomeData(int id)
{
return Ok(_db.GetSomeDataById(id));
}
}
因为LocalDb
被注入到构造函数中,所以必须在DI Container中注册:
services.AddTransient<LocalDb>();
services.AddDbContext<LocalDbContext>(options =>
{
options.UseSqlServer(builderLocal.ConnectionString);
});
但是由于LocalDb
是由DI Container组成的,它可以用任何依赖来扩展,比如ILogger
依赖:
public class LocalDb
{
private readonly LocalDbContext _context;
private readonly ILogger<LocalDb> _logger;
public LocalDb(LocalDbContext context, ILogger<LocalDb> _logger)
{
_context = context;
_logger = logger;
}
...
}
提示: 防止在您的代码库中散布 catch
记录和重新抛出的语句。相反,更喜欢有一些全局基础设施来记录所有失败的请求。如果我没记错的话 ASP.NET Core 会为您开箱即用。如果没有,只需几行代码即可启用。这使代码(例如您的 LocalDb.AddStudent
更简单,并限制了 class 具有的依赖项数量。