Создание консольного приложения, использующего API TESSA
Создание консольного приложения, использующего API TESSA¶
В этом примере мы рассмотрим создание независимого консольного приложения .NET, которое может использоваться в целях интеграции и автоматизации взаимодействия с системой TESSA.
Откройте Visual Studio проектного решения Source\Tessa.Extensions.sln
. Создайте папку Applications
в контекстном меню Solution Explorer
. Далее создайте проект Console Application
через контекстное меню в папке, который поместите в подпапку Source\Applications
, указав путь в поле Location
.
Убедитесь, что в свойствах созданного проекта указана платформа .NET 5.0
.
Откройте для редактирования файл проекта .csproj
и замените его содержимое таким образом:
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(ProjectDir)../../Tessa.targets" />
<Import Project="$(ProjectDir)../../Tessa.Extensions.targets" />
<Import Project="$(ProjectDir)../../Tessa.Runtime.targets" />
<PropertyGroup>
<Company>Place your Organization here</Company>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RestoreSources>$(RestoreSources);../../Bin/packages;https://api.nuget.org/v3/index.json</RestoreSources>
<NoWarn>$(NoWarn);1591</NoWarn>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'win-x64'">
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="..\..\..\Configuration\Localization\*.jlocalization" LinkBase="Resources" />
<None Remove="extensions\**" />
<Content Include="extensions\**" CopyToOutputDirectory="PreserveNewest" />
<None Remove="app.json" />
<None Remove="extensions.xml" />
<None Remove="NLog.config" />
<Content Include="app.json" CopyToOutputDirectory="PreserveNewest" />
<Content Include="extensions.xml" CopyToOutputDirectory="PreserveNewest" />
<Content Include="NLog.config" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
-
В теге
<Company>
укажите название вашей организации, которое будет выводиться на консоль в Copyright-сообщении. -
В теге
<Version>
изменяйте номер версии вашего приложения, который будет выводиться на консоль в Copyright-сообщении. В приведённом примере файла проекта тег отсутствует, и версия синхронизирована с версией расширений из файлаTessa.Extensions.targets
. -
В проекте указано использование версии языка C# 9.0. Эту версию можно использовать на момент написания этого документа только для платформы .NET 5.0.
-
В проекте отключены предупреждения об async-методах, которые не содержат конструкции await, по аналогии с проектными расширениями, поскольку это удобно при добавлении методов команд, которые должны быть асинхронными по сигнатуре, но фактически могут быть синхронными.
-
При публикации приложения на 64-битной платформе Windows будет использована технология ReadyToRun, увеличивающая размер публикуемых файлов, но при этом сокращающая время запуска приложения, что особенно актуально для консольных утилит.
-
Конфигурационные файлы
app.json
,extensions.xml
,NLog.config
, а также папкаextensions
копируются в выходную папку приложения. Они будут добавлены ниже. -
Добавляется несуществующая папка
Resources
, в которой будут размещены библиотеки локализации в ресурсах скомпилированного приложения.
Перейдите в диалог выбора NuGet-пакетов, для этого в контекстном меню на узле Solution '...'
в панели инструментов Solution Explorer
выберите пункт Manage NuGet Packages
.
Перейдите на вкладку Browse и последовательно установите пакеты Tessa.Linux
и Tessa.PostgreSql
, выбрав версию пакета, соответствующую версии вашей сборки TESSA. Например, для версии сборки TESSA 3.6.0 с патчем 1 укажите версию пакетов также 3.6.0.1. Не обновляйте пакеты до более новых версий до того, как будет обновлена инсталляция всей платформы (вместе с конфигурацией, базой данных и расширениями).
Note
Даже если вы будете использовать разработанную утилиту на Windows для взаимодействия с СУБД MSSQL, установленные пакеты включают в своих зависимостях базовые пакеты для поддержки Windows и MSSQL. Рекомендуется использовать указанные пакеты, поскольку они также обеспечат кроссплатформенность на Linux и поддержку СУБД PostgreSQL ценой нескольких дополнительных мегабайт в выходной папке.
Скопируйте следующее содержимое в файл Program.cs
. Комментариями в коде указаны места, на которые следует обратить внимание.
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using NLog;
using Tessa.Localization;
using Tessa.Platform;
using Tessa.Platform.CommandLine;
using Tessa.Platform.ConsoleApps;
namespace TessaConsoleApp
{
internal static class Program
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public static async Task Main(string[] args)
{
await TessaPlatform.InitializeFromConfigurationAsync();
await LocalizationManager.InitializeDefaultLocalizationAsync(
true, // detectLanguage
new ILocalizationService[]
{
JsonResourceFileLocalizationService.FromEmbeddedResources(
Assembly.GetExecutingAssembly(),
typeof(Program).Namespace + ".Resources.")
});
await ConfigurationManager.GetDefaultAsync();
List<string> probingPathList = AssemblyLoaderHelper.GetActualProbingPathList(
AssemblyLoaderHelper.GetProbingPathList(ConfigurationManager.Settings),
addRootFolder: true);
AssemblyLoaderHelper.AddAssemblyResolveHandler(probingPathList);
if (logger.IsInfoEnabled && args.Length > 0)
{
string appName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly()?.Location);
if (OperatingSystem.IsWindows())
{
appName += ".exe";
}
logger.Info("{0} {1}", appName, string.Join(" ", args.Select(arg => "\"" + arg + "\"")));
}
if (args.Length == 0)
{
args = new[] { "help" };
ConsoleAppHelper.WriteLogo(extraLine: false);
}
var commandContext = new CommandContext("root");
// пример регистрации команды без использования расширений и регистраторов [ConsoleRegistrator]
commandContext.AddCommand<TextWriter, string>(Hello);
// удалите следующую строку, если не требуется выполнять поиск консольных команд в подключённых расширениях
ConsoleRegistratorHelper.FindAndExecute(null, commandContext, out _);
try
{
await commandContext.ExecuteAsync(args);
}
catch (Exception ex)
{
logger.LogException(ex);
await System.Console.Error.WriteLineAsync(Environment.NewLine + ex.Message);
Exception inner = ex.InnerException;
if (inner != null)
{
await System.Console.Error.WriteLineAsync(inner.Message);
}
ConsoleAppHelper.EnvironmentExit(ConsoleAppHelper.UnhandledExceptionExitCode);
}
finally
{
LogManager.Shutdown();
}
}
// пример простой команды: TessaConsoleApp Hello Tessa
[Verb("Hello"), Description("Says \"Hello\" to a user.")]
public static async Task Hello(
[Output] TextWriter output,
[Argument, Description("User name to say hello to.")] string userName)
{
await output.WriteLineAsync($"Hello, {userName}!");
}
}
}
Также в папке приложения нужен ряд конфигурационных файлов для настройки расширений, логирования и методов подключения к базе данных.
Добавьте файл extensions.xml
(Add -> New item -> XML File
). Содержимое файла приведено ниже:
<?xml version="1.0" encoding="utf-8" ?>
<extensions xmlns="http://syntellect.ru/tessa/include">
<scan path="extensions" />
<include file="Tessa.Extensions.PostgreSql.Server.dll" />
</extensions>
Добавьте файл NLog.config
(Add -> New item -> XML File
). Содержимое файла приведено ниже:
<?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="Error" 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
). Содержимое файла приведено ниже, рекомендуем заменить в нём строку подключения к базе данных “default” (строка “migration” может использоваться в типовой команде tadmin MigrationDatabase
и может быть удалена, если типовые команды отключены):
{
"ConnectionStrings": {
"default": "Server=.\\SQLEXPRESS; Database=tessa; Integrated Security=false; User ID=sa; Password=Master1234; Connect Timeout=200; pooling='true'; Max Pool Size=200; MultipleActiveResultSets=true;",
"migration": [ "Host=localhost; Database=tessa; User ID=postgres; Password=Master1234; Pooling=true; MaxPoolSize=100", "Npgsql" ]
},
"//ConnectionStrings PostgreSQL": {
"default": [ "Host=localhost; Database=tessa; User ID=postgres; Password=Master1234; Pooling=true; MaxPoolSize=100", "Npgsql" ]
},
"DataProviders": {
"Npgsql": "Npgsql.NpgsqlFactory, Npgsql"
},
".if": [
"linux",
{
"Settings": {
"PlatformDependencies": "Tessa.Platform.LinuxTessaPlatformDependencies, Tessa.Linux"
}
}
],
"Settings": {
"BaseAddress": "https://localhost",
"InstanceName": "",
"OpenTimeout": "00:01:01",
"CloseTimeout": "00:01:02",
"SendTimeout": "00:40:00",
"ProbingPath": "extensions"
}
}
Создайте папку extensions
, в которой будут расположены проектные Shared-расширения и расширения с консольными командами Console. Добавьте файл extensions.xml
(Add -> New item -> XML File
). Содержимое файла приведено ниже:
<?xml version="1.0" encoding="utf-8" ?>
<extensions xmlns="http://syntellect.ru/tessa/include">
<include file="Tessa.Extensions.Default.Console.dll" />
<include file="Tessa.Extensions.Default.Shared.dll" />
<include file="Tessa.Extensions.Console.dll" />
<include file="Tessa.Extensions.Shared.dll" />
</extensions>
Также вам потребуется копировать в папку extensions
файлы расширений, собранные для вашего проекта (они будут автоматически скопированы в выходную папку):
-
Tessa.Extensions.Console.dll
-
Tessa.Extensions.Shared.dll
-
Tessa.Extensions.Default.Console.dll
-
Tessa.Extensions.Default.Shared.dll
Все искомые файлы можно найти, например, в папке Source\Bin\Tessa.Extensions.Console
в проектном репозитории после сборки решения. Скопируйте эти файлы в папку (в проводнике Windows, не в IDE).
Для успешной работы API внутри консольного приложения также требуется инициализировать локализацию, указав все строки локализации из папки Configuration\Localization
вашего решения. Эти файлы встраиваются в исполняемый файл в момент компиляции и далее инициализируются при запуске приложения в Program.cs
. В файле проекта .csproj
, который был указан выше в теге <EmbeddedResource>
указано местоположение файлов локализации относительно папки проекта.
Папка Configuration
уже должна располагаться по указанному пути в репозитории вашего проектного решения:
Вы можете указать другой относительный или абсолютный путь к библиотекам локализации в файле .csproj
. Для текущего примера достаточно, чтобы в папке Configuration
была только подпапка с локализацией Localization
, другие файлы можно не копировать. После компиляции консольному приложению уже не потребуется эта папка, все необходимые ресурсы будут встроены в бинарные файлы приложения.
Для сборок расширений должны быть установлены все их зависимости, которые обычно указываются в файлах проектов .csproj
для исходных файлах проектов Shared-расширений и консольных команд: Tessa.Extensions.Default.Console.csproj
, Tessa.Extensions.Default.Shared.csproj
, и любые зависимости в проектах ваших решений Tessa.Extensions.Console.csproj
и Tessa.Extensions.Shared.csproj
.
В платформе версии 3.6.0.14 это два дополнительных NuGet-пакета DocumentFormat.OpenXml v2.20.0
и CsvHelper v30.0.1
. Установим их:
Мы рекомендуем добавлять такое веб-приложение как проект в solution проектных расширений Tessa.Extensions.sln
. Тогда вместо ссылок на .dll
и дополнительных зависимостей (DocumentFormat.OpenXml, CsvHelper
) можно добавить ссылку на проект, при этом выходной файл проектов с расширениями будет скопирован в сборку, а все зависимые 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%"
pause
Note
Для публикации приложения для Linux замените win-x64
на linux-x64
в этом примере.
Запустите скрипт publish.bat
двойным кликом и дождитесь окончания его выполнения. Предварительно собирать проект в Visual Studio не требуется.
В папке bin\Publish
будет расположен собранный проект, который можно скопировать в любую папку и использовать для соответствующей ОС (64-битной Windows или 64-битной Linux). Никаких требований к компьютерам, на которых будет запускаться консольная утилита, не предъявляется, т.е. устанавливать .NET Framework или .NET 5.0 не требуется. Поддерживаемые операционные системы определяются используемой платформой .NET, например, для версии .NET 5.0 требования перечислены в документации Microsoft. Если вы используете API TESSA, то обратитесь к руководству по установке и руководству по установке на Linux для системы TESSA.
Для проверки сервиса без установки, запустите командную строку или окно терминала, перейдите в папку публикации, и выполните команду для exe-файла скомпилированного приложения, например, TessaConsoleApp.exe
.
TessaConsoleApp Hello TESSA
В соответствии с примером файла Program.cs
для команды Hello
будет выведено сообщение:
Hello, TESSA!
Для вывода автоматически генерируемой справки по команде:
TessaConsoleApp Hello --help
В примере также подключаются все стандартные команды, включаемые в утилиту tadmin
(как это отключить указано в комментарии в Program.cs
). Например, вы можете проверить подключение к базе данных, указанной в конфигурационном файле app.json
:
TessaConsoleApp CheckDatabase
Таким образом, мы создали, выполнили сборку и публикацию консольного приложения, которое может использоваться в сценариях автоматизации взаимодействия с системой, при этом мы можем использовать полноценное клиентское и/или серверное API платформы TESSA без ограничений.