Search
Write a publication
Pull to refresh

Comments 17

UFO landed and left these words here
  1. В статье об этом есть - использовал генераторы не заметил тормозов. Инкрементальные пока не смотрел.

  2. В статье об этом есть - хочу по доменным сущностям все сделать. При этом хочу чтобы сгенерированный код лежал где надо (в Infrastructure.Web, например. А атрибуты для аннотации в Domain.Common). Где вы тут антипаттерн нашли(и как он называется)? xD

Если что - я вот пару четыре лет назад исследовал кодогенерацию через source generator - https://habr.com/ru/articles/542300/

По итогу эта штука ужасно тормозит при малейшей навигации по файлам и глючная, зайти в отладку тяжело.

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

Можно не регистрировать обработчики изменений синтаксиса.

 context.RegisterForSyntaxNotifications(()=>new AttributeSyntaxReceiver<GenerateServiceAttribute>());

А просто вызывать генерацию (написав все нужное в Generate)

Такая генерация запускается при сборке\пересборке.

Даже 10к строк генерируется за секунды.

Зайти в отладку просто:

     public void Initialize(GeneratorInitializationContext context)
        {
#if DEBUG
            //if (!Debugger.IsAttached)
            //{
            //    Debugger.Launch();
            //}
#endif 
        }

Уберите комментарий и отлаживайте кодогенератор как и любой другой код на C#.

Было бы славно еще освоить гит и публиковать код нормально, а не архивом, загруженным в репозиторий.

Жду продолжения, был как то план сделать подобное, но руки не дошли, интересно увидеть чужой результат.

П.с. а все же сделать "правильное подключение" - генератор в клиентские проекты (в домен, аппликейшен, веб) вместо их перечисления в генераторе не выйдет?

Я себе это представляю так (не факт что это сработает):

  1. Генератор сканирует веб сборку, в ней явного ничего нет (атрибутов и т.д.), но есть референсы на другие сборки, по ним прыгает до домена

  2. В домене находит свои атрибуты (на доменных объектах)

  3. По доменным объектам генерирует что нужно для веб (контроллеры) и пишет их в код базу веб проекта.

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

Тогда все генераторы надо подключать к доменной сборке.

Хотелось хотя-бы немного по проектам разнести (чтобы в доменной сборке не падать от тысяча и одного класса).

Да и сделать не только запуск в зависимости от сборки, но и добавить очередность.

Ненене, наоборот, генераторы подключать к конечным сборкам (веб, аппликейшен), ведь они имеют доступ к домену, а не наоборот. И классы соответственно будут сгенерированы в этих сборках

Уже смотрел, да, имеют доступ к домену, все что можно получить это IAssemblySymbol.

И тут нет синтаксических деревьев.

Тогда зачем эти атрибуты на доменах. Берете Web API, подключаете к нему генератор. Даёте ссылку на проект домена. Все, дальше конвенционально парсите aggregate, entities, value objects, domain exceptions и вуаля web API готов. Т.е. комбинация проект + генератор + ссылки на проекты домена = то, как должен домен быть представлен во внешнем мире. Тот вариант: консольное приложение + генератор воркера + проект домена = проект для асинхронной обработки сообщений из домена (например для интеграции с внешними сервисами).

Если надо что-то подкорректировать (задать base url, настроить конвенции) подкидываете специальный конфиг в формате JSON (как nswag делает) ну или на C# объявляете его прямо в коде (типа как MappingGenerator), не важно.

Таким образом, когда меняется путь эндпойнта, правила парсинга (вчера передавали параметры в query string, а сегодня добавили поддержку body) и ТД, вы не трогаете домен. В конце концов какая разница бизнесу, какой у вас там путь к эндпойнту (только если конечно ваш бизнес не Apigee, но даже так можно сгенерировать management tools для управления доменом: эндпойнт для добавления эндпойнта :) )

В конце концов какая разница бизнесу, какой у вас там путь к эндпойнту (только если конечно ваш бизнес не Apigee

Apigee :)

Берете Web API, подключаете к нему генератор

Какое веб-апи?

Я объектом на едином языке в рамках домена задаю требование заказчика - конечная точка WebApi. Тут многие привыкли видеть или документ (объект), или документы и какие-то правила их валидации. Но задание просто конечной точки - тоже вполне валидный вариант (потому что это - основа проекта, и без WebApi никакого сбора данных из 100 источников не будет. И замены WebApi на шины тоже не будет).

Все остальное (DTO, код в Infrastructure и application) генерируется.

Да, задание объектом было бы логичнее, но менее удобно для статьи (мне не нужно через Web конструктор добавлять endpoint-ы, они добавляются раз в неделю\месяц. Задание Api динамически объектами - скорее всего очень много лишней писанины). Да и вообще статья о кодогенерации ).

Как я буду разделять конфигурации (какие воркеры запускать, какое API поднимать) - еще не думал. Думаю через атрибуты :).

Конфигурировать скорее всего буду стандартно через https://learn.microsoft.com/ru-ru/dotnet/core/extensions/configuration.

Классом.

Задание объектами как в Apigee было бы логичнее, но слишком муторно в плане бойлерплейта и не нужно.

Уже понятнее. В какой-то момент мы с Вами более менее синхронизировались. Далее уже надо определиться, что будет лучше - динамическая конфигурация или статика. Ответ: зависит. Но если предположить, что в Вашем кейсе статика лучше, то да, все выглядит логично. Правда это не раскрыто в статье, поэтому жёсткий диссонанс вызывает у практикующих DDD. Всё-таки обычно DDD реализуется через динамическую конфигурацию, а у вас получается нестандартный кейс. Вроде как бы да, DDD, но все инварианты это валидация. И особенность, что единственный тип контроллера это HTTP.

А так, всё-таки посмотрите на Orleans. Во-первых, обработчик данных с датчика / девайса будет "теплым", держать открытым соединения с базой, какой-нибудь кеш метаданных девайса и ТД. Во-вторых, можно стриминг данных настроить и скейлится автоматически в рамках кластера (очень удобно, когда подключаете нового нагруженного заказчика - железок пару добавили в кластер и оно само смасштабировалось ровно на столько, на сколько нужно, не нужно выделять отдельные железяки под заказчика и потом настраивать роутинг). В-третьих данные реалтайм отображать на какие-то дашбордики. Это как раз туда для IoT. Ничто не мешает сгенерировать API, которое будет использовать Grain как инфраструктурный компонент. Получится, что у вас все типа "stateless", но где надо для перфоманса "stateful".

Выражений проекта "в реальном мире" пока два - Web и консольное приложение (где воркеры будут из шины читать).

В реальном проекте - или выделю Domain.* и Generators.* в отдельный репозиторий\пакет и буду всюду подключать (или придумаю еще что-нибудь, вертикальные слайсы например). Или даже дерево доменных проектов, и контейнеры (с воркерами\webApi) в infrastructure.

В рамках цикла статей я не буду на этом акцентировать внимание.

Я, конечно, прошу пардону, как говорится, но воркеры в аппликейшен слое? Дядя Боб вами был бы явно недоволен

Action-ы не смущают в Application?

А Action-ы по расписанию?

Sign up to leave a comment.

Articles