Какие способы взаимодействия между сервисами используются: REST или другие интеграции?
Что проверяют
Понимаете ли вы, когда сервису нужен ответ сразу, а когда достаточно гарантии доставки, и умеете ли сделать это надёжно в .NET. Следом почти всегда спрашивают, как вы создаёте HttpClient и что происходит при отказе соседнего сервиса.
Как отвечать
Разделите взаимодействие на синхронное и асинхронное:
- REST поверх HTTP: ASP.NET Core с контроллерами или Minimal API, контракт в OpenAPI. Клиент это
HttpClientчерезIHttpClientFactory, типизированные клиенты или Refit для декларативного описания; - gRPC:
Grpc.AspNetCoreиGrpc.Net.Client, контракт в.proto, классы генерируются при сборке. HTTP/2, строгая типизация, стриминг. Хорош между внутренними сервисами; - SOAP: живёт в интеграциях со старыми системами. Серверная часть WCF в современный .NET не перенесена, для этого есть CoreWCF;
- брокеры сообщений: RabbitMQ, Kafka, Azure Service Bus через клиентские библиотеки или MassTransit. Отправитель не ждёт получателя, сбой одного сервиса не валит цепочку.
REST это архитектурный стиль поверх HTTP, а не протокол. Выбор: синхронно, когда ответ нужен для продолжения запроса; асинхронно, когда важна гарантия обработки и развязка сервисов.
Про надёжность: с .NET 8 есть пакет Microsoft.Extensions.Http.Resilience, где AddStandardResilienceHandler() вешает на клиент таймауты, повторы и circuit breaker поверх Polly. Для событий нужен идемпотентный обработчик, потому что брокеры обычно доставляют «хотя бы один раз», и Transactional Outbox, чтобы сохранение в базе и публикация не разъехались. В MassTransit outbox есть готовый, с EF Core.
Где спотыкаются
Создают new HttpClient() на каждый запрос. Под нагрузкой это исчерпание сокетов, а один статический клиент на всё приложение не замечает смену DNS. Правильный путь это IHttpClientFactory.
Утверждают, что SOAP безопаснее REST или нужен ради транзакций. Безопасность дают TLS и токены, а распределённые транзакции через WS-стандарты в современных системах почти не встречаются.
Вызывают .Result или .Wait() на асинхронном HTTP-вызове. Потоки пула блокируются, а в окружении с контекстом синхронизации, как в старом ASP.NET или WinForms, это прямой дедлок.