Перейти к содержанию

Создание веб-приложения ASP.NET Core, использующего API TESSA

Создание веб-приложения ASP.NET Core, использующего API TESSA

В этом примере мы рассмотрим создание независимого веб-приложения ASP.NET Core, которое может использоваться для обработки REST-запросов и вывода статических или динамических сайтов. Подход, описанный в этом разделе, может задействоваться для разработки кастомизированного веб-клиента или веб-приложения для мобильных устройств.

Откройте Visual Studio проектного решения Source\Tessa.Extensions.sln. Создайте папку Services в контекстном меню Solution Explorer. Далее создайте проект ASP.NET Core Empty через контекстное меню в папке, который поместите в подпапку Source\Services, указав путь в поле Location.

Откройте Visual Studio и создайте проект ASP.NET Core Web Application.

Укажите реализацию для .NET 5.0.

Откройте для редактирования файл проекта .csproj и замените его содержимое таким образом:

<Project Sdk="Microsoft.NET.Sdk.Web">

<Import Project="$(ProjectDir)../../Tessa.targets" /> <Import Project="$(ProjectDir)../../Tessa.Extensions.targets" /> <Import Project="$(ProjectDir)../../Tessa.Runtime.targets" />

<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net5.0</TargetFramework> <RestoreSources>$(RestoreSources);../../Bin/packages;https://api.nuget.org/v3/index.json</RestoreSources> <NoWarn>$(NoWarn);1591</NoWarn> <GenerateDocumentationFile>true</GenerateDocumentationFile> <LangVersion>9</LangVersion> </PropertyGroup>

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'win-x64'"> <PublishReadyToRun>true</PublishReadyToRun> </PropertyGroup>

<ItemGroup> <Content Update="app.json" CopyToOutputDirectory="PreserveNewest" /> <Content Update="extensions.xml" CopyToOutputDirectory="PreserveNewest" /> <Content Update="NLog.config" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup>

</Project>

Перейдите в диалог выбора NuGet-пакетов, для этого в контекстном меню на узле Solution '...' в панели инструментов Solution Explorer выберите пункт Manage NuGet Packages.

Перейдите на вкладку Browse и последовательно установите пакеты Tessa.Linux, Tessa.Server (в сборке 3.4.0 или ранее назывался Tessa.Compilation), Tessa.PostgreSql и Tessa.Web, выбрав версию пакета, соответствующую версии вашей сборки TESSA. Например, для версии сборки TESSA 3.6.0 с патчем 1 укажите версию пакетов также 3.6.0.1. Не обновляйте пакеты до более новых версий до того, как будет обновлена инсталляция всей платформы (вместе с конфигурацией, базой данных и расширениями).

Note

Для логирования ошибок ASP.NET Core, возникающих в запросах, не связанных с TESSA и её расширениями, таких как Swagger, добавьте NuGet-пакет NLog.Web.AspNetCore актуальной версии. Это требуется для использования метода .UseNLog() в коде ниже.

В файле Program.cs в методе Main добавьте вызовы методов инициализации перед тем, как будет вызван метод CreateWebHostBuilder().

using System; using System.Linq; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NLog; using NLog.Web; using Tessa.Platform; using Tessa.Web; using LogLevel = NLog.LogLevel;

