Действительно ли нам нужно реализовывать IDisposable в классах Repository или UnitOfWork? - PullRequest
0 голосов
/ 29 января 2019

Сначала , давайте посмотрим, что Microsoft говорит о стандартных службах внедрения зависимостей Asp.Net Core:

Фреймворк берет на себя ответственность за создание экземпляра зависимости и его удаление.когда он больше не нужен.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#disposal-of-services

Т.е. платформа будет вызывать метод Dispose классов (при условии, что класс реализует IDisposable)

Второй , класс DbContext действительно реализует IDisposable из коробки.

Третий , в нашем классе Startup.cs мы добавляем наш DbContext с помощью метода AddDbContext, которыйпо умолчанию добавляется как экземпляр Scoped (т. е. создается наш DbContext и мусор собирается при каждом отдельном запросе).

Службы времени действия Scoped создаются один раз за запрос.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.1#service-lifetimes

Например,

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddDbContext<TheStoreDbContext>(ConfigureDbContext)      
        .AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) 
}

Заключение , нам не нужно явно вызывать context.Dispose () в любом месте нашего основного приложения Asp.net.

Так почему же в Интернете и в учебных руководствах так много примеров, которые показывают, что вы должны реализовать IDisposable в своих классах Repository или UnitOfWork?

Например,

public class UnitOfWork : IUnitOfWork
    {
        private readonly DbContext _context;

        public IProductRepository ProductRepository { get; }

        public UnitOfWork(DbContext context)
        {
            _context = context;
            ProductRepository = new ProductRepository(context);
        }

        public void Dispose()
        {
            _context.Dispose();
        }
    }

Что вы думаете?Это правильный вопрос?Имеет ли смысл никуда явно не вызывать метод Dispose ()?

1 Ответ

0 голосов
/ 29 января 2019

Ваш пример класса UnitOfWork фактически применяет плохую практику.Правило состоит в том, что класс должен распоряжаться только тем, что ему принадлежит .Однако в случае UnitOfWork он не владеет DbContext, так как он не создается UnitOfWork, а предоставляется другим лицом.

Letting UnitOfWork избавиться от этого DbContext даже проблематично, поскольку UnitOfWork не может узнать, используется ли или нет DbContext другими классами в системе, когда утилизируется UnitOfWork.Другими словами, система может сломаться, когда UnitOfWork начнет избавляться от этой зависимости.

Так что, если вы следуете правилу распоряжения только тем, что у вас есть , это означает, что UnitOfWork должно вфакт не реализовать IDisposable вообще.А это значит, что вы позволяете «кому-то другому» управлять временем жизни DbContext.

Эта идея переноса контроля над временем жизни зависимостей (таких как DbContext) третьей стороне не является чем-тоновый, и, конечно, не что-то конкретное для нового контейнера Microsoft DI.На самом деле это старая идея, которая заключается в том, что вы централизуете контроль над временем жизни компонентов приложения на пути запуска приложения.В контексте DI этот начальный путь обычно упоминается как Composition Root .

Внутри Composition Root, это будет работа Composer создавать компоненты приложения, управлять их временем жизни и утилизировать их, когда они больше не нужны.Контейнер DI (такой как DI-контейнер .NET Core) выступает в роли Composer в вашей системе, но вы можете сделать это также вручную - практика, известная как Pure DI .

...