Документация
Библиотека Ascon.Polynom.Web.Api.Client
Клиентская библиотека .NET для Web API v1 ПОЛИНОМ:MDM. Содержит модели, интерфейсы, перечисления, JSON-настройки, сервисы вызова методов API и инфраструктуру авторизации (JWT: вход/выход/обновление токена).
1. Состав библиотеки
| Папка / файл | Содержимое |
|---|---|
Models/ |
Классы-модели запросов и ответов API |
Interfaces/ |
Интерфейсы моделей (ISignInRequest, ISearchRequest, IDocument, IPaginatedList<T> и др.) |
Enums/ |
Перечисления (FilterType, AccessRights, PropertyType, TicketStatus и др.) |
Services/ |
Клиенты методов API (DocumentApiClient, SearchApiClient, LoginApiClient и др.) |
Json/ |
PolynomJsonOptions, PolymorphicTypeResolver и конвертеры (OptionalConverter, DateTimeConverter) |
Auth/ |
Инфраструктура JWT-авторизации: AuthorizationService, AuthorizationMessageHandler, хранилища токенов, PolynomApiClientOptions |
Optional<T> |
Структура для «частично заданных» значений |
PolynomApiClientFactory |
Фабрика клиентов для использования без DI |
AddPolynomApiClient |
Расширение для регистрации клиентов в DI |
2. Установка
Библиотека распространяется как NuGet-пакет Ascon.Polynom.Web.Api.Client.
Требуется .NET SDK 8.0+.
2.1. Установка из локальной папки дистрибутива
Пакет поставляется как файл .nupkg в папке дистрибутива. Установка выполняется в кеш
пакетов пользователя по умолчанию — создавать или править nuget.config не нужно:
dotnet add package Ascon.Polynom.Web.Api.Client --source C:\Distr\polynom-web\nuget
Укажите вместо C:\Distr\polynom-web\nuget путь к папке, в которой лежит .nupkg.
2.2. Куда попадает пакет
- Кеш пакетов по умолчанию:
%userprofile%\.nuget\packages(Windows),~/.nuget/packages(Linux/macOS). - Пакет полностью распаковывается в
<кеш>\ascon.polynom.web.api.client\<версия>\; рядом сохраняется копия исходного.nupkg. - В папку проекта содержимое пакета не копируется — проект ссылается на пакет из кеша.
- Источник (
--source) нужен только при первой установке: последующиеdotnet restoreберут пакет из кеша.
Проверить расположение кеша:
dotnet nuget locals global-packages --list
2.3. Ссылка на пакет
Команда dotnet add package добавляет в файл проекта ссылку на пакет:
<ItemGroup>
<PackageReference Include="Ascon.Polynom.Web.Api.Client" />
</ItemGroup>
При необходимости версия фиксируется атрибутом Version:
<PackageReference Include="Ascon.Polynom.Web.Api.Client" Version="24.1.0.*" />
2.4. Дополнительное требование
Для работы с токенами (PersistTokens) требуется Microsoft.AspNetCore.DataProtection.
В приложениях ASP.NET Core он доступен через FrameworkReference Microsoft.AspNetCore.App,
который подключается автоматически при использовании пакета.
3. Быстрый старт: регистрация через DI
using Ascon.Polynom.Web.Api.Client;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddPolynomApiClient(options =>
{
options.BaseAddress = new Uri("https://polynom-mdm.local:5100");
options.SsoUrl = "https://sso.local";
options.PersistTokens = true;
options.TokenStoragePath = Path.Combine(AppContext.BaseDirectory, "tokens.protected");
options.AutoRefreshToken = true;
options.RefreshOnUnauthorized = true;
});
var app = builder.Build();
AddPolynomApiClient регистрирует:
AuthorizationService(singleton) — управление авторизацией;ITokenRefresher,ILoginApiClientFactory,ITokenStorage,ITokenProtector;- именованный
HttpClient(имя по умолчанию —PolynomApiClient) сAuthorizationMessageHandler; - все клиенты из
Services/(DocumentApiClient,SearchApiClientи т.д.) как transient.
Использование сервисов
using Ascon.Polynom.Web.Api.Client.Enums;
using Ascon.Polynom.Web.Api.Client.Models;
using Ascon.Polynom.Web.Api.Client.Services;
using Ascon.Polynom.Web.Api.Client.Auth;
app.MapPost("/search", async (
AuthorizationService authorization,
SearchApiClient search,
CancellationToken cancellationToken) =>
{
// Вход по логину и паролю (токен сохраняется и автоматически продлевается).
if (!authorization.IsAuthenticated)
{
await authorization.SignInAsync(
new SignInRequest
{
Login = "user",
Password = "password",
},
cancellationToken);
}
var page = await search.ExecuteSearch(
new SearchRequest
{
ObjectTypeFilter = FilterType.All,
SearchText = "насос",
PageNumber = 1,
PageSize = 50,
},
cancellationToken);
return Results.Ok(page?.Items);
});
4. Быстрый старт: без DI (фабрика)
Для консольных утилит и сценариев без IServiceCollection используйте PolynomApiClientFactory.
using Ascon.Polynom.Web.Api.Client;
using Ascon.Polynom.Web.Api.Client.Auth;
using Ascon.Polynom.Web.Api.Client.Enums;
using Ascon.Polynom.Web.Api.Client.Models;
// Протектор токенов на базе ASP.NET Data Protection (ключи — в файловом каталоге).
var protector = TokenProtectorFactory.CreateDataProtection(@"C:\ProgramData\Ascon\Keys");
using var factory = new PolynomApiClientFactory(
new PolynomApiClientOptions
{
BaseAddress = new Uri("https://polynom-mdm.local:5100"),
PersistTokens = true,
TokenStoragePath = @"C:\ProgramData\Ascon\tokens.protected",
},
protector);
await factory.Authorization.SignInAsync(new SignInRequest
{
Login = "user",
Password = "password",
});
var search = factory.CreateSearchApiClient();
var page = await search.ExecuteSearch(new SearchRequest
{
ObjectTypeFilter = FilterType.All,
SearchText = "насос",
});
foreach (var item in page?.Items ?? [])
{
Console.WriteLine(item);
}
Dispose()фабрики освобождаетAuthorizationServiceи HTTP-обработчик. Для каждого клиента фабрика создаёт отдельныйHttpClientс одним общимAuthorizationMessageHandler, поэтому токен подставляется автоматически.
5. Авторизация
Управление сессией выполняет AuthorizationService.
| Элемент | Назначение |
|---|---|
IsAuthenticated |
Признак наличия действующего access-токена |
SignInAsync(ISignInRequest, ...) |
Вход по логину и паролю |
SignInBySystemAsync(ISignInBySystemRequest, ...) |
Системный вход |
SignInByAccessTokenAsync(accessToken, ISignInRequest, tokenFromSso, ...) |
Вход по готовому access-токену (в т.ч. из SSO) |
UpdateTokenAsync(...) |
Обновление пары токенов по refresh-токену |
SignOutAsync(...) |
Выход из сессии (и из SSO, если настроено) |
SignOutSsoAsync(...) |
Выход только из системы единой авторизации |
SetSsoUrl(string?) |
Переопределение адреса SSO |
AuthenticationStateChanged |
Событие EventHandler<bool>: изменилось состояние авторизации |
SignedOut |
Событие EventHandler: выход выполнен |
authorization.AuthenticationStateChanged += (_, isAuthenticated) =>
{
Console.WriteLine($"Авторизован: {isAuthenticated}");
};
authorization.SignedOut += (_, _) => Console.WriteLine("Сессия закрыта.");
await authorization.SignInByAccessTokenAsync(
accessToken,
new SignInRequest
{
Login = "user",
Password = "password",
},
tokenFromSso: true);
AuthorizationMessageHandler автоматически добавляет заголовок Authorization: Bearer <token>
и при ответе 401 (если RefreshOnUnauthorized = true) однократно обновляет токен и повторяет запрос.
Дополнительно AuthorizationService реализует IAsyncDisposable — обязательно освобождайте его
(в DI это делает контейнер, при ручном создании — фабрика).
6. Параметры клиента
Все параметры задаются через PolynomApiClientOptions.
| Свойство | Тип | По умолчанию | Описание |
|---|---|---|---|
BaseAddress |
Uri? |
— | Базовый адрес Web API. Обязателен |
SsoUrl |
string? |
— | Адрес сервера SSO для выхода из единой сессии |
ClientName |
string |
"PolynomApiClient" |
Имя именованного HttpClient |
RefreshTokenBeforeExpiry |
TimeSpan |
2 минуты | За сколько до истечения продлевать токен |
AutoRefreshToken |
bool |
true |
Автопродление токена по таймеру |
RefreshOnUnauthorized |
bool |
true |
Обновлять токен и повторять запрос при ответе 401 |
ProtectTokensInMemory |
bool |
true |
Шифрование токенов в памяти |
PersistTokens |
bool |
false |
Сохранять токены между запусками |
TokenStoragePath |
string? |
— | Путь к файлу токенов. Обязателен при PersistTokens = true |
7. Работа с сервисами API
Каждый сервис — отдельный класс в Services/, соответствующий контроллеру Web API.
Методы возвращают Task<T?> и принимают CancellationToken.
| Сервис | Назначение |
|---|---|
LoginApiClient |
Авторизация, текущий пользователь/хранилище, обновление токена |
DocumentApiClient |
Создание, удаление, чтение документов |
ElementApiClient |
Работа с элементами |
SearchApiClient |
Поиск: ExecuteSearch, ExecutePropertySearch, поиск заявок |
PropertyApiClient |
Значения свойств |
BackgroundTaskApiClient |
Фоновые задачи |
TicketApiClient |
Заявки |
Постраничный результат (ExecuteSearch) — это IPaginatedList<T>
со свойством Items: List<T> и данными о странице.
// groupId — идентификатор группы документов.
var documents = await documentClient.GetByDocumentGroup(
new IdentifierRequest { ObjectId = groupId },
cancellationToken);
8. Optional
Структура Optional<T> различает «значение не задано» и «явно задано null».
Используется в запросах частичного обновления, где важно передать только изменяемые поля.
using Ascon.Polynom.Web.Api.Client;
// Явно заданное значение.
Optional<int> pageSize = 50;
// Пустое (незаданное) значение.
var description = default(Optional<string>);
Optional<string> noValue = (string?)null;
if (pageSize.HasValue)
{
Console.WriteLine(pageSize.Value); // 50
}
Console.WriteLine(description); // "unspecified"
Console.WriteLine(noValue); // "unspecified"
| Элемент | Описание |
|---|---|
HasValue |
true, если значение задано |
Value |
Хранимое значение (T?) |
implicit operator Optional<T>(T value) |
Неявное преобразование из T |
ToString() |
Значение, "null" или "unspecified" |
9. JSON и полиморфизм
Все клиенты сериализуют и десериализуют данные через единые настройки
PolynomJsonOptions.Options:
- camelCase-имена, регистронезависимый разбор, пропуск
null; - конвертеры
OptionalConverterиDateTimeConverter; PolymorphicTypeResolverсоздаёт экземпляр конкретного типа при десериализации интерфейсов (ISignInRequest,ISearchRequest,IPaginatedList<T>и др.) по атрибуту[JsonDerivedType(...)].
Свои настройки можно получить через PolynomJsonOptions.GetJsonSerializerOptions()
или применить к существующим: options.SetJsonSerializerOptions().
using System.Text.Json;
using Ascon.Polynom.Web.Api.Client.Json;
var json = JsonSerializer.Serialize(request, PolynomJsonOptions.Options);
var restored = JsonSerializer.Deserialize<ISearchRequest>(json, PolynomJsonOptions.Options);
10. Обработка ошибок
Методы API вызывают HttpResponseMessage.EnsureSuccessStatusCode(), поэтому при неуспешном
HTTP-ответе выбрасывается System.Net.Http.HttpRequestException со статус-кодом в StatusCode.
using System.Net;
using System.Net.Http;
try
{
var page = await search.ExecuteSearch(request, cancellationToken);
return page?.Items ?? [];
}
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
// Сессия истекла и не была продлена — требуется повторный вход.
await authorization.SignInAsync(signInRequest, cancellationToken);
throw;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Ошибка запроса: {ex.StatusCode} — {ex.Message}");
throw;
}