namespace TessaWebApp { public class Program { public static async Task Main(string[] args) { try { try { await TessaPlatform.InitializeFromConfigurationAsync(); await WebHelper.InitializeWebServerAsync(); } catch (OperationCanceledException) { return; } catch (Exception ex) { TessaLoggers.ServiceHost.LogException("Service host failed to initialize", ex, LogLevel.Fatal); throw; }

try { await CreateHostBuilder(args).Build().RunAsync(); } catch (OperationCanceledException) { // ignored } catch (Exception ex) { TessaLoggers.ServiceHost.LogException("Service host has stopped with critical exception", ex, LogLevel.Fatal); throw; } } finally { LogManager.Shutdown(); } }

public static IHostBuilder CreateHostBuilder(string[] args) { WebHelper.ParseUrlsFromCommandLine(ref args, out string[] urls, out string[] sockets); WebListenEndPoint[] endPoints = urls.Select(WebHelper.ParseUrlToEndPoint).ToArray();

return Host.CreateDefaultBuilder(args) .UseNLog() .ConfigureWebHostDefaults( webBuilder => { webBuilder .ConfigureKestrel(options => { options.AddServerHeader = false;

var environment = options.ApplicationServices.GetRequiredService<IWebHostEnvironment>(); var logger = options.ApplicationServices.GetRequiredService<ILogger<IWebHostBuilder>>();

var serverLimits = options.ApplicationServices.GetRequiredService<IOptions<WebServerLimits>>().Value; serverLimits.Apply(options.Limits);

var serverOptions = options.ApplicationServices.GetRequiredService<IOptions<WebServerOptions>>().Value; X509Certificate2 httpsCertificate = endPoints.Any(x => x.Protocol == WebHelper.HttpsProtocol) ? WebHelper.LoadCertificate(serverOptions, environment.IsDevelopment()) : null;

TessaLoggers.ServiceHost.Info("Web server Options: {0}", serverOptions); TessaLoggers.ServiceHost.Info("Web server Limits: {0}", serverLimits);

if (serverOptions.EnforceTls12) { options.ConfigureHttpsDefaults(listenOptions => listenOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13); }

EndPointsResult endPointsResult = options.UseEndPoints(endPoints, serverOptions, httpsCertificate, logger); if (!endPointsResult.HasHttps) { serverOptions.HttpsRedirect = HttpsRedirectMode.Disabled; }

if (OperatingSystem.IsLinux()) { options.UseSystemd();

foreach (string socket in sockets) { options.ListenUnixSocket(socket); }

if (sockets.Length > 0) { endPointsResult = new EndPointsResult(true); } }

if (!endPointsResult.HasAny) { const string message = "Kestrel has no endpoints to listen to. Check https certificate availability."; logger.LogCritical(message); throw new InvalidOperationException(message); } });

webBuilder .UseTessaConfiguration(args) .UseStartup<Startup>(); }); } } }

В файле Startup.cs выполните конфигурацию сервисов TESSA в методе ConfigureServices и конфигурацию приложения в методе Configure.

using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Tessa.Platform.Runtime; using Tessa.Web; using Tessa.Web.Services; using Unchase.Swashbuckle.AspNetCore.Extensions.Extensions;

namespace TessaWebApp { public class Startup : WebStartupBase { public Startup(IWebHostEnvironment hostEnvironment) : base(hostEnvironment) { }

public void ConfigureServices(IServiceCollection services) { services .AddTessaServices() .AddTessaResponseCompression() .AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_3_0) .ConfigureTessaMvc();

// если используем проверку работоспособности сервиса (health checks) services .AddHttpClient() .AddOptions() .AddTessaHealthChecks() .ConfigureWebOptions();

// если используем Swagger для документирования REST-методов if (RuntimeHelper.SwaggerDocIsEnabled) { services .AddSwaggerGen(c => { c.SwaggerDocForTessa("My REST API", "My API Description");

// указываем одну или несколько сборок, в которых присутствуют описываемые контроллеры c.IncludeXmlComments(Assembly.GetExecutingAssembly(), includeControllerXmlComments: true);

c.IncludeXmlCommentsFromInheritDocs(); c.UseAllOfToExtendReferenceSchemas();

c.AddEnumsWithValuesFixFilters(o => { o.ApplySchemaFilter = true; o.ApplyParameterFilter = true; o.ApplyDocumentFilter = true; o.IncludeDescriptions = true; o.IncludeXEnumRemarks = true; o.DescriptionSource = DescriptionSources.DescriptionAttributesThenXmlComments;

o.IncludeXmlCommentsForTessa(); }); }) .AddTessaSwaggerGenNewtonsoftSupport(); } }

public void Configure( IApplicationBuilder app, IHostApplicationLifetime applicationLifetime, IOptions<WebOptions> options, IOptions<WebServerOptions> serverOptions) { bool isDevelopment = this.HostEnvironment.IsDevelopment(); if (isDevelopment) { app.UseDeveloperExceptionPage(); }

var forwardedHeaders = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, ForwardLimit = 10, };

forwardedHeaders.KnownNetworks.Clear(); forwardedHeaders.KnownProxies.Clear();

app .UseForwardedHeaders(forwardedHeaders) .UseTessaHttpsRedirection(serverOptions.Value, isDevelopment) .UsePathBaseIfSpecified(options.Value.PathBase) .UseResponseCompression();

app.UseStaticFiles();

// если используем Swagger для документирования REST-методов if (RuntimeHelper.SwaggerDocIsEnabled) { app .UseSwagger() .UseSwaggerUIForTessa("My custom API v1"); }

// вызовы UseRouting, UseAuthorization и UseEndpoints должны быть в указанном порядке // разделены по разным операторам (точкой с запятой), чтобы анализатор .NET при сборке не выводил предупреждения

app .UseTessaApplication() .UseRouting();

app .UseAuthentication() .UseAuthorization();

app .UseEndpoints(endpoints => { endpoints.MapHealthChecks("/hcheck"); endpoints.MapControllers(); }) .ConfigureTessaApplication();

applicationLifetime.RegisterTessaLifetime(app); app.Run(context => context.HandleNotFoundAsync()); } } }

