September 13, 2020

Реализация сервиса корзины CartService

Выбор применяемых технологий

  • WEB API ASP.NET CORE
  • ORM Entity Framework (подключен Dapper для ReadOnly операций p.s. не до конца реализован)
  • Local db (MSSQL)
  • xUnit (unit-тестирование, интеграционное)
  • IronPdf (конвертация в pdf)
  • AutoMapper
  • Hangfire (background jobs)
  • Swagger

Архитектура

Было принято решение следовать классической clean архитектуре, придерживаться REST-стиля API.

Также стоит отметить, что некоторые модули могут иметь High coupling, но я старался придерживаться solid

p.s. не использовал Docker

Проект состоит из 4 проектов.

  • CartTest.Data
  • CartTest.IntegrationTesting
  • CartTest.Service
  • CartTest.WebAPI

В проекте CartTest.Data созданы сущности + репозитории для Dapper и EntityFramework

Сущности - Product, CartItem, Cart, Report, WebHook (по-хорошему, сделать связи через fluent api)

Реализован отдельный Readonly репозиторий (asNoTracking).

Dapper реализует IRepository (принимает generic методы). Подключение к базе через инъекцию IDatabaseConnectionFactory

На будущее - есть мысли реализовать UOW/Repository как стандартный вариант или CQS команды для подключения Dapper.

CartTest.Service создан для описания кейсов, взаимодействия с нижнем уровнем Data, описания DTO-объектов и основной бизнес-логики

Создан профиль для маппинга моделей в DTO.

На будущее - определен класс OperationResult для обработки операций и избегания try/catch. Необходимо обернуть большинство методов и обработку разных кейсов

CartTest.WebAPI api методы, также зарегистрированы сервисы/DI.

Hangfire запускает раз в сутки отчет GenerationPdf()

Был использован AnonymousId middleware для идентификации анонимного неавторизованного пользователя посредством cookie

Подводный камень - если зарегистрированный пользователь набрал себе корзину как аноним и потом входит в аккаунт. Надо будет реализовать отдельное решение

По поводу веб-хуков и выполнения background-задачи

Для пользователя определен API для регистрации веб-хука (логику подписки можно будет менять)

Определен класс для планировщика DeleteCartOnExpirationJob, который выполняется по cron'у раз в сутки.

Он проверяет одним запросом просроченные корзины, если такие есть, планировщик удаляет их из базы

Далее проверяем есть ли подписанные вебхуки, берем callbackUrl,затем запускаем метод ExecuteJobAsync клиента IWebHookClient по каждому хуку и передаем callbackUrl

ExecuteJobAsync вызывает post запрос HttpClient'а, который честно стучится по retry 3 раза, добавляем обработку в TryHandler (+ отмена операции CancellationToken)