В приложении, над которым я работаю, я использую Mediatr и его конвейеры для обработки взаимодействия с базой данных, некоторой второстепенной бизнес-логики, проверки и т. д.
Есть несколько проверок таких вещей, как контроль доступа, которые я могу обработать в конвейере, поскольку я использую объект контекста, как описано здесь https://jimmybogard.com/sharing-context-in-mediatr-pipelines/ для перехода от удостоверения ASP.Net к объекту пользовательского контекста с информацией о пользователе и утверждениями.
Одна проблема, с которой я сталкиваюсь, заключается в том, что, поскольку это приложение является мультитенантным, мне нужно убедиться, что даже если объект существует, он принадлежит этому арендатору, и единственный способ убедиться в этом — получить объект из базы данных. и проверьте это. Мне кажется, что проверка не должна иметь побочных эффектов, поэтому я не хочу полагаться на это для заполнения объекта контекста. Но затем это приводит к тому, что обработчикам Mediatr приходится выполнять множество проверок, поскольку они проверяют существование объекта и так далее, что приводит к большому количеству повторяющегося кода. Я действительно не хочу запрашивать базу данных несколько раз, поскольку некоторые запросы могут быть дорогими.
Еще одна проблема, связанная с более сложной проверкой в реальных обработчиках запросов, заключается в возврате того, что, по сути, является ошибкой проверки. В настоящее время, если одна из этих проверок терпит неудачу, я бросаю ValidationException
, который затем перехватывается промежуточным программным обеспечением и превращается в ProblemDetails
, который возвращается вызывающей стороне API. Это в основном исключения, такие как управление потоком, и сбой проверки в любом случае не является «исключительным».
У меня есть мысли о том, как решить эту проблему:
Где-то в конвейере, когда я создаю контекст, включите попытку извлечения необходимых объектов из базы данных. Затем проверка завершается неудачей, если какой-либо из них равен нулю. Похоже, это усложнит тестирование, а также потребует как-то декорировать запросы (или использовать отражение), чтобы конвейер мог знать, что нужно попытаться загрузить эти объекты.
Имейте запросы в валидаторе, но используйте какой-то репозиторий с поддержкой кеша, поэтому, когда тот же объект запрашивается позже, он обслуживается из кеша, а не из базы данных. Обработчики также будут использовать этот репозиторий с поддержкой кэша (в настоящее время обработчики напрямую взаимодействуют с EF Core DbContext для запросов). Затем это добавляет проблему аннулирования кеша, которую мне все равно придется обрабатывать в какой-то момент (довольно много элементов редко изменяются). Для тестирования можно внедрить фиктивный объект кэша, который на самом деле ничего не кэширует.
Сделайте так, чтобы все ответы на запросы реализовывали интерфейс (или расширяли абстрактный класс), который имеет информацию о проверке, общие флаги успеха и т. д. Это может быть либо возвращено через API напрямую, либо иметь некоторый конвейер, который преобразует сбои в
ProblemDetails
. Это добавит некоторый шаблон к каждому ответу и обработчику, но позволит избежать исключений, таких как управление потоком, и проблем с кэшированием/отражением в других параметрах.
Предположим для 1 и 2, что любые условия гонки не являются проблемой. Объекты не меняют владельцев, и данные редко удаляются из базы данных в целях аудита/бухгалтерского учета.
Я знаю, что не существует универсального решения для подобных проблем, но я хотел бы знать, есть ли дополнительные параметры, которые мне не хватает, или какие-либо проблемы с долгосрочной ремонтопригодностью, с которыми сталкивался любой, у кого есть аналогичный конвейер, если они использовали один из перечисленных опции.