Note

Метод app.UsePathBaseIfSpecified() доступен, начиная со сборки 3.5.0.

В файле TestController.cs приведён пример REST-контроллера, который выполняет некоторые бизнес-требования. Файл рекомендуется создать в подпапке Controllers проекта сервиса.

Note

Для создания REST API укажите атрибут [ApiController] на классе контроллера, и воспользуйтесь рекомендациями из MSDN: https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-5.0

using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Tessa.Cards; using Tessa.Platform; using Tessa.Platform.Runtime; using Tessa.Platform.Storage; using Tessa.Platform.Validation; using Tessa.Roles; using Tessa.Web;

namespace TessaWebApp.Controllers { [Route("test"), ApiController, AllowAnonymous] [ProducesErrorResponseType(typeof(PlainValidationResult))] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public class TestController : Controller { public TestController( ITessaServerSettings serverSettings, ILoginService loginService, ISessionService sessionService, ICardRepository cardRepository) { this.serverSettings = serverSettings; this.loginService = loginService; this.sessionService = sessionService; this.cardRepository = cardRepository; }

private readonly ITessaServerSettings serverSettings;

private readonly ILoginService loginService;

private readonly ISessionService sessionService;

private readonly ICardRepository cardRepository;

[HttpGet("system")] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult<CardGetResponse>> GetSystemUserText(CancellationToken cancellationToken = default) { // объект PlainValidationResult в формате application/json возвращается в случае необработанных исключений await using var _ = SessionContext.Create(Session.CreateSystemToken(SessionType.Server, this.serverSettings)); return await this.GetSystemUserTextWithoutSession(cancellationToken); }

[HttpGet("method"), SessionMethod] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult<CardGetResponse>> GetSystemUserTextWithoutSession(CancellationToken cancellationToken = default) { CardGetResponse response = await this.cardRepository.GetAsync( new CardGetRequest { CardID = Session.SystemID, CardTypeID = RoleHelper.PersonalRoleTypeID, }, cancellationToken);

return this.TypedJson(response); }

public sealed class Credentials { public string Login { get; set; } public string Password { get; set; } }

[HttpPost("login")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Text.Xml, MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK)] public async Task<ActionResult<string>> PostLogin( [FromBody] Credentials credentials, CancellationToken cancellationToken = default) => this.Ok(await this.loginService.OpenSessionAsync( SessionClientParameters.CreateCurrent(), ApplicationIdentifiers.Other, credentials.Login, credentials.Password, cancellationToken: cancellationToken));

[HttpPost("logout"), SessionMethod] [Consumes(MediaTypeNames.Text.Xml)] [Produces(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status204NoContent)] public async Task<IActionResult> PostLogout([FromBody, SessionToken] string token = null) { await this.sessionService.CloseSessionWithTokenAsync(token); return this.NoContent(); } } }

