Загрузка виртуального файла на клиенте без добавления его в карточку
Загрузка виртуального файла на клиенте без добавления его в карточку¶
Рассмотрим ситуацию, когда на клиенте при нажатии на кнопку или плитку требуется загрузить виртуальный или физический файл, который не приложен к текущей карточке, причём файл может иметь отношение к другой карточке с заданным идентификатором.
Файл должен быть загружен во временную папку, из которой он будет удалён только при обновлении или закрытии текущей карточки.
Для этого напишем вспомогательный метод, который асинхронно загружает файл с заданными параметрами и возвращает путь ко временному файлу или null, если файл загрузить не удалось.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Tessa.Cards;
using Tessa.Files;
using Tessa.Platform.Validation;
using Tessa.UI;
using Tessa.UI.Cards;
namespace Tessa.Extensions.Client
{
public static class FileExtensionHelper
{
public static async Task<string> TryLoadVirtualFileAsync(
ICardFileManager cardFileManager,
ICardModel cardModel,
string fileName,
Guid cardID,
Guid cardTypeID,
Guid fileID,
Guid versionID,
CancellationToken cancellationToken = default)
{
// cardModel для файлового кэша, из которого временный файл попытается удалиться
// после рефреша или закрытия вкладки с карточкой
// создаём псевдо-карточку с заданным идентификатором, и произвольными TypeName/TypeCaption
var fakeCard = new Card
{
ID = cardID,
TypeID = cardTypeID,
TypeName = CardHelper.FileTypeName,
TypeCaption = CardHelper.FileTypeCaption,
};
// создаём псевдофайл
ICardFileContainer container = await cardFileManager.CreateContainerAsync(fakeCard, cancellationToken: cancellationToken);
(IFile file, ValidationResult buildResult) = await container.FileContainer
.BuildFile(fileName)
.SetFileToken((x, _) => { x.ID = fileID; return ValueTask.CompletedTask; })
.SetVersionToken((x, _) => { x.ID = versionID; return ValueTask.CompletedTask; })
.SetContent(Stream.Null)
.ReturnAsync(cancellationToken);
TessaDialog.ShowNotEmpty(buildResult);
if (!buildResult.IsSuccessful)
{
return null;
}
// создаём временный файл, в который будет записан контент
IFileContent tempContent = await cardModel.FileContainer.Source.Cache.AllocateAsync(fileName, cancellationToken: cancellationToken);
if (!tempContent.IsLocal)
{
throw new InvalidOperationException("Content isn't local when allocating from cache.");
}
string tempPath = tempContent.GetLocalFilePath();
// асинхронно загружаем содержимое файла и сохраняем его в tempPath;
// при загрузке не будут учитываться токены KrToken
var target = System.IO.File.Create(tempPath);
IFileContentResponse loadResponse = await Task.Run(async () =>
{
var request = new FileContentRequest(file.Versions.Last)
{
ProcessContentActionAsync = async (p, ct) => await p.CopyToAsync(target, ct)
};
return await container.FileContainer.Source.GetContentAsync(request);
},
cancellationToken);
TessaDialog.ShowNotEmpty(loadResponse.ValidationResult);
return loadResponse.ValidationResult.IsSuccessful ? tempPath : null;
}
}
}
Пример расширения в карточке “Автомобиль”, которое пытается загрузить файл с некоторыми заданными идентификаторами, и в случае успеха файл открывается вызовом Process.Start()
.
using System;
using System.Threading.Tasks;
using Tessa.Cards;
using Tessa.UI;
using Tessa.UI.Cards;
using Tessa.UI.Cards.Controls;
using Unity;
using Unity.Lifetime;
namespace Tessa.Extensions.Client
{
public sealed class TestUIExtension : CardUIExtension
{
public TestUIExtension(ICardFileManager cardFileManager)
{
this.cardFileManager = cardFileManager;
}
private readonly ICardFileManager cardFileManager;
public override async Task Initialized(ICardUIExtensionContext context)
{
ICardModel cardModel = context.Model;
if (cardModel.Controls.TryGet("Get1CButton", out var control))
{
var button = (ButtonViewModel)control;
button.CommandClosure.Execute = async p =>
{
string tempPath;
using (TessaSplash.Create(TessaSplashMessage.OpeningFile))
{
// загружаем здесь печатный лист согласования для некоторой карточки договора
tempPath = await FileExtensionHelper.TryLoadVirtualFileAsync(
cardFileManager,
cardModel,
"file.txt",
cardID: new Guid("b6d11bb3-0a6e-4fb3-be59-0f4a01f996b5"),
cardTypeID: new Guid("b6d11bb3-0a6e-4fb3-be59-0f4a01f996b5"),
fileID: new Guid("b6d11bb3-0a6e-4fb3-be59-0f4a01f996b5"),
versionID: new Guid("b6d11bb3-0a6e-4fb3-be59-0f4a01f996b5"));
}
if (!string.IsNullOrEmpty(tempPath))
{
System.Diagnostics.Process.Start(tempPath);
}
};
}
}
}
[Registrator]
public sealed class TestUIRegistrator : RegistratorBase
{
public override void RegisterUnity()
{
this.UnityContainer
.RegisterType<TestUIExtension>(new ContainerControlledLifetimeManager())
;
}
public override void RegisterExtensions(IExtensionContainer extensionContainer)
{
extensionContainer
.RegisterExtension<ICardUIExtension, TestUIExtension>(x => x
.WithOrder(ExtensionStage.AfterPlatform, 100)
.WithUnity(this.UnityContainer)
.WhenCardTypes("Car"))
;
}
}
}