Внедрение DbContext и ILogger в конструктор DAL базы данных, лучшие практики - PullRequest
0 голосов
/ 15 апреля 2020

Я создаю веб-API в ASP. NET Core 3.1 с Entity Framework.

Мой контекст базы данных зарегистрирован как служба в Startup.cs:

services.AddDbContext<LocalDbContext>(options =>
{
    options.UseSqlServer(builderLocal.ConnectionString);
});

И я извлекаю DbContext в моем контроллере, используя DI, передавая его в свой класс доступа к базе данных (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;
        }
    }
}

Так что я sh хочу, чтобы _logger был доступен для записи, но в моем коде я не установил _logger в что-либо. Я знаю, что ILogger существует в DbContext, и есть много руководств, объясняющих, как добавить и настроить регистратор для Context и EF. Но когда я хочу использовать свой класс LocalDb, должен ли я передавать экземпляр ILogger каждый раз, когда я вызываю var localDb = new LocalDb(_context, _logger)

, я чувствую, что каждый раз приходится передавать экземпляр регистратора странно, должно быть лучшее решение для этого. Можно ли добавить класс LocalDb в качестве службы, затем добавить контекст зависимостей и регистратор в этот класс? Какая лучшая практика?

1 Ответ

3 голосов
/ 15 апреля 2020

Обратите внимание, что HomeController не LocalDbContext напрямую, а только использует его, чтобы передать его в свою зависимость real , LocalDb. Следовательно, вы не должны вставлять LocalDbContext в конструктор HomeController, а вместо этого вводить LocalDb напрямую. Это решает ваши проблемы элегантно, потому что теперь LocalDb может быть зарегистрирован в контейнере DI, и он может разрешить его для вас с любой зависимостью, которую он может иметь.

Вот пример HomeController, который зависит от LocalDb напрямую.

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:

services.AddTransient<LocalDb>();
services.AddDbContext<LocalDbContext>(options =>
{
    options.UseSqlServer(builderLocal.ConnectionString);
});

Но поскольку LocalDb состоит из DI-контейнер, он может быть расширен любыми зависимостями, такими как ILogger зависимость:

public class LocalDb
{
    private readonly LocalDbContext _context;
    private readonly ILogger<LocalDb> _logger;

    public LocalDb(LocalDbContext context, ILogger<LocalDb> _logger) 
    {
        _context = context;
        _logger = logger; 
    }
    ...
}

TIP: Предотвращение спринклинговых операторов catch в базе кода, которые регистрируются и повторно выдать. Вместо этого предпочтительнее иметь некоторую глобальную инфраструктуру, которая регистрирует любые неудачные запросы. Если я не ошибаюсь ASP. NET Core сделает это за вас из коробки. Если нет, это можно включить всего несколькими строками кода. Это значительно упрощает код (например, LocalDb.AddStudent) и ограничивает число зависимостей, которые имеет класс.

...