Компонент Swagger может использоваться для генерации страницы с автоматической документацией по REST-методам в ваших контроллерах. Для этого укажите регистрации Swagger в методах ConfigureServices и Configure (см. выше). В коде ваших контроллеров используйте символ тройного слэша /// для добавления описаний для класса контроллера и его REST-методов. Также включите генерацию xml-файла документации в том проекте (или проектах), где расположены классы контроллеров, отредактировав файл проекта .csproj и добавив строку GenerateDocumentationFile (уже должна присутствовать в файле .csproj, отредактированном ранее):

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup> ... <GenerateDocumentationFile>true</GenerateDocumentationFile> ... </PropertyGroup>

... </Project>

Просмотреть документацию можно будет после публикации приложения, перейдя по адресу вида https://localhost/tessa/app/swagger (где app - имя вашего приложения).

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

Добавьте файл extensions.xml (Add -> New item -> XML File), в свойствах файлах укажите Content и Copy if newer. Содержимое файла приведено ниже:

<?xml version="1.0" encoding="utf-8" ?> <extensions xmlns="http://syntellect.ru/tessa/include">

<include file="Tessa.Extensions.Default.Shared.dll" /> <include file="Tessa.Extensions.Default.Server.dll" serverOnly="true" />

<include file="Tessa.Extensions.Shared.dll" /> <include file="Tessa.Extensions.Server.dll" serverOnly="true" />

<include file="Tessa.Extensions.PostgreSql.Server.dll" serverOnly="true" />

</extensions>

Добавьте файл NLog.config (Add -> New item -> XML File), в свойствах файлах укажите Content и Copy if newer. Содержимое файла приведено ниже:

<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<targets async="true"> <target name="file" xsi:type="File" encoding="utf-8" writeBom="true" fileName="${basedir}/log.txt" /> <target name="queries" xsi:type="File" encoding="utf-8" writeBom="true" fileName="${basedir}/queries.txt" layout="--${longdate}${newline}${message}${newline}GO${newline}" /> <target name="null" xsi:type="Null" formatMessage="false" /> </targets>

<rules> <logger name="SqlQueries" minlevel="Off" writeTo="queries" final="true" /> <logger name="SqlQueries" minlevel="Trace" writeTo="null" final="true" /> <logger name="*" minlevel="Info" writeTo="file" /> </rules>

</nlog>

Добавьте файл app.json (Add -> New item -> JSON File), в свойствах файлах укажите Content и Copy if newer.

Содержимое вместе со строкой подключения и файлом лицензии мы рекомендуем скопировать из файла app.json вашей инсталляции, удалив из него ключи: WebControllers (обязательно!), GuyFawkesAuth, WinAuth, UserWallpaperName, WallpaperSizeKb, MultipartBodyLengthLimit, SAML, Themes.

Пример содержимого файла приведён ниже (для тестового приложения можно скопировать его):

