Перейти к основному содержимому

Вызовы сервисов

Библиотека ASE.MD.Platform.Utils.ApiClient инкапсулирует следующие аспекты взаимодействия между сервисами:

  • обнаружение сервисов;
  • аутентификация;
  • обработка ошибок и повторные попытки вызова.

Эта статья описывает, как предоставить API разрабатываемого сервиса другим сервисам, а также как запросить API другого сервиса.

Вызываемая сторона: подготовка API сервиса для вызова

Предположим, что вызываемый сервис имеет имя Xyz.

Чтобы подготовить сервис Xyz для вызова другим сервисом:

  1. Объявите сервис с помощью атрибута Discovery.

    Атрибут [assembly: Discovery] в файле Startup.cs или Program.cs сообщает Атомкод о существовании сервиса Xyz, его имени и версиях.

    Следующий блок кода демонстрирует объявление сервиса с именем xyzservice, версией API 3.2.1 и версией реализации 1.0.

    [assembly: Discovery("xyzservice", "3.2.1", "1.0")]
  2. Создайте интерфейс сервиса.

    Интерфейс определяет контракт разрабатываемого API. Именно на интерфейс будет ориентироваться ApiClient на вызывающей стороне. Атрибут [ServiceName] связывает интерфейс с разрабатываемым сервисом.

    Вам потребуется добавить ссылку на пакет NuGet, содержащий модели API, например, ASE.MD.Platform.Infrastructure.Xyz.ApiContracts.

    Следующий блок кода демонстрирует создание интерфейса IXyzIdentityServiceAsync. Атрибут [ServiceName] указывает, что этот интерфейс представляет API сервиса xyzservice версии 3.2.1. Методы интерфейса должны соответствовать методам разрабатываемого контроллера.

    // Директивы using необходимы для работы с определенными моделями данных сервиса Xyz.
    // Директивы доступны после подключения пакета NuGet, содержащего модели данных и контракты сервиса Xyz, например, ASE.MD.Platform.Infrastructure.Xyz.ApiContracts.
    using ASE.MD.Platform.Infrastructure.Xyz.ApiResults.Identity;
    using ASE.MD.Platform.Utils.ApiClient.Models.Attributes;
    using System.Threading.Tasks;

    [ServiceName("xyzservice", "3.2.1")]
    public interface IXyzIdentityServiceAsync
    {
    Task<UserListApiResult> GetAllUsersSystem();
    }
  3. Реализуйте интерфейс в контроллере.

    Разрабатываемый контроллер должен не только наследоваться от ControllerBase, но и реализовывать созданный интерфейс. Такой подход гарантирует, что контракт, объявленный в интерфейсе, точно соответствует реализации.

    Следующий блок кода демонстрирует, как контроллер XyzController реализует интерфейс IXyzIdentityServiceAsync. Метод использует следующие атрибуты:

    • [HttpPost] указывает, что метод обрабатывает POST-запросы;
    • [ScopeRequirement("xyz:users:read")] обеспечивает проверку прав доступа, требуя у вызывающей стороны наличие разрешения xyz:users:read.
    public class XyzController : ControllerBase, IXyzIdentityServiceAsync // Наследование от интерфейса
    {
    [HttpPost]
    [ScopeRequirement("xyz:users:read")] // Требуемое разрешение
    public Task<UserListApiResult> GetAllUsersSystem()
    {
    // ... ваша бизнес-логика ...
    var users = _userRepository.GetAll();
    return Task.FromResult(new UserListApiResult(users));
    }
    }

В результате разрабатываемый сервис регистрируется в Атомкод и предоставляет строго типизированный контракт (интерфейс), который другие сервисы могут использовать.

Вызывающая сторона: вызов API другого сервиса

Предположим, что вызывающий сервис имеет имя Abc.

