Внедрение зависимости в частичный класс

#c# #asp.net-core #dependency-injection

#c# #asp.net-core #внедрение зависимости

Вопрос:

Мы используем .NET Core 3.1 . Мы хотим использовать частичные классы для разделения реализации сервиса на несколько файлов. Код выглядит следующим образом:

IAccountsService.cs

 public interface IAccountsService
{
    AppUser Get(string username);
    bool HasRole(string username, int roleId);
    // ...
}
  

AccountsService.cs

 public partial class AccountsService : IAccountsService
{
    private readonly MyDbContext _dbContext;
    
    public AccountsService(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    
    public AppUser Get(string username)
    {
        return _dbContext.AppUser.FirstOrDefault(x => x.Username == username);
    }
}
  

Служба учетных записей.Роли.cs

 public partial class AccountsService : IAccountsService
{
    public bool HasRole(string username, int roleId)
    {
        // _dbContext is null here!
    }
}
  

AccountsController.cs

 private readonly IAccountsService _accountsService;

public AccountsController(IAccountsService accountsService)
{
    _accountsService = accountsService;
}

[HttpGet]
public IActionResult Test1()
{
    // _dbContext is NOT null
    return Ok(_accountsService.Get("admin", 1));
}

[HttpGet]
public IActionResult Test2()
{
    // _dbContext is null
    return Ok(_accountsService.HasRole("admin", 1));
}
  

Я заметил, что когда я вызываю Test1 (который вызывает Get(string username) ), _dbContext ЭТО НЕ null . Но, когда я вызываю Test2 (который вызывает HasRole(string username, int roleId) ), _dbContext является null . При вызове Test2 конструктор в AccountsService.cs никогда не попадает.

Комментарии:

1. Вы подтвердили, что все работает нормально, если вместо этого поместить весь код в один файл? partial действительно не должно оказывать никакого влияния на DI.

2. У вас есть несколько конструкторов в AccountsService ? Вы также должны добавить проверку аргументов следующим образом: this.dbContext == dbContext ?? throw new ArgumentNullException(nameof(dbContext)); .

3. partial это функция времени компиляции, DI — среда выполнения. Это не может повлиять друг на друга.

4. @Dai Да, действительно, в AccountsService было несколько конструкторов. Я удалил их, и теперь это работает.

5. «Мы хотим использовать частичные классы для разделения реализации сервиса на несколько файлов». Мне кажется, ваши классы просто слишком большие, что вызывает проблемы с ремонтопригодностью. Разделение их на части поможет вам лишь незначительно. Возможно, здесь вы нарушаете принцип единой ответственности. Возможно, вы захотите сначала устранить основную проблему.

Ответ №1:

Как отметили люди в комментариях: « partial это функция времени компиляции, DI — это среда выполнения». Это компилятор, объединяющий эти два класса, поэтому, если вы видите, что _dbContext равно null во время вызова HasRole , это может означать несколько вещей:

  1. AccountsService(MyDbContext dbContext) Конструктор вызывается с null аргументом. Поскольку вы говорите, что конструктор «никогда не попадает» в Test2 , эти параметры, похоже, оказались ложными.
  2. Вызывается другой конструктор (например, ctor по умолчанию). Это может иметь место, если у вас есть третий частичный класс, о котором вы не знаете.
  3. Компилятор C # не объединяет две части в один тип CLR, что произойдет, если у них обоих разные пространства имен или разные сборки. В этом случае C # генерирует конструктор по умолчанию для типа «Роли», который будет вызываться контейнером DI.

Комментарии:

1. У меня был другой конструктор, который вызывался. Спасибо, что указали на это.