{ "ConnectionStrings": { "default": [ "Host=localhost; Database=tessa; Integrated Security=false; User ID=postgres; Password=Master1234; Pooling=true; MaxPoolSize=100", "Npgsql" ] },

"DataProviders": { "Npgsql": "Npgsql.NpgsqlFactory, Npgsql" },

".if": [ "linux", { "Settings": { "PlatformDependencies": "Tessa.Platform.LinuxTessaPlatformDependencies, Tessa.Linux" } } ],

".include": [ "app-*.json", "localization.json", "patch*.json" ],

"Settings": { // Autogenerated "SignatureKey": "l5pthoEIB/s8LuiNnG1OUA+3FO1fSW5/nX4zilQnlLM013Z33Q/L7hErHKptUpfOQ6ZPG35mVkwMGu0oF8/JpA==", "CipherKey": "SKW2d3hgQUeM61FRKV6TafWGjmqCCAQErVTk0g4YViY=",

// Basic options "ServerCode": "tessa", "LicenseFile": "@*.tlic", "Redis": "", "EnableInterprocessCache": true, "ProbingPath": "extensions", "ServerDependencies": "Tessa.Server.TessaServerDependencies, Tessa.Server", "WebControllers": [ "extensions/Tessa.Extensions.Default.Server.Web.dll", "extensions/Tessa.Extensions.Server.Web.dll" ], "WebRazorReferences": [ "extensions" ],

// Web client options "PathBase": "", "GuyFawkesAuth": "", "WinAuthIsEnabled": false, "WinAuth": "", "WinAutoLogin": true, "PreviewPdfEnabled": true, "CryptoProPluginEnabled": false,

// Kerberos auth "Kerberos.Enabled": false, "Kerberos.Keytab": "*.keytab", "Kerberos.DisableRealmCheck": false,

// Security options "Configuration.Sealed": false, "Configuration.StrictSecurity": false, "HealthCheckIsEnabled": true, "SwaggerDocIsEnabled": true, "CookiesSameSite": "Strict", "CheckPlatformVersion": true, "SessionExpirationTimeSpan": "7.00:00:00", "CipherKeyRotationInterval": "10.00:00:00", "ViewAccessCacheTimeSpan": "0.01:00:00", "AllowedRefererValues": [ ], "ResponseHeaders": { "X-Frame-Options": "sameorigin", "X-XSS-Protection": "1; mode=block" },

// Misc "ExtensionTracingMode": "Off", "RoleTimeoutTimeSpan": "0.00:30:00", "RolesLockTimeoutSeconds": 300, "LimitMaxThreads": true, "MultipartBodyLengthLimit": -1, "UserWallpaperName": "Wallpaper", "WallpaperSizeKb": 600,

"WebServer": { "HttpsRedirect": "Enabled", "HttpsRedirectPort": null, "HstsMaxAgeDays": 365, "CertificateFile": "@*.cer", "CertificateKeyFile": "@*.key", "CertificatePassword": "", "CertificateStoreName": "My", "CertificateStoreLocation": "CurrentUser", "CertificateStoreSubject": "localhost", "Http2Disabled": false, "EnforceTls12": false, "DataProtectionKeysPath": "", "DataProtectionCertificateFile": "@*.cer", "DataProtectionCertificatePassword": "" },

"WebServerLimits": { "MaxResponseBufferSizeBytes": 65536, "MaxRequestBufferSizeBytes": 1048576, "MaxRequestLineSizeBytes": 8192, "MaxRequestHeadersTotalSizeBytes": 32768, "MaxRequestHeaderCount": 100, "MaxRequestBodySizeBytes": 30000000, "KeepAliveTimeoutSeconds": 120, "RequestHeadersTimeoutSeconds": 30, "MaxConcurrentConnections": null, "MaxConcurrentUpgradedConnections": null, "MinRequestBodyDataRateBytesPerSecond": 240.0, "MinRequestBodyDataRateGraceSeconds": 5, "MinResponseDataRateBytesPerSecond": 240.0, "MinResponseDataRateGraceSeconds": 5 },

"LDAP": { "Enabled": false, "UseSsl": false, "Url": "localhost", "Port": 10389, "TimeoutMilliseconds": null, "BindDn": "uid=admin,ou=system", "BindCredentials": "secret", "SearchBase": "dc=example,dc=com", "SearchFilter": "(&(objectClass=person)(cn={0}))" } } }

Добавьте ваш файл лицензии .tlic (Add -> Existing Item), в свойствах файлах укажите Content и Copy if newer.

Также вам потребуется копировать в выходную папку файлы расширений, собранные для вашего проекта:

  • Tessa.Extensions.Server.dll

  • Tessa.Extensions.Shared.dll

  • Tessa.Extensions.Default.Server.dll

  • Tessa.Extensions.Default.Shared.dll

Все искомые файлы можно найти, например, в папке Services\web внутри сборки TESSA вашей версии (в примере это 3.6.0). Добавьте эти файлы (Add -> Existing Item), в свойствах файлов укажите None и Copy if newer.