Чтобы вызвать API другого сервиса:

  1. Добавьте ссылку на интерфейс сервиса.

    Чтобы вызвать сервис Xyz, вам нужен доступ к его интерфейсу IXyzIdentityServiceAsync. В проект сервиса Abc необходимо добавить ссылку на пакеты NuGet, которые предоставляет сервис Xyz.

    В проект сервиса Abc необходимо добавить следующие пакеты:

    • Пакет с контрактами сервиса Xyz, например, ASE.MD.Platform.Infrastructure.Xyz.ApiContracts. Пакет предоставляет интерфейс IXyzServiceAsync и модели данных, например, UserListApiResult.
    • Пакет ASE.MD.Platform.Utils.ApiClient. Пакет предоставляет базовую функциональность клиента.

    Код в файле, например, Controllers/AbcController.cs, где будет использоваться клиент, должен включать соответствующие директивы.

    Следующий блок кода демонстрирует подключение пространств имен в коде сервиса Abc. Первые две строки предназначены для работы с ApiClient, третья предназначена для использования контракта и моделей сервиса Xyz.

    // Код в проекте Abc
    // Эти директивы необходимы для работы с библиотекой ApiClient
    using ASE.MD.Platform.Utils.ApiClient.Interfaces;
    using ASE.MD.Platform.Utils.ApiClient.Extensions;

    // Эта директива необходима для использования контракта IXyzServiceAsync
    // Она станет доступна после подключения пакета NuGet сервиса Xyz
    using ASE.MD.Platform.Infrastructure.Xyz.ApiContracts;

    namespace AbcService.Controllers
    {
    public class AbcController : ControllerBase
    {
    ...
    }
    }
  2. Зарегистрируйте клиента в контейнере зависимостей.

    В методе ConfigureServices вашего Startup.cs или Program.cs зарегистрируйте клиента для нужного интерфейса.

    Следующий блок кода демонстрирует регистрацию клиента для интерфейса IXyzIdentityServiceAsync в контейнере зависимостей Abc. Метод AddWebApiDirectClient реализует настройку HTTP-клиента, сериализации и аутентификации.

    // Код в проекте Abc
    using ASE.MD.Platform.Utils.ApiClient.Extensions;

    public void ConfigureServices(IServiceCollection services)
    {
    // Сервис Abc регистрирует клиента для вызова сервиса Xyz
    services.AddWebApiDirectClient<IXyzServiceAsync>(Configuration);
    }
  3. Внедрите и используйте клиента в разрабатываемом коде.

    Теперь сервис Abc может внедрить клиента и вызывать методы сервиса Xyz так, как если бы это был локальный объект.

    Следующий блок кода демонстрирует внедрение клиента и его использование для вызова метода GetAllUsersSystem. Библиотека ApiClient автоматически выполняет поиск сервиса xyzservice, получение токена с нужной областью разрешения доступа и обработку HTTP-запросов.

    // Код в проекте Abc
    public class AbcController : ControllerBase
    {
    // Сервис Abc внедряет клиента для сервиса Xyz
    private readonly IWebApiDirectClient<IXyzServiceAsync> _xyzServiceClient;

    public AbcController(IWebApiDirectClient<IXyzServiceAsync> xyzServiceClient)
    {
    _xyzServiceClient = xyzServiceClient;
    }

    public async Task<IActionResult> GetDataFromXyz()
    {
    // Сервис Abc вызывает метод сервиса Xyz
    // ApiClient автоматически находит "xyzservice", получает токен и обрабатывает запрос
    UserListApiResult result = await _xyzServiceClient.Proxy.GetAllUsersSystem();

    // ... дальнейшая обработка результата в сервисе Abc ...
    return Ok(result);
    }
    }

Настройка аутентификации в appsettings.json

Для работы клиента необходима конфигурация. ApiClient поддерживает несколько схем аутентификации. Наиболее рекомендуемой и безопасной является Client Credentials (сервис-сервисная аутентификация без участия пользователя).

Следующий блок кода демонстрирует пример конфигурации для аутентификации по схеме Client Credentials. Секция ClientSelector определяет, какой ClientId использовать для вызова определенного сервиса, а ClientSecrets хранит секреты для этих клиентов.

{
"ApiConfiguration": {
"IdentityProvider": "local",
"ClientSelector": [
{
"TargetServiceName": "IXyzIdentityServiceAsync", // Для вызова Xyz сервиса
"ClientId": "client-for-xyz" // Используется этот клиент
}
],
"ClientSecrets": [
{
"ClientId": "client-for-xyz", // Секрет для клиента 'client-for-xyz'
"Secret": "secret1"
}
]
}
}