Архитектура для DbContext в приложении .Net Core с несколькими базами данных (1 на клиента)

#c# #architecture #entity-framework-core #multi-tenant #dbcontext

Вопрос:

Я унаследовал приложение .Net Framework, которое на самом деле не было разработано, но было создано как приложение портала для клиентов, но затем у каждого клиента есть своя собственная база данных для хранения своих данных по соображениям безопасности и суверенитета данных. Домашняя страница загружает основные данные из общей базы данных, но когда пользователи переходят на одну из страниц, сайту необходимо подключиться к их конкретной базе данных.

Приложение написано на C# с использованием Angular и свободно следует MVC, основной контекст передается через DI, и я только что обновил его до .Net 5. Поскольку могут существовать тысячи клиентских баз данных, которые не могут быть зарегистрированы в качестве служебных подключений при запуске, я пытаюсь найти наилучший способ обработки DbContext для этих клиентских баз данных. По-видимому, в целом он соответствует принципам многоквартирного дома, но следующие проблемы

  • Избегая повторения кода или добавления большого количества «= новый DbContext » — использование DI было бы предпочтительнее, если это возможно, с помощью перехватчика TenantFactory или базы данных
  • Убедитесь, что соединение предназначено для правильной базы данных, если у пользователя открыто несколько вкладок для разных клиентов
  • Обеспечение удаления подключения к БД при закрытии клиентской страницы или возвращении пользователя домой для просмотра другого клиента

Я понимаю, что могу создавать новый контекст БД для каждого запроса, каждый раз передавая имя БД, но есть ли шаблон или пример, который лучше подходит для этого случая использования? Что-то вроде DbCommandInterceptor на уровне БД может сработать, но опять же, если есть несколько примеров того, как это сделать, я могу их найти.

Ответ №1:

Для контекста вашего клиента убедитесь, что вы используете одну из AddDbContext перегрузок с областью optionsLifetime действия . Затем вы можете предоставить другую строку подключения для каждого экземпляра, полученную из любой другой службы с областью действия.

 services.AddDbContext<T>((sp, o) => {
    var context = sp.GetService<IHttpContextAccessor>().Context;
    o.UseSqlServer(... get the connection string here. From context.User? ...)
});
 

Ответ №2:

Самый простой, безопасный и лучший способ сделать это-именно то, что вы сказали. Создайте новый DbContext для каждого запроса, указав имя базы данных с помощью некоторого метода изоляции нескольких арендаторов.

DbContext предназначен для работы только в краткосрочной перспективе. Попытка сделать его живым дольше, чем запрос, создаст проблемы с памятью и безопасностью. НИКОГДА не создавайте статический (или одноэлементный) DbContext в многопользовательском приложении, таком как веб-сайт.

Наилучшей практикой является внедрение DbContext с жизненным циклом для каждого запроса. Это гарантирует, что DbContext будет уничтожен после завершения запроса, и вся память будет очищена.