Для сборок расширений должны быть установлены все их зависимости, которые обычно указываются в файлах проектов .csproj для исходных файлах проектов расширений: Tessa.Extensions.Default.Server.csproj, Tessa.Extensions.Default.Shared.csproj, и любые зависимости в проектах вашего решения Tessa.Extensions.Server.csproj и Tessa.Extensions.Shared.csproj.

В платформе версии 3.6.0.14 это один дополнительный NuGet-пакет DocumentFormat.OpenXml v2.20.0. Установим его:

Мы рекомендуем добавлять такое веб-приложение как проект в solution проектных расширений Tessa.Extensions.sln. Тогда вместо ссылок на .dll и дополнительных зависимостей (DocumentFormat.OpenXml) можно добавить ссылку на проект, при этом выходной файл проектов с расширениями будет скопирован в сборку, а все зависимые NuGet-пакеты - автоматически установлены.

Веб-приложение перед использованием должно быть опубликовано. Для этого добавьте скрипт publish.bat (Add -> New item -> Text File), в свойствах файлах оставьте None и Do Not Copy.

Укажите следующее содержимое скрипта, причём в текстовом редакторе задайте кодировку UTF-8 без BOM (по умолчанию в Visual Studio создаётся файл в кодировке UTF-8 + BOM, что приводит к некорректному выполнению скрипта).

@echo off set BuildPath=bin\Publish rd /S /Q "%BuildPath%">nul 2>&1

dotnet publish -c Release -r win-x64 -o "%BuildPath%"

del /Q "%BuildPath%\*.Development.json" for %%a in (cs, de, es, fr, it, ja, ko, pl, pt-BR, ru, tr, zh-Hans, zh-Hant) do rd /S /Q "%BuildPath%\%%a" pause

Note

Для публикации приложения для Linux замените win-x64 на linux-x64 в этом примере. Убедитесь, что вы предварительно установили NuGet-пакет Tessa.Linux.

Запустите скрипт publish.bat двойным кликом и дождитесь окончания его выполнения. Предварительно собирать проект в Visual Studio не требуется.

В папке bin\Publish будет расположен собранный проект, который в дальнейшем можно будет настроить, например, в IIS по аналогии с настройкой веб-сервиса web в Руководстве по установке.

Для проверки сервиса без установки, запустите exe-файл в папке публикации, например, TessaWebApp.exe. Вы увидите окно с указанием локальных портов, по которым доступно приложение:

Перейдите в браузере по адресу https://localhost:5001/check, и при корректном соединении с базой данных в app.json, где уже установлена TESSA этой же версии, должно быть отображено окно следующего вида:

Теперь в веб-приложении можно добавлять любые зависимости как NuGet-пакеты и контроллеры по аналогии с тем, как они добавляются в проект Tessa.Extensions.Server.Web.

В рамках примера используем метод контроллера TestController.cs, созданного ранее.

Опубликуем приложение (перед публикацией его надо закрыть, нажав Ctrl+C в окне консоли, если приложение было запущено). Теперь запустим приложение TessaWebApp.exe и откроем в браузере ссылку https://localhost:5001/test/system

При успешном выполнении должна быть загружена карточка сотрудника “System”, и для него выведена структура объекта с карточкой CardGetResponse.

Теперь откройте ссылку https://localhost:5001/test/method

Поскольку этот метод с атрибутом [SessionMethod], то для его выполнения требуется аутентификация, и на экране будет отображён JSON для класса PlainValidationResult с сообщением об ошибке: Session is required to call operation /test/method

Для успешной работы такого метода сначала должен быть вызван POST-запрос по адресу /test/login, потом результат вызова должен быть проброшен в HTTP-заголовок Tessa-Session этого метода и всех последующих методов в пределах сессии. Для закрытия сессии выполняется POST-запрос по адресу /test/logout (токен параметром передавать не требуется, он будет заполнен из HTTP-заголовка). Для реального приложения, конечно, адрес контроллера будет отличен от /test.

Таким образом, мы создали, выполнили сборку и публикацию веб-приложения, которое может использоваться в сценариях обработки REST-запросов независимо от основного веб-приложения платформы, при этом мы можем использовать полноценное серверное API платформы TESSA без ограничений.

Back to top