Пишу дипломный проект веб-сервиса на .net core. Пытаюсь выстроить масштабируемую архитектуру.
На данный момент в проекте есть единая база данных на orm EntityFramework, обернутая в репозитории, и веб-апи с полным доступом ко всем репозиториям. Есть библиотека DAl.Client, которая оборачивает логику http запросов к апи и предполагается для использования в других сервисах.
Таким образом структура сервиса базы данных выглядит следующим образом:
- DAL - проект с контекстом и репозиториями
- DAL.Entities - проект с сущностями, чтобы другие микросервисы не тянули контекст и репозитории
- DAL.SqlServer - проект для миграций
- DAL.API - Апи с контроллерами
- DAL.Client - Проект в веб-репозиториями, общающийся с апи
Репозиторий базы данных и веб-репозиторий реализуют один общий generic интерфейс, который декларирует основные crud операции над указанной сущностью. Только бд репозиторий общается с ef core, а веб-репозиторий с DAL.API.
И есть несколько других микросервисов, использующих базу данных. Я использую внедрение зависимостей для получения нужных мне сервисов в конструкторе классов. Было очень удобно регистрировать веб-репозиторий следующим образом:
builder.Services.AddHttpClient<IRepository<CloudResource>, WebRepository<CloudResource>>
(configureClient:
client => { client.BaseAddress = new Uri($"{builder.Configuration["DatabaseAPI"]}/Resource/"); });
А затем так же удобно получать его в сервисе:
public CloudService(IRepository<CloudResource> repository)
{
_repository = repository;
}
При разработке этого проекта я следовал
видеоуроку Павла Шмачилина. Как я понял, такая структура обеспечила полную независимость domain сервисов, потому что они принимают интерфейсы, а реализация настраивается в конфигурации внедрения зависимостей. И мне это показалось правильным. Таким же образом я реализовал сервис облачного хранилища и сервис отправки email сообщений. Благодаря интерфейсам, я могу легко подменить поставщика облачного хранилища в файле Program.cs в своем domain сервисе:
builder.Services.AddHttpClient<ICloud, YandexCloudProvider>();
Моя проблема состоит в том, что мне нужны репозитории бд с дополнительными операциями по выборке из навигационных свойств или сортировке. И я создавал такие репозитории, наследовал их от generic и расширял. Но, чтобы пользоваться расширенной логикой, в моем domain service в конструкторе надо запросить именно этот класс, а не интерфейс, тк он не декларирует расширяемую логику. Таким образом я нарушаю принцип слабой связанности и единственное решение, которое я вижу - это создать интерфейс для такого репозитория по типу IExtendedUserRepository.
Но мне нужно реально много таких репозиториев, неужели правильным решением будет создавать под каждый репозиторий интерфейс в проекте с интерфейсами?
Тот же вопрос относится к взаимодействию ui и domain сервисов. Допустим у меня есть AuthService, RegisterService, CloudService и т.д. Неужели для того, чтобы независимо их использовать в ui надо под каждый сервис создать интерфейс? А как быть с DTO, которые предоставляют эти сервисы? Нужно создавать их копии в клиентском проекте, чтобы избежать связанности?
Допускаю, что делаю всё совсем не так. Посоветуйте, пожалуйста, где можно почитать про это. Где можно посмотреть на пример веб-сервиса с хорошей архитектурой. Обычно я нахожу какие-то поверхностные объяснения и структуры, которые подвергаются критике в комментарии, но никто не объясняет как действительно нужно сделать. Заранее спасибо!